fix: node_groups unordered socket loading
fix: geometry_node sample texture handling fix: geometry node dependencies
This commit is contained in:
@ -27,7 +27,7 @@ from .dump_anything import Loader, Dumper
|
|||||||
from .bl_datablock import BlDatablock, get_datablock_from_uuid
|
from .bl_datablock import BlDatablock, get_datablock_from_uuid
|
||||||
|
|
||||||
NODE_SOCKET_INDEX = re.compile('\[(\d*)\]')
|
NODE_SOCKET_INDEX = re.compile('\[(\d*)\]')
|
||||||
IGNORED_SOCKETS = ['GEOMETRY', 'SHADER']
|
IGNORED_SOCKETS = ['GEOMETRY', 'SHADER', 'CUSTOM']
|
||||||
|
|
||||||
def load_node(node_data: dict, node_tree: bpy.types.ShaderNodeTree):
|
def load_node(node_data: dict, node_tree: bpy.types.ShaderNodeTree):
|
||||||
""" Load a node into a node_tree from a dict
|
""" Load a node into a node_tree from a dict
|
||||||
@ -54,8 +54,8 @@ def load_node(node_data: dict, node_tree: bpy.types.ShaderNodeTree):
|
|||||||
if inputs_data:
|
if inputs_data:
|
||||||
inputs = [i for i in target_node.inputs if i.type not in IGNORED_SOCKETS]
|
inputs = [i for i in target_node.inputs if i.type not in IGNORED_SOCKETS]
|
||||||
for idx, inpt in enumerate(inputs):
|
for idx, inpt in enumerate(inputs):
|
||||||
loaded_input = inputs_data[idx]
|
|
||||||
if idx < len(inputs_data) and hasattr(inpt, "default_value"):
|
if idx < len(inputs_data) and hasattr(inpt, "default_value"):
|
||||||
|
loaded_input = inputs_data[idx]
|
||||||
try:
|
try:
|
||||||
if inpt.type in ['OBJECT', 'COLLECTION']:
|
if inpt.type in ['OBJECT', 'COLLECTION']:
|
||||||
inpt.default_value = get_datablock_from_uuid(loaded_input, None)
|
inpt.default_value = get_datablock_from_uuid(loaded_input, None)
|
||||||
@ -69,13 +69,17 @@ def load_node(node_data: dict, node_tree: bpy.types.ShaderNodeTree):
|
|||||||
outputs_data = node_data.get('outputs')
|
outputs_data = node_data.get('outputs')
|
||||||
if outputs_data:
|
if outputs_data:
|
||||||
outputs = [o for o in target_node.outputs if o.type not in IGNORED_SOCKETS]
|
outputs = [o for o in target_node.outputs if o.type not in IGNORED_SOCKETS]
|
||||||
for idx, output in enumerate(outputs_data):
|
for idx, output in enumerate(outputs):
|
||||||
if idx < len(outputs) and hasattr(outputs[idx], "default_value"):
|
if idx < len(outputs_data) and hasattr(output, "default_value"):
|
||||||
|
loaded_output = outputs_data[idx]
|
||||||
try:
|
try:
|
||||||
outputs[idx].default_value = output
|
if output.type in ['OBJECT', 'COLLECTION']:
|
||||||
|
output.default_value = get_datablock_from_uuid(loaded_output, None)
|
||||||
|
else:
|
||||||
|
output.default_value = loaded_output
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.warning(
|
logging.warning(
|
||||||
f"Node {target_node.name} output {outputs[idx].name} parameter not supported, skipping ({e})")
|
f"Node {target_node.name} output {output.name} parameter not supported, skipping ({e})")
|
||||||
else:
|
else:
|
||||||
logging.warning(
|
logging.warning(
|
||||||
f"Node {target_node.name} output length mismatch.")
|
f"Node {target_node.name} output length mismatch.")
|
||||||
@ -328,6 +332,8 @@ def get_node_tree_dependencies(node_tree: bpy.types.NodeTree) -> list:
|
|||||||
def has_node_group(node): return (
|
def has_node_group(node): return (
|
||||||
hasattr(node, 'node_tree') and node.node_tree)
|
hasattr(node, 'node_tree') and node.node_tree)
|
||||||
|
|
||||||
|
def has_texture(node): return (
|
||||||
|
node.type in ['ATTRIBUTE_SAMPLE_TEXTURE','TEXTURE'] and node.texture)
|
||||||
deps = []
|
deps = []
|
||||||
|
|
||||||
for node in node_tree.nodes:
|
for node in node_tree.nodes:
|
||||||
@ -335,6 +341,8 @@ def get_node_tree_dependencies(node_tree: bpy.types.NodeTree) -> list:
|
|||||||
deps.append(node.image)
|
deps.append(node.image)
|
||||||
elif has_node_group(node):
|
elif has_node_group(node):
|
||||||
deps.append(node.node_tree)
|
deps.append(node.node_tree)
|
||||||
|
elif has_texture(node):
|
||||||
|
deps.append(node.texture)
|
||||||
|
|
||||||
return deps
|
return deps
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ import mathutils
|
|||||||
from replication.exception import ContextError
|
from replication.exception import ContextError
|
||||||
|
|
||||||
from .bl_datablock import BlDatablock, get_datablock_from_uuid
|
from .bl_datablock import BlDatablock, get_datablock_from_uuid
|
||||||
|
from .bl_material import IGNORED_SOCKETS
|
||||||
from .dump_anything import (
|
from .dump_anything import (
|
||||||
Dumper,
|
Dumper,
|
||||||
Loader,
|
Loader,
|
||||||
@ -43,10 +44,15 @@ else:
|
|||||||
logging.warning("Geometry node Float parameter not supported in \
|
logging.warning("Geometry node Float parameter not supported in \
|
||||||
blender 2.92.")
|
blender 2.92.")
|
||||||
|
|
||||||
|
def get_node_group_inputs(node_group):
|
||||||
def get_input_index(e):
|
inputs = []
|
||||||
return int(re.findall('[0-9]+', e)[0])
|
for inpt in node_group.inputs:
|
||||||
|
if inpt.type in IGNORED_SOCKETS:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
inputs.append(inpt)
|
||||||
|
return inputs
|
||||||
|
# return [inpt.identifer for inpt in node_group.inputs if inpt.type not in IGNORED_SOCKETS]
|
||||||
|
|
||||||
def dump_modifier_geometry_node_inputs(modifier: bpy.types.Modifier) -> list:
|
def dump_modifier_geometry_node_inputs(modifier: bpy.types.Modifier) -> list:
|
||||||
""" Dump geometry node modifier input properties
|
""" Dump geometry node modifier input properties
|
||||||
@ -54,11 +60,10 @@ def dump_modifier_geometry_node_inputs(modifier: bpy.types.Modifier) -> list:
|
|||||||
:arg modifier: geometry node modifier to dump
|
:arg modifier: geometry node modifier to dump
|
||||||
:type modifier: bpy.type.Modifier
|
:type modifier: bpy.type.Modifier
|
||||||
"""
|
"""
|
||||||
inputs_name = [p for p in dir(modifier) if "Input_" in p]
|
|
||||||
inputs_name.sort(key=get_input_index)
|
|
||||||
dumped_inputs = []
|
dumped_inputs = []
|
||||||
for inputs_index, input_name in enumerate(inputs_name):
|
for inpt in get_node_group_inputs(modifier.node_group):
|
||||||
input_value = modifier[input_name]
|
input_value = modifier[inpt.identifier]
|
||||||
|
|
||||||
dumped_input = None
|
dumped_input = None
|
||||||
if isinstance(input_value, bpy.types.ID):
|
if isinstance(input_value, bpy.types.ID):
|
||||||
dumped_input = input_value.uuid
|
dumped_input = input_value.uuid
|
||||||
@ -80,18 +85,16 @@ def load_modifier_geometry_node_inputs(dumped_modifier: dict, target_modifier: b
|
|||||||
:type target_modifier: bpy.type.Modifier
|
:type target_modifier: bpy.type.Modifier
|
||||||
"""
|
"""
|
||||||
|
|
||||||
inputs_name = [p for p in dir(target_modifier) if "Input_" in p]
|
for input_index, inpt in enumerate(get_node_group_inputs(target_modifier.node_group)):
|
||||||
inputs_name.sort(key=get_input_index)
|
|
||||||
for input_index, input_name in enumerate(inputs_name):
|
|
||||||
dumped_value = dumped_modifier['inputs'][input_index]
|
dumped_value = dumped_modifier['inputs'][input_index]
|
||||||
input_value = target_modifier[input_name]
|
input_value = target_modifier[inpt.identifier]
|
||||||
if isinstance(input_value, SUPPORTED_GEOMETRY_NODE_PARAMETERS):
|
if isinstance(input_value, SUPPORTED_GEOMETRY_NODE_PARAMETERS):
|
||||||
target_modifier[input_name] = dumped_value
|
target_modifier[inpt.identifier] = dumped_value
|
||||||
elif hasattr(input_value, 'to_list'):
|
elif hasattr(input_value, 'to_list'):
|
||||||
for index in range(len(input_value)):
|
for index in range(len(input_value)):
|
||||||
input_value[index] = dumped_value[index]
|
input_value[index] = dumped_value[index]
|
||||||
elif input_value and isinstance(input_value, bpy.types.ID):
|
elif inpt.type in ['COLLECTION', 'OBJECT']:
|
||||||
target_modifier[input_name] = get_datablock_from_uuid(
|
target_modifier[inpt.identifier] = get_datablock_from_uuid(
|
||||||
dumped_value, None)
|
dumped_value, None)
|
||||||
|
|
||||||
|
|
||||||
@ -168,19 +171,23 @@ def find_textures_dependencies(modifiers: bpy.types.bpy_prop_collection) -> [bpy
|
|||||||
return textures
|
return textures
|
||||||
|
|
||||||
|
|
||||||
def find_geometry_nodes(modifiers: bpy.types.bpy_prop_collection) -> [bpy.types.NodeTree]:
|
def find_geometry_nodes_dependencies(modifiers: bpy.types.bpy_prop_collection) -> [bpy.types.NodeTree]:
|
||||||
""" Find geometry nodes group from a modifier stack
|
""" Find geometry nodes dependencies from a modifier stack
|
||||||
|
|
||||||
:arg modifiers: modifiers collection
|
:arg modifiers: modifiers collection
|
||||||
:type modifiers: bpy.types.bpy_prop_collection
|
:type modifiers: bpy.types.bpy_prop_collection
|
||||||
:return: list of bpy.types.NodeTree pointers
|
:return: list of bpy.types.NodeTree pointers
|
||||||
"""
|
"""
|
||||||
nodes_groups = []
|
dependencies = []
|
||||||
for item in modifiers:
|
for mod in modifiers:
|
||||||
if item.type == 'NODES' and item.node_group:
|
if mod.type == 'NODES' and mod.node_group:
|
||||||
nodes_groups.append(item.node_group)
|
dependencies.append(mod.node_group)
|
||||||
|
for inpt in get_node_group_inputs(mod.node_group):
|
||||||
return nodes_groups
|
parameter = mod.get(inpt.identifier)
|
||||||
|
if parameter and isinstance(parameter, bpy.types.ID):
|
||||||
|
dependencies.append(parameter)
|
||||||
|
logging.info(dependencies)
|
||||||
|
return dependencies
|
||||||
|
|
||||||
|
|
||||||
def dump_vertex_groups(src_object: bpy.types.Object) -> dict:
|
def dump_vertex_groups(src_object: bpy.types.Object) -> dict:
|
||||||
@ -597,6 +604,6 @@ class BlObject(BlDatablock):
|
|||||||
|
|
||||||
if self.instance.modifiers:
|
if self.instance.modifiers:
|
||||||
deps.extend(find_textures_dependencies(self.instance.modifiers))
|
deps.extend(find_textures_dependencies(self.instance.modifiers))
|
||||||
deps.extend(find_geometry_nodes(self.instance.modifiers))
|
deps.extend(find_geometry_nodes_dependencies(self.instance.modifiers))
|
||||||
|
|
||||||
return deps
|
return deps
|
||||||
|
Reference in New Issue
Block a user