Sfoglia il codice sorgente

Add Radius Driver to Hook Deformer

I've added an option to drive the radius of curve points with the Hook
Deformer.
Joseph Brandenburg 6 mesi fa
parent
commit
339a7c2e0c
3 ha cambiato i file con 67 aggiunte e 2 eliminazioni
  1. 51 2
      deformer_containers.py
  2. 2 0
      deformer_socket_templates.py
  3. 14 0
      xForm_containers.py

+ 51 - 2
deformer_containers.py

@@ -232,6 +232,41 @@ class DeformerHook(MantisDeformerNode):
         self.set_traverse([("Deformer", "Deformer")])
         self.prepared = True
 
+    def driver_for_radius(self, object, hook, index, influence, bezier=True):
+        """ Creates a driver to control the radius of a curve point with the hook."""
+        var_template = {"owner":hook,
+                        "name":"a",
+                        "type":"TRANSFORMS",
+                        "space":'WORLD_SPACE',
+                        "channel":'SCALE_X',}
+        keys_template = [{"co":(0,0),
+                          "interpolation": "LINEAR",
+                          "type":"KEYFRAME",},
+                         {"co":(1,influence),
+                          "interpolation": "LINEAR",
+                          "type":"KEYFRAME",},]
+        if bezier:
+            owner=object.data.splines[0].bezier_points
+        else:
+            owner=object.data.splines[0].points
+        driver = {
+            "owner":owner[index],
+            "prop":"radius",
+            "ind":-1,
+            "extrapolation":"LINEAR",
+            "type":"AVERAGE",
+            "vars":[],
+            "keys":keys_template,
+        }
+        from .drivers import CreateDrivers
+        axes='XYZ'
+
+        for i in range(3):
+            var = var_template.copy()
+            var["channel"]="SCALE_"+axes[i]
+            driver["vars"].append(var)
+        CreateDrivers([driver])
+
     def GetxForm(self, socket="Deformer"):
         if socket == "Deformer":
             return GetxForm(self)
@@ -279,13 +314,27 @@ class DeformerHook(MantisDeformerNode):
             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
+        affect_radius=self.evaluate_input("Affect Curve Radius")
+        auto_bezier=self.evaluate_input("Auto-Bezier")
         vertex = self.evaluate_input("Curve Point Index")
-        if ob.type == 'CURVE' and ob.data.splines[0].type == 'BEZIER' and \
-                      self.evaluate_input("Auto-Bezier"):
+        if ob.type == 'CURVE' and ob.data.splines[0].type == 'BEZIER' and auto_bezier:
+            if affect_radius:
+                self.driver_for_radius(ob, target_node.bGetObject(), vertex, d.strength)
             vertex*=3
             vertices_used.extend([vertex, vertex+1, vertex+2])
         else:
             vertices_used.append(vertex)
+        # if we have a curve and it is NOT using auto-bezier for the verts..
+        if ob.type == 'CURVE' and ob.data.splines[0].type == 'BEZIER' and affect_radius and not auto_bezier:
+            print (f"WARN: {self}: \"Affect Radius\" may not behave as expected"
+                    " when used on Bezier curves without Auto-Bezier")
+            #bezier point starts at 1, and then every third vert, so 4, 7, 10...
+            if vertex%3==1:
+                self.driver_for_radius(ob, target_node.bGetObject(), vertex, d.strength)
+        if ob.type == 'CURVE' and ob.data.splines[0].type != 'BEZIER' and \
+                    affect_radius:
+            self.driver_for_radius(ob, target_node.bGetObject(), vertex, d.strength, bezier=False)
+            
         d.vertex_indices_set(vertices_used)
         evaluate_sockets(self, d, props_sockets)
         finish_drivers(self)

+ 2 - 0
deformer_socket_templates.py

@@ -16,6 +16,8 @@ HookSockets= [
         is_input=True, default_value=0, ),
     Influence := SockTemplate(name="Influence", bl_idname='FloatFactorSocket',
         is_input=True, default_value=1.0, blender_property='strength'),
+    HookDrivesRadius := SockTemplate(name="Affect Curve Radius", bl_idname='BooleanSocket',
+        is_input=True, default_value=True),
     HookAutoBezier := SockTemplate(name="Auto-Bezier", bl_idname='BooleanSocket',
         is_input=True, default_value=True, ),
     DeformerOutput := SockTemplate(name="Deformer", bl_idname='DeformerSocket',

+ 14 - 0
xForm_containers.py

@@ -692,6 +692,20 @@ class xFormGeometryObject(MantisNode):
             self.bObject = bpy.data.objects.new(self.evaluate_input("Name"), data)
         if self.bObject and (self.inputs["Geometry"].is_linked and self.bObject.type  in ["MESH", "CURVE"]):
             self.bObject.data = trace[-1].node.bGetObject()
+        # NOW: find out if we need to duplicate the object data.
+        dupe_data=False
+        node_line = trace_single_line(self, "Deformer")[0]
+        from .deformer_containers import DeformerHook
+        for deformer in node_line:
+            if isinstance(deformer, DeformerHook) and  \
+               deformer.evaluate_input("Affect Curve Radius") == True and \
+               self.bObject.type == 'CURVE':
+                    print(f"INFO: Duplicating data {self.bObject.data.name} in {self} so it can be used for drivers.")
+                    dupe_data=True; break
+        if dupe_data:
+            name = self.bObject.data.name
+            self.bObject.data=self.bObject.data.copy()
+            self.bObject.data.name = name+"_MANTIS"
         reset_object_data(self.bObject)
         matrix= get_matrix(self)
         self.parameters['Matrix'] = matrix