Jelajahi Sumber

Add Radius Driver to Hook Deformer

I've added an option to drive the radius of curve points with the Hook
Deformer.
Joseph Brandenburg 11 bulan lalu
induk
melakukan
339a7c2e0c
3 mengubah file dengan 67 tambahan dan 2 penghapusan
  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