Ver código fonte

Add Hook Deformer

also cleanup get_target_and_subtarget in node_container_common
also fix bug with Schema shadowing modifiers because it was reusing them by name.
Joseph Brandenburg 8 meses atrás
pai
commit
0346715a3f
3 arquivos alterados com 119 adições e 27 exclusões
  1. 89 17
      deformer_containers.py
  2. 20 0
      deformer_definitions.py
  3. 10 10
      node_container_common.py

+ 89 - 17
deformer_containers.py

@@ -12,11 +12,21 @@ def TellClasses():
              
     return [ 
              DeformerArmature,
+             DeformerHook,
              DeformerMorphTarget,
              DeformerMorphTargetDeform,
            ]
 
 
+def trace_xForm_back(nc, socket):
+    from .xForm_containers import xFormGeometryObject
+    from .misc_containers import InputExistingGeometryObject
+    from bpy.types import Object
+    if (trace := trace_single_line(nc, socket)[0] ) :
+        for i in range(len(trace)): # have to look in reverse, actually
+            if ( isinstance(trace[ i ], xFormGeometryObject ) ) or ( isinstance(trace[ i ], InputExistingGeometryObject ) ):
+                return trace[ i ].bGetObject()
+        raise GraphError(wrapRed(f"No other object found for {nc}."))
 
 def default_evaluate_input(nc, input_name):
     # duped from link_containers... should be common?
@@ -89,14 +99,7 @@ class DeformerArmature:
         if socket == "Deformer":
             return GetxForm(self)
         else:
-            from .xForm_containers import xFormGeometryObject
-            from .misc_containers import InputExistingGeometryObject
-            from bpy.types import Object
-            if (trace := trace_single_line(self, socket)[0] ) :
-                for i in range(len(trace)): # have to look in reverse, actually
-                    if ( isinstance(trace[ i ], xFormGeometryObject ) ) or ( isinstance(trace[ i ], InputExistingGeometryObject ) ):
-                        return trace[ i ].bGetObject()
-                raise GraphError(wrapRed(f"No other object found for {self}."))
+            trace_xForm_back(self, socket)
     
     # DUPLICATED FROM xForm_containers::xFormBone 
     # DEDUP HACK HACK HACK HACK HACK
@@ -164,14 +167,11 @@ class DeformerArmature:
                 bpy.ops.object.datalayout_transfer(data_type='VGROUP_WEIGHTS')
                 bpy.ops.object.data_transfer(data_type='VGROUP_WEIGHTS')
             bpy.ops.object.mode_set(mode=original_mode)
-    
+         
     def bFinalize(self, bContext=None):
         prGreen("Executing Armature Deform Node")
         mod_name = self.evaluate_input("Name")
-        try:
-            d = self.GetxForm().bGetObject().modifiers[mod_name]
-        except KeyError:
-            d = self.GetxForm().bGetObject().modifiers.new(mod_name, type='ARMATURE')
+        d = self.GetxForm().bGetObject().modifiers.new(mod_name, type='ARMATURE')
         if d is None:
             raise RuntimeError(f"Modifier was not created in node {self} -- the object is invalid.")
         self.bObject = d
@@ -227,6 +227,81 @@ class DeformerArmature:
             self.copy_weights()
 
 
+class DeformerHook:
+    '''A node representing a hook deformer'''
+
+    def __init__(self, signature, base_tree):
+        self.base_tree=base_tree
+        self.signature = signature
+        self.inputs = {
+          "Hook Target"    : NodeSocket(is_input = True, name = "Hook Target", node = self,),
+          "Index"          : NodeSocket(is_input = True, name = "Index", node = self),
+          "Deformer"       : NodeSocket(is_input = True, name = "Deformer", node = self),
+        }
+        self.outputs = {
+          "Deformer" : NodeSocket(is_input = False, name = "Deformer", node=self), }
+        self.parameters = {
+          "Hook Target"     : None,
+          "Index"           : None,
+          "Deformer"        : None,
+          "Name"            : None,
+        }
+        # now set up the traverse target...
+        self.inputs["Deformer"].set_traverse_target(self.outputs["Deformer"])
+        self.outputs["Deformer"].set_traverse_target(self.inputs["Deformer"])
+        self.node_type = "LINK"
+        self.hierarchy_connections, self.connections = [], []
+        self.hierarchy_dependencies, self.dependencies = [], []
+        self.prepared = True
+        self.executed = False
+
+    def evaluate_input(self, input_name):
+        return default_evaluate_input(self, input_name)
+
+    def GetxForm(self, socket="Deformer"):
+        if socket == "Deformer":
+            return GetxForm(self)
+        else:
+            trace_xForm_back(self, socket)
+            
+    def bExecute(self, bContext = None,):
+        self.executed = True
+
+    def bFinalize(self, bContext=None):
+        from bpy.types import Bone, PoseBone, Object
+        prGreen(f"Executing Hook Deform Node: {self}")
+        mod_name = self.evaluate_input("Name")
+        target_node = self.evaluate_input('Hook Target')
+        target = target_node.bGetObject(); subtarget = ""
+        if isinstance(target, Bone) or isinstance(target, PoseBone):
+            subtarget = target.name; target = target.id_data
+        ob=self.GetxForm().bGetObject()
+        prOrange(self.GetxForm().bGetObject())
+        reuse = False
+        for m in ob.modifiers:
+            if False and m.type == 'HOOK' and m.object == target and m.subtarget == subtarget:
+                d = m; reuse = True; prOrange("REUSE"); break
+        else:
+            # don't reuse it
+            d = ob.modifiers.new(mod_name, type='HOOK')
+            if d is None:
+                raise RuntimeError(f"Modifier was not created in node {self} -- the object is invalid.")
+        get_target_and_subtarget(self, d, input_name="Hook Target")
+        vertices_used=[]
+        if reuse: # Get the verts in the list... filter out all the unneeded 0's
+            vertices_used = list(d.vertex_indices)
+            include_0 = 0 in vertices_used
+            vertices_used = list(filter(lambda a : a != 0, vertices_used))
+            if include_0: vertices_used.append(0)
+        # now we add the selected vertex to the list, too
+        vertices_used.append(self.evaluate_input("Index"))
+        d.vertex_indices_set(vertices_used)
+        # props_sockets = {
+        # 'vertex_group'               : ("Blend Vertex Group", ""),
+        # }
+        # evaluate_sockets(self, d, props_sockets)
+
+
 class DeformerMorphTarget:
     '''A node representing an armature deformer'''
     def __init__(self, signature, base_tree):
