Quellcode durchsuchen

new Curve Matrix, Compose Matrix modes

Joseph Brandenburg vor 4 Wochen
Ursprung
Commit
b1e7d687e1
5 geänderte Dateien mit 150 neuen und 44 gelöschten Zeilen
  1. 37 10
      misc_nodes.py
  2. 14 5
      misc_nodes_socket_templates.py
  3. 45 9
      misc_nodes_ui.py
  4. 6 3
      socket_definitions.py
  5. 48 17
      versioning.py

+ 37 - 10
misc_nodes.py

@@ -375,6 +375,8 @@ class UtilityMatrixFromCurve(MantisNode):
         mat = Matrix.Identity(4)
         curve_name = self.evaluate_input("Curve")
         curve = bpy_object_get_guarded( curve_name, self)
+        mode = self.evaluate_input("Mode")
+        # DIVISIONS, FACTOR
         if not curve:
             prRed(f"WARN: No curve found for {self}. Using an identity matrix instead.")
             mat[3][3] = 1.0
@@ -387,10 +389,10 @@ class UtilityMatrixFromCurve(MantisNode):
             from .utilities.utilities import data_from_ribbon_mesh
             #
             num_divisions = self.evaluate_input("Total Divisions")
-            if num_divisions <= 0:
+            if mode == 'DIVISIONS' and num_divisions <= 0:
                 raise GraphError("The number of divisions in the curve must be 1 or greater.")
             m_index = self.evaluate_input("Matrix Index")
-            if m_index >= num_divisions:
+            if mode == 'DIVISIONS' and m_index >= num_divisions:
                 prRed(m_index, num_divisions)
                 raise GraphError(f"{self} tried to get a matrix-index greater the total number of divisions."
                                   "The matrix index starts at 0. You're probably off by +1.")
@@ -399,11 +401,24 @@ class UtilityMatrixFromCurve(MantisNode):
                 raise GraphError(f"{self} is attempting to read from a spline in {curve.name} that does not exist."
                                   " Try and reduce the value of Spline Index.")
             splines_factors = [ [] for i in range (spline_index)]
-            factors = [1/num_divisions*m_index, 1/num_divisions*(m_index+1)]
+            if mode == 'DIVISIONS':
+                factors = [1/num_divisions*m_index, 1/num_divisions*(m_index+1)]
+            elif mode == 'FACTOR':
+                factor = self.evaluate_input('Factor')
+                factor = min(factor, 1 - 0.0001) # to make our fake tangent work
+                factors = [ factor, factor + 0.0001 ]
+                # TODO this is technically not accurate, we want the real tangent
+                # ... but this should be close enough.
+            elif mode == 'FACTOR_WITH_TAIL':
+                factor = self.evaluate_input('Factor')
+                factor = min(factor, 1 - 0.0001) # to make our fake tangent work
+                factors = [ factor,
+                            self.evaluate_input('Factor (Tail)')]
             splines_factors.append(factors)
             data = data_from_ribbon_mesh(m, splines_factors, curve.matrix_world)
             if data[spline_index][1][0] < FLOAT_EPSILON: # radius is None:
                 raise RuntimeError(zero_radius_error_message(self, curve))
+            
             head=data[spline_index][0][0]
             tail= data[spline_index][0][1]
             axis = (tail-head).normalized()
@@ -416,6 +431,8 @@ class UtilityMatrixFromCurve(MantisNode):
             mat = matrix_from_head_tail(head, tail, normal)
             # this is in world space... let's just convert it back
             mat.translation = head - curve.location
+            if mode == 'FACTOR':
+                mat[3][3]=1.0 # Set the length
 
             # TODO HACK TODO
             # all the nodes should work in world-space, and it should be the responsibility
@@ -1584,13 +1601,23 @@ class UtilityMatrixCompose(MantisNode):
         self.node_type = "UTILITY"
 
     def bPrepare(self, bContext = None,):
