| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- import bpy
- from bpy.types import NodeTree, Node, NodeSocket
- from .base_definitions import MantisUINode, DeformerNode, get_signature_from_edited_tree
- from.deformer_socket_templates import *
- from .utilities import (prRed, prGreen, prPurple, prWhite, prOrange,
- wrapRed, wrapGreen, wrapPurple, wrapWhite,
- wrapOrange,)
- def TellClasses():
- return [
- DeformerArmatureNode,
- DeformerHook,
- DeformerMorphTargetDeform,
- DeformerMorphTarget,
- DeformerSurfaceDeform,
- DeformerMeshDeform,
- DeformerLatticeDeform,
- DeformerSmoothCorrectiveDeform,
- ]
- def default_traverse(self, socket):
- if (socket == self.outputs["Deformer"]):
- return self.inputs["Deformer"]
- if (socket == self.inputs["Deformer"]):
- return self.outputs["Deformer"]
- return None
- class DeformerArmatureNode(Node, DeformerNode):
- '''A node representing an Armature Deformer'''
- bl_idname = 'DeformerArmature'
- bl_label = "Armature Deform"
- bl_icon = 'MOD_ARMATURE'
- initialized : bpy.props.BoolProperty(default = False)
- mantis_node_class_name=bl_idname
- def init(self, context):
- # self.inputs.new ("RelationshipSocket", "Input Relationship")
- self.inputs.new('xFormSocket', "Armature Object")
- self.inputs.new('StringSocket', "Blend Vertex Group")
- # self.inputs.new('StringSocket', "Preserve Volume Vertex Group") #TODO figure out the right UX for automatic dual-quat blending
- self.inputs.new('BooleanSocket', "Invert Vertex Group")
-
- self.inputs.new('BooleanSocket', "Preserve Volume")
- # TODO: make the above controlled by a vertex group instead.
- self.inputs.new('BooleanSocket', "Use Multi Modifier")# might just set this auto
- self.inputs.new('BooleanSocket', "Use Envelopes")
- self.inputs.new('BooleanSocket', "Use Vertex Groups")
-
- self.inputs.new("DeformerSocket", "Deformer")
- s = self.inputs.new("xFormSocket", "Copy Skin Weights From")
- s.hide = True
- self.inputs.new("EnumSkinning", "Skinning Method")
-
- self.outputs.new('DeformerSocket', "Deformer")
- self.initialized = True
-
- def display_update(self, parsed_tree, context):
- self.inputs["Copy Skin Weights From"].hide = True
- node_tree = context.space_data.path[0].node_tree
- nc = parsed_tree.get(get_signature_from_edited_tree(self, context))
- if nc:
- self.inputs["Copy Skin Weights From"].hide = not (nc.evaluate_input("Skinning Method") == "COPY_FROM_OBJECT")
-
- class DeformerHook(Node, DeformerNode):
- '''A node representing a Hook Deformer'''
- bl_idname = 'DeformerHook'
- bl_label = "Hook Deform"
- bl_icon = 'HOOK'
- initialized : bpy.props.BoolProperty(default = False)
- mantis_node_class_name=bl_idname
- def init(self, context):
- self.init_sockets(HookSockets)
- self.initialized = True
-
- def display_update(self, parsed_tree, context):
- curve_sockets = [
- self.inputs["Affect Curve Radius"],
- self.inputs['Auto-Bezier'],
- self.inputs['Spline Index'],
- ]
- is_curve_hook=True
- if self.outputs["Deformer"].is_linked:
- from bpy.types import Object
- if (mantis_node := parsed_tree.get(get_signature_from_edited_tree(self, context))):
- if (xforms := mantis_node.GetxForm()):
- for xF_node in xforms:
- if (ob := xF_node.bObject) and isinstance (xF_node, Object):
- if ob.type != 'CURVE': is_curve_hook=False
- for socket in curve_sockets:
- socket.hide=not is_curve_hook
- from .utilities import get_socket_maps, relink_socket_map
- # TODO this should probably not be in this file but intstead in Utilities or something
- def simple_do_relink(node, map, in_out='INPUT'):
- from bpy.types import NodeSocket
- for key, val in map.items():
- s = node.inputs.get(key) if in_out == "INPUT" else node.outputs.get(key)
- if s is None:
- if in_out == "INPUT":
- if node.num_targets > 0:
- s = node.inputs["Target."+str(node.num_targets-1).zfill(3)]
- else:
- continue
- if isinstance(val, list):
- for sub_val in val:
- if isinstance(sub_val, NodeSocket):
- if in_out =='INPUT':
- node.id_data.links.new(input=sub_val, output=s)
- else:
- node.id_data.links.new(input=s, output=sub_val)
- else:
- try:
- s.default_value = val
- except (AttributeError, ValueError, TypeError): # must be readonly or maybe it doesn't have a d.v.. TypeError if the d.v. is None at this point
- pass
- # Dynamic
- # - each Morph Target gets a MT input
- # - each Morph Target gets an influence input
- class DeformerMorphTargetDeform(Node, DeformerNode):
- '''A node representing a Morph Target Deformer'''
- bl_idname = 'DeformerMorphTargetDeform'
- bl_label = "Morph Deform"
- bl_icon = 'MOD_ARMATURE'
- initialized : bpy.props.BoolProperty(default = False)
- num_targets : bpy.props.IntProperty(default = 0)
- mantis_node_class_name=bl_idname
- def init(self, context):
- self.id_data.do_live_update = False
- self.inputs.new('DeformerSocket', 'Deformer', )
- self.inputs.new('BooleanSocket', 'Use Shape Key', )
- s = self.inputs.new('BooleanSocket', 'Use Offset', )
- s.default_value = True
- self.inputs.new('WildcardSocket', '', identifier='__extend__')
- self.outputs.new('DeformerSocket', "Deformer")
- self.update_morph_deformer()
- def update_morph_deformer(self, force=False):
- self.initialized = False
- # use_offset = self.inputs["Use Offset"].default_value
- socket_maps = get_socket_maps(self)
- if socket_maps is None:
- return
- input_map = socket_maps[0]
- # checc to see if targets have been removed... then modify the input map if necessary
- targets_deleted = 0 # this should usually be either 0 or 1
- for i in range(self.num_targets):
- name = "Target."+str(i).zfill(3); inf_name = "Value."+str(i).zfill(3)
- if self.inputs[name].is_linked == False:
- del input_map[name]; del input_map[inf_name]
- targets_deleted+=1
- elif targets_deleted: # move it back
- new_name = "Target."+str(i-targets_deleted).zfill(3); new_inf_name = "Value."+str(i-targets_deleted).zfill(3)
- input_map[new_name] = input_map[name]; input_map[new_inf_name] = input_map[inf_name]
- del input_map[name]; del input_map[inf_name]
- self.num_targets-=targets_deleted
- if self.inputs[-1].is_linked and self.inputs[-1].bl_idname == 'WildcardSocket':
- self.num_targets+=1
- self.inputs.clear()
- self.inputs.new('DeformerSocket', 'Deformer', )
- self.inputs.new('BooleanSocket', 'Use Shape Key', )
- self.inputs.new('BooleanSocket', 'Use Offset', )
- for i in range(self.num_targets):
- self.inputs.new("MorphTargetSocket", "Target."+str(i).zfill(3))
- self.inputs.new("FloatSocket", "Value."+str(i).zfill(3))
- simple_do_relink(self, input_map, in_out='INPUT')
- if self.inputs[-1].bl_idname not in ["WildcardSocket"]:
- self.inputs.new('WildcardSocket', '', identifier='__extend__')
- self.initialized = True
- def update(self):
- if self.id_data.is_exporting:
- return # so that we don't update it while saving/loading the tree
- self.update_morph_deformer(force=False)
-
- def display_update(self, parsed_tree, context):
- if self.inputs["Deformer"].is_linked:
- if self.inputs["Deformer"].links[0].from_node.bl_idname not in [self.bl_idname, "NodeGroupInput"]:
- self.inputs["Use Shape Key"].default_value = False
- self.inputs["Use Shape Key"].hide = True
- elif self.inputs["Deformer"].links[0].from_node.inputs["Use Shape Key"].default_value == False:
- self.inputs["Use Shape Key"].default_value = False
- self.inputs["Use Shape Key"].hide = True
- if self.inputs["Use Offset"] == False:
- self.inputs["Use Shape Key"].hide = True
- self.inputs["Use Shape Key"].default_value = False
- # TODO: there is no reason for this to be a separate node!
- class DeformerMorphTarget(Node, DeformerNode):
- '''A node representing a single Morph Target'''
- bl_idname = 'DeformerMorphTarget'
- bl_label = "Morph Target"
- bl_icon = 'SHAPEKEY_DATA'
- initialized : bpy.props.BoolProperty(default = False)
- num_targets : bpy.props.IntProperty(default = 0)
- mantis_node_class_name=bl_idname
- def init(self, context):
- self.inputs.new('xFormSocket', "Relative to")
- self.inputs.new('xFormSocket', "Object")
- self.inputs.new('StringSocket', "Vertex Group")
- self.outputs.new('MorphTargetSocket', "Morph Target")
- self.initialized = True
- class DeformerSurfaceDeform(Node, DeformerNode):
- '''A node representing a Surface Deform modifier'''
- bl_idname = 'DeformerSurfaceDeform'
- bl_label = "Surface Deform"
- bl_icon = 'MOD_SOFT'
- initialized : bpy.props.BoolProperty(default = False)
- num_targets : bpy.props.IntProperty(default = 0)
- mantis_node_class_name=bl_idname
- def init(self, context):
- self.init_sockets(SurfaceDeformSockets)
- self.initialized = True
- class DeformerMeshDeform(Node, DeformerNode):
- '''A node representing a Mesh Deform modifier'''
- bl_idname = 'DeformerMeshDeform'
- bl_label = "Mesh Deform"
- bl_icon = 'MOD_SOFT'
- initialized : bpy.props.BoolProperty(default = False)
- num_targets : bpy.props.IntProperty(default = 0)
- mantis_node_class_name=bl_idname
- def init(self, context):
- self.init_sockets(MeshDeformSockets)
- self.initialized = True
- class DeformerLatticeDeform(Node, DeformerNode):
- '''A node representing a Lattice Deformer'''
- bl_idname = 'DeformerLatticeDeform'
- bl_label = "Lattice Deform"
- bl_icon = 'MOD_LATTICE'
- initialized : bpy.props.BoolProperty(default = False)
- num_targets : bpy.props.IntProperty(default = 0)
- mantis_node_class_name=bl_idname
- def init(self, context):
- self.init_sockets(LatticeDeformSockets)
- self.initialized = True
- class DeformerSmoothCorrectiveDeform(Node, DeformerNode):
- '''A node representing a Corrective Smooth Deformer'''
- bl_idname = 'DeformerSmoothCorrectiveDeform'
- bl_label = "Smooth Deform"
- bl_icon = 'MOD_SMOOTH'
- initialized : bpy.props.BoolProperty(default = False)
- num_targets : bpy.props.IntProperty(default = 0)
- mantis_node_class_name=bl_idname
- def init(self, context):
- self.init_sockets(SmoothDeformSockets)
- self.initialized = True
- def display_update(self, parsed_tree, context):
- use_corrective_smooth = self.inputs["Use Corrective Smooth"]
- if ( use_corrective_smooth.is_linked or
- use_corrective_smooth.default_value == False): # this is inverted
- self.inputs['Corrective Smooth Scale'].hide = False
- else:
- self.inputs['Corrective Smooth Scale'].hide = True
- # Set up the class property that ties the UI classes to the Mantis classes.
- for cls in TellClasses():
- cls.set_mantis_class()
|