@@ -323,10 +398,7 @@ class DeformerMorphTargetDeform:
 
     def gen_morph_target_modifier(self):
         mod_name = self.evaluate_input("Name")
-        try:
-            m = self.GetxForm().bGetObject().modifiers[mod_name]
-        except KeyError:
-            m = self.GetxForm().bGetObject().modifiers.new(mod_name, type='NODES')
+        m = self.GetxForm().bGetObject().modifiers.new(mod_name, type='NODES')
         self.bObject = m
         # at this point we make the node tree
         from bpy import data

+ 20 - 0
deformer_definitions.py

@@ -10,6 +10,7 @@ from .utilities import (prRed, prGreen, prPurple, prWhite, prOrange,
 def TellClasses():
     return [
              DeformerArmatureNode,
+             DeformerHook,
              DeformerMorphTargetDeform,
              DeformerMorphTarget,
            ]
@@ -59,6 +60,25 @@ class DeformerArmatureNode(Node, DeformerNode):
             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)
+
+    def init(self, context):
+        self.inputs.new("DeformerSocket", "Deformer")
+        self.inputs.new('xFormSocket', "Hook Target")
+        self.inputs.new('IntSocket', "Index")
+        # self.inputs.new('StringSocket', "Blend Vertex Group")
+        # self.inputs.new('BooleanSocket', "Invert Vertex Group")
+        self.outputs.new('DeformerSocket', "Deformer")
+        self.initialized = True
+    
+    # def display_update(self, parsed_tree, context):
+
+
 from .utilities import get_socket_maps, relink_socket_map
 
 # TODO this should probably not be in this file but intstead in Utilities or something

+ 10 - 10
node_container_common.py

@@ -335,7 +335,7 @@ def get_parent(node_container, type = 'XFORM'):
     # it is OK to generate a new, "fake" node container for this!
 
 def get_target_and_subtarget(node_container, linkOb, input_name = "Target"):
-    from bpy.types import PoseBone, Object, SplineIKConstraint, ArmatureModifier
+    from bpy.types import PoseBone, Object, SplineIKConstraint, ArmatureModifier, HookModifier
     subtarget = ''; target = node_container.evaluate_input(input_name)
     if target:
         if (isinstance(target.bGetObject(), PoseBone)):
@@ -350,16 +350,16 @@ def get_target_and_subtarget(node_container, linkOb, input_name = "Target"):
             if target and target.type not in ["CURVE"]:
                 raise GraphError(wrapRed("Error: %s requires a Curve input, not %s" %
                                  (node_container, type(target))))
-            # don't get a subtarget
-            linkOb.target = target
-    elif (isinstance(linkOb, ArmatureModifier)):
-        linkOb.object = target
-    elif (input_name == 'Target'): # this is sloppy, but it werks
-        linkOb.target, linkOb.subtarget = target, subtarget
-    elif (input_name == 'Pole Target'):
+            linkOb.target = target# don't get a subtarget
+    if (input_name == 'Pole Target'):
         linkOb.pole_target, linkOb.pole_subtarget = target, subtarget
-    else: # this is really just for Armature Constraint targets...
-        linkOb.target, linkOb.subtarget = target, subtarget
+    else:
+        if hasattr(linkOb, "target"):
+            linkOb.target = target
+        if hasattr(linkOb, "object"):
+            linkOb.object = target
+        if hasattr(linkOb, "subtarget"):
+            linkOb.subtarget = subtarget
 
 
 def setup_custom_props(nc):