Node Wrangler: LTS: backport many bugfixes from main #105169

Merged
Damien Picard merged 7 commits from pioverfour/blender-addons:dp_nw_3.6 into blender-v3.6-release 2024-02-21 18:57:14 +01:00
3 changed files with 73 additions and 49 deletions

View File

@ -3,7 +3,7 @@
bl_info = {
"name": "Node Wrangler",
"author": "Bartek Skorupa, Greg Zaal, Sebastian Koenig, Christian Brinkmann, Florian Meyer",
"version": (3, 46),
"version": (3, 46, 1),
"blender": (3, 6, 0),
"location": "Node Editor Toolbar or Shift-W",
"description": "Various tools to enhance and speed up node-based workflow",

View File

@ -367,7 +367,8 @@ class NWAttributeMenu(bpy.types.Menu):
for obj in objs:
if obj.data.attributes:
for attr in obj.data.attributes:
attrs.append(attr.name)
if not attr.is_internal:
attrs.append(attr.name)
attrs = list(set(attrs)) # get a unique list
if attrs:

View File

@ -1691,7 +1691,7 @@ class NWCopySettings(Operator, NWBase):
new_node.location = node_loc
for str_from, str_to in reconnections:
node_tree.connect_sockets(eval(str_from), eval(str_to))
connect_sockets(eval(str_from), eval(str_to))
success_names.append(new_node.name)
@ -1959,7 +1959,8 @@ class NWAddPrincipledSetup(Operator, NWBase, ImportHelper):
['Metallic', tags.metallic.split(' '), None],
['Specular', tags.specular.split(' '), None],
['Roughness', rough_abbr + gloss_abbr, None],
['Normal', normal_abbr + bump_abbr, None],
['Bump', bump_abbr, None],
['Normal', normal_abbr, None],
['Transmission', tags.transmission.split(' '), None],
['Emission', tags.emission.split(' '), None],
['Alpha', tags.alpha.split(' '), None],
@ -1990,6 +1991,9 @@ class NWAddPrincipledSetup(Operator, NWBase, ImportHelper):
disp_texture = None
ao_texture = None
normal_node = None
normal_node_texture = None
bump_node = None
bump_node_texture = None
roughness_node = None
for i, sname in enumerate(socketnames):
print(i, sname[0], sname[2])
@ -2020,8 +2024,48 @@ class NWAddPrincipledSetup(Operator, NWBase, ImportHelper):
continue
# BUMP NODES
elif sname[0] == 'Bump':
# Test if new texture node is bump map
fname_components = split_into_components(sname[2])
match_bump = set(bump_abbr).intersection(set(fname_components))
if match_bump:
# If Bump add bump node in between
bump_node_texture = nodes.new(type='ShaderNodeTexImage')
img = bpy.data.images.load(path.join(import_path, sname[2]))
bump_node_texture.image = img
bump_node_texture.label = 'Bump'
# Add bump node
bump_node = nodes.new(type='ShaderNodeBump')
link = connect_sockets(bump_node.inputs[2], bump_node_texture.outputs[0])
link = connect_sockets(active_node.inputs['Normal'], bump_node.outputs[0])
continue
# NORMAL NODES
elif sname[0] == 'Normal':
# Test if new texture node is normal map
fname_components = split_into_components(sname[2])
match_normal = set(normal_abbr).intersection(set(fname_components))
if match_normal:
# If Normal add normal node in between
normal_node_texture = nodes.new(type='ShaderNodeTexImage')
img = bpy.data.images.load(path.join(import_path, sname[2]))
normal_node_texture.image = img
normal_node_texture.label = 'Normal'
# Add normal node
normal_node = nodes.new(type='ShaderNodeNormalMap')
link = connect_sockets(normal_node.inputs[1], normal_node_texture.outputs[0])
# Connect to bump node if it was created before, otherwise to the BSDF
if bump_node is None:
link = connect_sockets(active_node.inputs[sname[0]], normal_node.outputs[0])
else:
link = connect_sockets(bump_node.inputs[sname[0]], normal_node.outputs[sname[0]])
continue
# AMBIENT OCCLUSION TEXTURE
if sname[0] == 'Ambient Occlusion':
elif sname[0] == 'Ambient Occlusion':
ao_texture = nodes.new(type='ShaderNodeTexImage')
img = bpy.data.images.load(path.join(import_path, sname[2]))
ao_texture.image = img
@ -2037,25 +2081,7 @@ class NWAddPrincipledSetup(Operator, NWBase, ImportHelper):
img = bpy.data.images.load(path.join(import_path, sname[2]))
texture_node.image = img
# NORMAL NODES
if sname[0] == 'Normal':
# Test if new texture node is normal or bump map
fname_components = split_into_components(sname[2])
match_normal = set(normal_abbr).intersection(set(fname_components))
match_bump = set(bump_abbr).intersection(set(fname_components))
if match_normal:
# If Normal add normal node in between
normal_node = nodes.new(type='ShaderNodeNormalMap')
link = connect_sockets(normal_node.inputs[1], texture_node.outputs[0])
elif match_bump:
# If Bump add bump node in between
normal_node = nodes.new(type='ShaderNodeBump')
link = connect_sockets(normal_node.inputs[2], texture_node.outputs[0])
link = connect_sockets(active_node.inputs[sname[0]], normal_node.outputs[0])
normal_node_texture = texture_node
elif sname[0] == 'Roughness':
if sname[0] == 'Roughness':
# Test if glossy or roughness map
fname_components = split_into_components(sname[2])
match_rough = set(rough_abbr).intersection(set(fname_components))
@ -2091,6 +2117,10 @@ class NWAddPrincipledSetup(Operator, NWBase, ImportHelper):
if disp_texture:
texture_nodes.append(disp_texture)
if bump_node_texture:
texture_nodes.append(bump_node_texture)
if normal_node_texture:
texture_nodes.append(normal_node_texture)
if ao_texture:
# We want the ambient occlusion texture to be the top most texture node
@ -2105,6 +2135,10 @@ class NWAddPrincipledSetup(Operator, NWBase, ImportHelper):
# Extra alignment if normal node was added
normal_node.location = normal_node_texture.location + Vector((300, 0))
if bump_node:
# Extra alignment if bump node was added
bump_node.location = bump_node_texture.location + Vector((300, 0))
if roughness_node:
# Alignment of invert node if glossy map
invert_node.location = roughness_node.location + Vector((300, 0))
@ -2125,7 +2159,7 @@ class NWAddPrincipledSetup(Operator, NWBase, ImportHelper):
else:
link = connect_sockets(texture_nodes[0].inputs[0], mapping.outputs[0])
# Connect texture_coordiantes to mapping node
# Connect texture_coordinates to mapping node
texture_input = nodes.new(type='ShaderNodeTexCoord')
texture_input.location = mapping.location + Vector((-200, 0))
link = connect_sockets(mapping.inputs[0], texture_input.outputs[2])
@ -2178,35 +2212,21 @@ class NWAddReroutes(Operator, NWBase):
# create reroutes and recreate links
for node in [n for n in nodes if n.select]:
if node.outputs:
x = node.location.x
x = node.location.x + node.width + 20.0
y = node.location.y
width = node.width
new_node_reroutes = []
# unhide 'REROUTE' nodes to avoid issues with location.y
if node.type == 'REROUTE':
node.hide = False
# When node is hidden - width_hidden not usable.
# Hack needed to calculate real width
if node.hide:
bpy.ops.node.select_all(action='DESELECT')
helper = nodes.new('NodeReroute')
helper.select = True
node.select = True
# resize node and helper to zero. Then check locations to calculate width
bpy.ops.transform.resize(value=(0.0, 0.0, 0.0))
width = 2.0 * (helper.location.x - node.location.x)
# restore node location
node.location = x, y
# delete helper
node.select = False
# only helper is selected now
bpy.ops.node.delete()
x = node.location.x + width + 20.0
if node.type != 'REROUTE':
else:
y -= 35.0
y_offset = -22.0
loc = x, y
reroutes_count = 0 # will be used when aligning reroutes added to hidden nodes
for out_i, output in enumerate(node.outputs):
if output.is_unavailable:
continue
pass_used = False # initial value to be analyzed if 'R_LAYERS'
# if node != 'R_LAYERS' - "pass_used" not needed, so set it to True
if node.type != 'R_LAYERS':
@ -2227,24 +2247,27 @@ class NWAddReroutes(Operator, NWBase):
valid = ((option == 'ALL') or
(option == 'LOOSE' and not output.links) or
(option == 'LINKED' and output.links))
# Add reroutes only if valid, but offset location in all cases.
if valid:
# Add reroutes only if valid.
n = nodes.new('NodeReroute')
nodes.active = n
for link in output.links:
connect_sockets(n.outputs[0], link.to_socket)
connect_sockets(output, n.inputs[0])
n.location = loc
new_node_reroutes.append(n)
post_select.append(n)
reroutes_count += 1
y += y_offset
if valid or not output.hide:
# Offset reroutes for all outputs, except hidden ones.
reroutes_count += 1
y += y_offset
loc = x, y
# disselect the node so that after execution of script only newly created nodes are selected
node.select = False
# nicer reroutes distribution along y when node.hide
if node.hide:
y_translate = reroutes_count * y_offset / 2.0 - y_offset - 35.0
for reroute in [r for r in nodes if r.select]:
for reroute in new_node_reroutes:
reroute.location.y -= y_translate
for node in post_select:
node.select = True