-        from mathutils import Matrix
-        matrix= Matrix.Identity(3)
-        matrix[0] = self.evaluate_input('X Basis Vector')
-        matrix[1] = self.evaluate_input('Y Basis Vector')
-        matrix[2] = self.evaluate_input('Z Basis Vector')
-        matrix.transpose(); matrix=matrix.to_4x4()
-        matrix.translation = self.evaluate_input('Translation')
+        from mathutils import Matrix, Vector
+        mode = self.evaluate_input("Mode")
+        translation = self.evaluate_input('Translation')
+        length = self.evaluate_input('Bone Length')
+        match mode:
+            case "BASIS":
+                matrix= Matrix.Identity(3)
+                matrix[0] = self.evaluate_input('X Basis Vector')
+                matrix[1] = self.evaluate_input('Y Basis Vector')
+                matrix[2] = self.evaluate_input('Z Basis Vector')
+                matrix.transpose(); matrix=matrix.to_4x4()
+                matrix.translation = translation
+            case "CHANNELS":
+                rotation    = self.evaluate_input('Rotation')
+                scale       = Vector((1,1,1))
+                matrix= Matrix.LocRotScale(translation, rotation, scale)
+        matrix[3][3]=length # Length
         self.parameters['Matrix']=matrix
         self.prepared = True; self.executed = True
 

+ 14 - 5
misc_nodes_socket_templates.py

@@ -58,7 +58,8 @@ MatrixFromCurveSockets=[
         bl_idname='UnsignedIntSocket', is_input=True, default_value=0,),
     MatrixIndexTemplate := ST(name="Matrix Index", category = "divisions",
         bl_idname='UnsignedIntSocket', is_input=True, default_value=0,),
-    replace(FactorTemplate, category="factor"),
+    MatrixFromCurveFactor := replace(FactorTemplate, category="factor"),
+    MatrixFromCurveTailFactor := replace(FactorTemplate, name='Factor (Tail)', category="factor_tail"),
     MatrixOutput,
 ]
 
@@ -372,14 +373,22 @@ MatrixInvertSockets=[
 ]
 
 MatrixComposeSockets=[
+    MatrixComposeMode := ST(name='Mode', bl_idname='EnumComposeMatrixModes',
+        category='always_show', is_input=True,),
+    ComposeMatrixRotation := ST( name="Euler Rotation", is_input=True,  
+        bl_idname='VectorEulerSocket', hide = True,
+        default_value = (0.0, 0.0, 0.0), category="transform" ),
     XBasisVector := ST(
     name="X Basis Vector", is_input=True,  bl_idname='VectorSocket', 
-        default_value = (1.0, 0.0, 0.0) ),
+        default_value = (1.0, 0.0, 0.0), category='axes', ),
     YBasisVector := replace(XBasisVector, name="Y Basis Vector",
-        default_value = (0.0, 1.0, 0.0) ),
+        default_value = (0.0, 1.0, 0.0), category='axes',),
     ZBasisVector := replace(XBasisVector, name="Z Basis Vector",
-        default_value = (0.0, 0.0, 1.0) ),
-    Translation := replace(XBasisVector, name="Translation"),
+        default_value = (0.0, 0.0, 1.0), category='axes', ),
+    Translation := replace(XBasisVector, name="Translation", category='always_show'),
+    ComposeMatrixBoneLength := ST( name="Bone Length", is_input=True,
+        bl_idname='FloatPositiveSocket', 
+        default_value = 1.0, category="always_show" ),
     MatrixOutput,
 ]
 

+ 45 - 9
misc_nodes_ui.py

@@ -234,14 +234,27 @@ class UtilityMatrixFromCurve(Node, MantisMiscNode):
             mode = self.inputs['Mode'].default_value
         # We just hide/show based on the selected mode.
         for template in self.__class__.socket_templates:
-            if mode == 'DIVISIONS' and template.category == 'factor':
-                self.inputs[template.name].hide=True
-            if mode == 'DIVISIONS' and template.category == 'divisions':
-                self.inputs[template.name].hide=False
-            elif mode == 'FACTOR' and template.category == 'divisions':
-                self.inputs[template.name].hide=True
-            elif mode == 'FACTOR' and template.category == 'factor':
-                self.inputs[template.name].hide=False
+            if mode == 'DIVISIONS':
+                if template.category == 'factor':
+                    self.inputs[template.name].hide=True
+                elif template.category == 'divisions':
+                    self.inputs[template.name].hide=False
+                elif template.category == 'factor_tail':
+                    self.inputs[template.name].hide=True
+            elif mode == 'FACTOR':
+                if template.category == 'factor':
+                    self.inputs[template.name].hide=False
+                elif template.category == 'divisions':
+                    self.inputs[template.name].hide=True
+                elif template.category == 'factor_tail':
+                    self.inputs[template.name].hide=True
+            elif mode == 'FACTOR_WITH_TAIL':
+                if template.category == 'factor':
+                    self.inputs[template.name].hide=False
+                elif template.category == 'divisions':
+                    self.inputs[template.name].hide=True
+                elif template.category == 'factor_tail':
+                    self.inputs[template.name].hide=False
 
 class UtilityPointFromCurve(Node, MantisMiscNode):
     """Gets a point from a curve."""
