Преглед на файлове

Add node: Align Matrix Roll

Joseph Brandenburg преди 6 месеца
родител
ревизия
ee0871a8a8
променени са 4 файла, в които са добавени 66 реда и са изтрити 7 реда
  1. 1 0
      __init__.py
  2. 38 4
      misc_nodes.py
  3. 14 3
      misc_nodes_socket_templates.py
  4. 13 0
      misc_nodes_ui.py

+ 1 - 0
__init__.py

@@ -150,6 +150,7 @@ matrix_category = [
         NodeItem("UtilityMatrixTransform"),
         NodeItem("UtilityMatrixInvert"),
         NodeItem("UtilityMatrixCompose"),
+        NodeItem("UtilityMatrixAlignRoll"),
         NodeItem("UtilityTransformationMatrix"),
         NodeItem("UtilitySetBoneMatrixTail"),
     ]

+ 38 - 4
misc_nodes.py

@@ -51,6 +51,7 @@ def TellClasses():
              UtilityMatrixTransform,
              UtilityMatrixInvert,
              UtilityMatrixCompose,
+             UtilityMatrixAlignRoll,
              UtilityTransformationMatrix,
              UtilityIntToString,
              UtilityArrayGet,
@@ -64,7 +65,7 @@ def TellClasses():
             ]
 
 def matrix_from_head_tail(head, tail, normal=None):
-    from mathutils import Vector, Quaternion, Matrix
+    from mathutils import Vector, Matrix
     if normal is None:
         rotation = Vector((0,1,0)).rotation_difference((tail-head).normalized()).to_matrix()
         m= Matrix.LocRotScale(head, rotation, None)
@@ -1521,7 +1522,6 @@ class UtilityMatrixInvert(MantisNode):
         self.prepared = True
         self.executed = True
 
-
 class UtilityMatrixCompose(MantisNode):
     def __init__(self, signature, base_tree):
         super().__init__(signature, base_tree, MatrixComposeSockets)
@@ -1537,9 +1537,43 @@ class UtilityMatrixCompose(MantisNode):
         matrix.transpose(); matrix=matrix.to_4x4()
         matrix.translation = self.evaluate_input('Translation')
         self.parameters['Matrix']=matrix
-        self.prepared = True
-        self.executed = True
+        self.prepared = True; self.executed = True
+
+class UtilityMatrixAlignRoll(MantisNode):
+    def __init__(self, signature, base_tree):
+        super().__init__(signature, base_tree, MatrixAlignRollSockets)
+        self.init_parameters()
+        self.node_type = "UTILITY"
 
+    def bPrepare(self, bContext = None,):
+        from mathutils import Vector, Matrix
+        align_axis = Vector(self.evaluate_input('Alignment Vector'))
+        # why do I have to construct a vector here?
+        # why is the socket returning a bpy_prop_array ?
+        print(align_axis)
+        if align_axis.length_squared==0:
+            raise RuntimeError(f"WARN: cannot align matrix in {self}"
+                                " because the alignment vector is zero.")
+        input=self.evaluate_input('Matrix').copy()
+        y_axis= input.to_3x3().transposed()[1]
+        from .utilities import project_point_to_plane
+        projected=project_point_to_plane(
+            align_axis.normalized(), Vector((0,0,0)), y_axis).normalized()
+        # now that we have the projected vector, transform the points from
+        #   the plane of the y_axis to flat space and get the signed angle
+        from math import atan2
+        flattened = (input.to_3x3().inverted() @ projected)
+        rotation = Matrix.Rotation(atan2(flattened.x, flattened.z), 4, y_axis)
+        matrix = rotation @ input.copy()
+        matrix.translation=input.translation
+        matrix[3][3] = input[3][3]
+        self.parameters['Matrix'] = matrix
+        self.prepared = True; self.executed = True
+        # NOTE: I tried other ways of setting the matrix, including composing
+        #  it directly from the Y axis, the normalized projection of the align
+        #  axis, and their cross-product. That only nearly worked.
+        # this calculation should not work better, but it does. Why?
+        
 class UtilityTransformationMatrix(MantisNode):
     def __init__(self, signature, base_tree):
         super().__init__(signature, base_tree)

+ 14 - 3
misc_nodes_socket_templates.py

@@ -68,12 +68,23 @@ MatrixInvertSockets=[
 
 MatrixComposeSockets=[
     XBasisVector := SockTemplate(
-    name="X Basis Vector", is_input=True,  bl_idname='VectorSocket', ),
-    YBasisVector := replace(XBasisVector, name="Y Basis Vector"),
-    ZBasisVector := replace(XBasisVector, name="Z Basis Vector"),
+    name="X Basis Vector", is_input=True,  bl_idname='VectorSocket', 
+        default_value = (1.0, 0.0, 0.0) ),
+    YBasisVector := replace(XBasisVector, name="Y Basis Vector",
+        default_value = (0.0, 1.0, 0.0) ),
+    ZBasisVector := replace(XBasisVector, name="Z Basis Vector",
+        default_value = (0.0, 0.0, 1.0) ),
     Translation := replace(XBasisVector, name="Translation"),
     MatrixOutTemplate,
 ]
+
+MatrixAlignRollSockets=[
+    MatrixInTemplate := replace(Matrix1Template, name="Matrix"),
+    AlignVector := SockTemplate(name="Alignment Vector", is_input=True,
+       bl_idname='VectorSocket', default_value=(0.0,-1.0,0.0)),
+    MatrixOutTemplate,
+]
+
 CompareSockets = [
     ComparisonOperation := SockTemplate( name='Comparison',
             is_input=True, bl_idname="EnumCompareOperation",

+ 13 - 0
misc_nodes_ui.py

@@ -57,6 +57,7 @@ def TellClasses():
              UtilityMatrixTransform,
              UtilityMatrixInvert,
              UtilityMatrixCompose,
+             UtilityMatrixAlignRoll,
              UtilityTransformationMatrix,
              UtilitySetBoneMatrixTail,
 
@@ -893,6 +894,18 @@ class UtilityMatrixCompose(Node, MantisUINode):
         self.init_sockets(MatrixComposeSockets)
         self.initialized = True
 
+class UtilityMatrixAlignRoll(Node, MantisUINode):
+    """Aligns the Z axis of a matrix to point in a direction."""
+    bl_idname = "UtilityMatrixAlignRoll"
+    bl_label = "Align Matrix Roll"
+    bl_icon = "NODE"
+    initialized : bpy.props.BoolProperty(default = False)
+    mantis_node_class_name=bl_idname
+    
+    def init(self, context):
+        self.init_sockets(MatrixAlignRollSockets)
+        self.initialized = True
+
 class UtilityMatrixSetLocation(Node, MantisUINode):
     """Sets a matrix's location."""
     bl_idname = "UtilityMatrixSetLocation"