@@ -731,10 +744,33 @@ class UtilityMatrixInvert(Node, MantisMiscNode):
 class UtilityMatrixCompose(Node, MantisMiscNode):
     """Inverts an invertable matrix, otherwise throws an error."""
     bl_idname = "UtilityMatrixCompose"
-    bl_label = "Compose Matrix"
+    bl_label = "Compose Bone Matrix"
     mantis_node_class_name=bl_idname
     socket_templates=MatrixComposeSockets
 
+    def display_update(self, parsed_tree, context):
+        # first we'll checc if the mode is connected to a noodle, should be rare
+        mode = 'BASIS'
+        if self.inputs['Mode'].is_linked:
+            if mantis_node := parsed_tree.get(get_signature_from_edited_tree(self, context)):
+                mode = mantis_node.evaluate_input("Mode")
+        else: # We can use it directly, this is a little faster.
+            mode = self.inputs['Mode'].default_value
+        # We just hide/show based on the selected mode.
+        for template in self.__class__.socket_templates:
+            if mode == 'BASIS':
+                if template.category == 'transform':
+                    self.inputs[template.name].hide=True
+                elif template.category == 'axes':
+                    self.inputs[template.name].hide=False
+            elif mode == 'CHANNELS':
+                if template.category == 'transform':
+                    self.inputs[template.name].hide=False
+                elif template.category == 'axes':
+                    self.inputs[template.name].hide=True
+            if template.category == 'always_show':
+                self.inputs[template.name].hide=False
+
 class UtilityMatrixAlignRoll(Node, MantisMiscNode):
     """Aligns the Z axis of a matrix to point in a direction."""
     bl_idname = "UtilityMatrixAlignRoll"

+ 6 - 3
socket_definitions.py

@@ -90,7 +90,10 @@ enumRotationOrder =(('AUTO', 'Auto', 'Auto'),
 eMatrixFromCurveModes = (('DIVISIONS', "Divisions", "Get a matrix from the curve automattically "
                                                     "based on dividing it into pieces."),
                          ('FACTOR', "Spline Factor", "Get a matrix from a specific factor"
-                                                     " along the spline."))
+                                                     " along the spline."),
+                         ('FACTOR_WITH_TAIL', "Spline Factor (With Tail)",
+                          "Get a matrix from a specific factor along the spline, "
+                          "and place the tail on the curve at a specific factor. "))
 
 eMatrixComposeModes = (('BASIS', "Basis Vectors", "Compose a matrix from basis vectors. "
                                                   "Mantis will not automatically orthonormalize them."),
@@ -2894,7 +2897,7 @@ class EnumMatrixFromCurveMode(MantisSocket):
     """Matrix From Curve Mode"""
     bl_idname = 'EnumMatrixFromCurveMode'
     bl_label = "Mode"
-
+    enum_display_type='DROPDOWN'
     default_value :bpy.props.EnumProperty(
         name="",
         description="Mode",
@@ -2911,7 +2914,7 @@ class EnumComposeMatrixModes(MantisSocket):
     """Compose Matrix Mode"""
     bl_idname = 'EnumComposeMatrixModes'
     bl_label = "Mode"
-
+    enum_display_type='DROPDOWN'
     default_value :bpy.props.EnumProperty(
         name="",
         description="Mode",

+ 48 - 17
versioning.py

@@ -327,6 +327,8 @@ def up_0_13_0_new_custom_prop_node(*args, **kwargs):
             prop_node.location = prop_node.location - Vector((180, -260*i))
             prop_node.select = False # it is annoying to select them all by default
     else: # just need to add the socket.
+        if node.inputs.get('Custom Properties'):
+            return # already done here
         new_input = node.inputs.new("CustomPropSocket", "Custom Properties", use_multi_input=True)
 
 def schema_enable_custom_interface_types(*args, **kwargs):
@@ -523,20 +525,49 @@ def add_new_display_features_v0_13_5(*args, **kwargs):
                 node.is_updating = False
         tree.do_live_update = live_updates
 
-# def up_0_13_5_modes_for_matrix_from_curve_and_compose_matrix(*args, **kwargs):
-#     node = kwargs['node']
-#     node.is_updating = True
-#     do_live_updates = node.id_data.do_live_updates
-#     node.id_data.do_live_updates = False
-#     # new re_init keyword should use socket template to automate the update.
-#     prGreen("THIS ONE HERE")
-#     print (node.id_data.name, node.name)
-#     print (node.inputs.keys())
-#     if "Mode" not in node.inputs.keys(): # just check here to see if it is needed.
-#         prOrange("DOING THE THING BRO")
-#         node.init_sockets(node.__class__.socket_templates, re_init=True)
-#     node.id_data.do_live_updates = do_live_updates
-#     node.is_updating = False
+def up_0_13_5_modes_for_matrix_from_curve_and_compose_matrix(*args, **kwargs):
+    node = kwargs['node']
+    if 'Mode' in node.inputs:
+        return # done already
+    tree = node.id_data
+    current_major_version = tree.mantis_version[0]
+    current_minor_version = tree.mantis_version[1]
+    current_sub_version = tree.mantis_version[2]
+    if  current_major_version > 0: return# major version must be 0
+    if current_minor_version >= 13: return# minor version must be 12 or less
+    if current_minor_version == 13 and current_sub_version >= 5: return# sub version must be 4 or less
+
+    live_updates = tree.do_live_update
+    tree.do_live_update = False
+
+    for other_node in tree.nodes:
+        if hasattr(other_node, 'is_updating'):
+            other_node.is_updating = True
+    try:
+        socket_templates = node.socket_templates
+        if node.bl_idname == 'UtilityMatrixFromCurve':
+            from .misc_nodes_socket_templates import (MatrixFromCurveMode,
+                                                    MatrixFromCurveFactor,
+                                                    MatrixFromCurveTailFactor, )
+            input_templates = ( MatrixFromCurveMode, MatrixFromCurveFactor,
+                                MatrixFromCurveTailFactor, )
+            node.init_sockets(input_templates)
+            node.inputs.move(len(node.inputs)-3, 0) # move Mode to first place
+        elif node.bl_idname == 'UtilityMatrixCompose':
+            from .misc_nodes_socket_templates import (ComposeMatrixBoneLength,
+                                                    MatrixComposeMode,
+                                                    ComposeMatrixRotation,)
+            input_templates = ( ComposeMatrixBoneLength, MatrixComposeMode,
+                                ComposeMatrixRotation,)
+            node.init_sockets(input_templates)
+            node.inputs.move(len(node.inputs)-1, 0) # These go in the top, so make em in order
+            node.inputs.move(len(node.inputs)-1, 0) # and move 'em one at a time in reverse order
+        node.socket_templates = socket_templates
+    finally:
+        for other_node in tree.nodes:
+            if hasattr(other_node, 'is_updating'):
+                other_node.is_updating = False
+        tree.do_live_update = live_updates
 
 # versioning tasks that involve Blender versions rather than Mantis versions:
 error_description_4_5_0_LTS = 'There is a bug in Blender 4.5.0 LTS, that is why these sockets are blue.'\
@@ -576,9 +607,9 @@ versioning_tasks = [
            update_fcurve_and_armature_node_to_multi_socket, ['node']),
     (['MantisTree', 'SchemaTree'], fix_bbone_default_scale_in_and_out, ['tree']),
     (['MantisTree', 'SchemaTree'], add_new_display_features_v0_13_5, ['tree']),
-    # (['UtilityMatrixFromCurve', 'UtilityMatrixCompose'],
-    #    up_0_13_5_modes_for_matrix_from_curve_and_compose_matrix,
-    #  ['node',], ),
+    (['UtilityMatrixFromCurve', 'UtilityMatrixCompose'],
+       up_0_13_5_modes_for_matrix_from_curve_and_compose_matrix,
+     ['node',], ),
 ]