[Bf-extensions-cvs] [6bb8ab3a] master: Rigify: various additions to bone, mechanism and widget utilities.

Alexander Gavrilov noreply at git.blender.org
Sun Sep 29 17:30:31 CEST 2019


Commit: 6bb8ab3ad7b8131ffa9ed3261b6da8627903f3b1
Author: Alexander Gavrilov
Date:   Sun Sep 29 11:00:38 2019 +0300
Branches: master
https://developer.blender.org/rBA6bb8ab3ad7b8131ffa9ed3261b6da8627903f3b1

Rigify: various additions to bone, mechanism and widget utilities.

Support easier setting of bone orientation via matrix, inherit_scale,
invert_x/y/z constraint properties, computing a matrix from two axis
vectors, adjusting widget positions, and add a pivot widget.

===================================================================

M	rigify/utils/bones.py
M	rigify/utils/mechanism.py
M	rigify/utils/misc.py
M	rigify/utils/rig.py
M	rigify/utils/widgets.py
M	rigify/utils/widgets_basic.py

===================================================================

diff --git a/rigify/utils/bones.py b/rigify/utils/bones.py
index 738f5d42..6a09cee1 100644
--- a/rigify/utils/bones.py
+++ b/rigify/utils/bones.py
@@ -261,7 +261,7 @@ def flip_bone_chain(obj, bone_names):
         bone.use_connect = True
 
 
-def put_bone(obj, bone_name, pos):
+def put_bone(obj, bone_name, pos, *, matrix=None, length=None, scale=None):
     """ Places a bone at the given position.
     """
     if bone_name not in obj.data.edit_bones:
@@ -270,8 +270,25 @@ def put_bone(obj, bone_name, pos):
     if obj == bpy.context.active_object and bpy.context.mode == 'EDIT_ARMATURE':
         bone = obj.data.edit_bones[bone_name]
 
-        delta = pos - bone.head
-        bone.translate(delta)
+        if matrix is not None:
+            old_len = len(matrix)
+            matrix = matrix.to_4x4()
+
+            if pos is not None:
+                matrix.translation = pos
+            elif old_len < 4:
+                matrix.translation = bone.head
+
+            bone.matrix = matrix
+
+        else:
+            delta = pos - bone.head
+            bone.translate(delta)
+
+        if length is not None:
+            bone.length = length
+        elif scale is not None:
+            bone.length *= scale
     else:
         raise MetarigError("Cannot 'put' bones outside of edit mode")
 
@@ -394,18 +411,20 @@ class BoneUtilityMixin(object):
         """Get the name of the parent bone, or None."""
         return get_name(self.get_bone(bone_name).parent)
 
-    def set_bone_parent(self, bone_name, parent_name, use_connect=False):
+    def set_bone_parent(self, bone_name, parent_name, use_connect=False, inherit_scale=None):
         """Set the parent of the bone."""
         eb = self.obj.data.edit_bones
         bone = eb[bone_name]
         if use_connect is not None:
             bone.use_connect = use_connect
+        if inherit_scale is not None:
+            bone.inherit_scale = inherit_scale
         bone.parent = (eb[parent_name] if parent_name else None)
 
-    def parent_bone_chain(self, bone_names, use_connect=None):
+    def parent_bone_chain(self, bone_names, use_connect=None, inherit_scale=None):
         """Link bones into a chain with parenting. First bone may be None."""
         for parent, child in pairwise(bone_names):
-            self.set_bone_parent(child, parent, use_connect=use_connect)
+            self.set_bone_parent(child, parent, use_connect=use_connect, inherit_scale=inherit_scale)
 
 #=============================================
 # B-Bones
diff --git a/rigify/utils/mechanism.py b/rigify/utils/mechanism.py
index 8cd34624..46545096 100644
--- a/rigify/utils/mechanism.py
+++ b/rigify/utils/mechanism.py
@@ -38,7 +38,7 @@ def _set_default_attr(obj, options, attr, value):
 
 def make_constraint(
         owner, type, target=None, subtarget=None, *, insert_index=None,
-        space=None, track_axis=None, use_xyz=None, use_limit_xyz=None,
+        space=None, track_axis=None, use_xyz=None, use_limit_xyz=None, invert_xyz=None,
         **options):
     """
     Creates and initializes constraint of the specified type for the owner bone.
@@ -51,6 +51,7 @@ def make_constraint(
       track_axis       : allows shorter X, Y, Z, -X, -Y, -Z notation
       use_xyz          : list of 3 items is assigned to use_x, use_y and use_z options
       use_limit_xyz    : list of 3 items is assigned to use_limit_x/y/z options
+      invert_xyz       : list of 3 items is assigned to invert_x, invert_y and invert_z options
       min/max_x/y/z    : a corresponding use_(min/max/limit)_(x/y/z) option is set to True
 
     Other keyword arguments are directly assigned to the constraint options.
@@ -80,6 +81,9 @@ def make_constraint(
     if use_limit_xyz is not None:
         con.use_limit_x, con.use_limit_y, con.use_limit_z = use_limit_xyz[0:3]
 
+    if invert_xyz is not None:
+        con.invert_x, con.invert_y, con.invert_z = invert_xyz[0:3]
+
     for key in ['min_x', 'max_x', 'min_y', 'max_y', 'min_z', 'max_z']:
         if key in options:
             _set_default_attr(con, options, 'use_'+key, True)
diff --git a/rigify/utils/misc.py b/rigify/utils/misc.py
index b0f79ea7..4d0fbad3 100644
--- a/rigify/utils/misc.py
+++ b/rigify/utils/misc.py
@@ -18,6 +18,7 @@
 
 # <pep8 compliant>
 
+import bpy
 import math
 import collections
 
@@ -56,6 +57,28 @@ def angle_on_plane(plane, vec1, vec2):
 
     return angle * sign
 
+
+# Convert between a matrix and axis+roll representations.
+# Re-export the C implementation internally used by bones.
+matrix_from_axis_roll = bpy.types.Bone.MatrixFromAxisRoll
+axis_roll_from_matrix = bpy.types.Bone.AxisRollFromMatrix
+
+
+def matrix_from_axis_pair(y_axis, other_axis, axis_name):
+    assert axis_name in 'xz'
+
+    y_axis = Vector(y_axis).normalized()
+
+    if axis_name == 'x':
+        z_axis = Vector(other_axis).cross(y_axis).normalized()
+        x_axis = y_axis.cross(z_axis)
+    else:
+        x_axis = y_axis.cross(other_axis).normalized()
+        z_axis = x_axis.cross(y_axis)
+
+    return Matrix((x_axis, y_axis, z_axis)).transposed()
+
+
 #=============================================
 # Color correction functions
 #=============================================
diff --git a/rigify/utils/rig.py b/rigify/utils/rig.py
index 41027c69..8c646ab5 100644
--- a/rigify/utils/rig.py
+++ b/rigify/utils/rig.py
@@ -235,8 +235,8 @@ def write_metarig(obj, layers=False, func_name="create", groups=False):
     for bone_name in bones:
         bone = arm.edit_bones[bone_name]
         code.append("    bone = arm.edit_bones.new(%r)" % bone.name)
-        code.append("    bone.head[:] = %.4f, %.4f, %.4f" % bone.head.to_tuple(4))
-        code.append("    bone.tail[:] = %.4f, %.4f, %.4f" % bone.tail.to_tuple(4))
+        code.append("    bone.head = %.4f, %.4f, %.4f" % bone.head.to_tuple(4))
+        code.append("    bone.tail = %.4f, %.4f, %.4f" % bone.tail.to_tuple(4))
         code.append("    bone.roll = %.4f" % bone.roll)
         code.append("    bone.use_connect = %s" % str(bone.use_connect))
         if bone.parent:
diff --git a/rigify/utils/widgets.py b/rigify/utils/widgets.py
index 6d83264a..037d4118 100644
--- a/rigify/utils/widgets.py
+++ b/rigify/utils/widgets.py
@@ -160,6 +160,14 @@ def adjust_widget_axis(obj, axis='y', offset=0.0):
         vert.co = matrix @ vert.co
 
 
+def adjust_widget_transform(obj, matrix):
+    """Adjust the generated widget by applying a world space correction matrix to the mesh."""
+    if obj:
+        obmat = obj.matrix_basis
+        matrix = obmat.inverted() @ matrix @ obmat
+        obj.data.transform(matrix)
+
+
 def write_widget(obj):
     """ Write a mesh object as a python script for widget use.
     """
@@ -170,9 +178,9 @@ def write_widget(obj):
 
     # Vertices
     script += "        verts = ["
-    for v in obj.data.vertices:
-        script += "(" + str(v.co[0]) + "*size, " + str(v.co[1]) + "*size, " + str(v.co[2]) + "*size),"
-        script += "\n                 "
+    for i, v in enumerate(obj.data.vertices):
+        script += "({:g}*size, {:g}*size, {:g}*size),".format(v.co[0], v.co[1], v.co[2])
+        script += "\n                 " if i % 2 == 1 else " "
     script += "]\n"
 
     # Edges
diff --git a/rigify/utils/widgets_basic.py b/rigify/utils/widgets_basic.py
index bb60237c..a40806ad 100644
--- a/rigify/utils/widgets_basic.py
+++ b/rigify/utils/widgets_basic.py
@@ -127,3 +127,35 @@ def create_bone_widget(rig, bone_name, r1=0.1, l1=0.0, r2=0.04, l2=1.0, bone_tra
         mesh.update()
 
 
+def create_pivot_widget(rig, bone_name, axis_size=1.0, cap_size=1.0, square=False, bone_transform_name=None):
+    """Creates a widget similar to Plain Axes empty, but with a cross or
+       a square on the end of each axis line.
+    """
+    obj = create_widget(rig, bone_name, bone_transform_name)
+    if obj is not None:
+        axis = 0.5 * axis_size
+        cap = 0.05 * cap_size
+        if square:
+            verts = [(0, 0, -axis), (-axis, 0, 0), (0, 0, axis), (axis, 0, 0), (axis, cap, -cap), (axis, cap, cap),
+                     (0, -axis, 0), (0, axis, 0), (cap, axis, cap), (cap, axis, -cap), (axis, -cap, -cap), (axis, -cap, cap),
+                     (-cap, axis, cap), (-cap, axis, -cap), (-axis, cap, cap), (-axis, cap, -cap), (-axis, -cap, cap), (-axis, -cap, -cap),
+                     (-cap, -axis, cap), (-cap, -axis, -cap), (cap, -axis, cap), (cap, -axis, -cap), (-cap, -cap, -axis), (-cap, cap, -axis),
+                     (cap, -cap, -axis), (cap, cap, -axis), (-cap, cap, axis), (-cap, -cap, axis), (cap, cap, axis), (cap, -cap, axis) ]
+            edges = [(10, 4), (4, 5), (8, 9), (0, 2), (12, 8), (6, 7), (11, 10), (13, 12), (5, 11), (9, 13),
+                     (3, 1), (14, 15), (16, 14), (17, 16), (15, 17), (18, 19), (20, 18), (21, 20), (19, 21), (22, 23),
+                     (24, 22), (25, 24), (23, 25), (26, 27), (28, 26), (29, 28), (27, 29) ]
+        else:
+            verts = [(0, 0, -axis), (-axis, 0, 0), (0, 0, axis), (axis, 0, 0), (-cap, 0, -axis), (-axis, 0, -cap),
+                     (-axis, 0, cap), (-cap, 0, axis), (cap, 0, axis), (axis, 0, cap), (axis, 0, -cap), (cap, 0, -axis),
+                     (0, -axis, 0), (0, axis, 0), (0, -cap, -axis), (0, -axis, -cap), (0, -axis, cap), (0, -cap, axis),
+                     (0, cap, axis), (0, axis, cap), (0, axis, -cap), (0, cap, -axis), (-axis, -cap, 0), (-cap, -axis, 0),
+                     (cap, -axis, 0), (axis, -cap, 0), (axis, cap, 0), (cap, axis, 0), (-cap, axis, 0), (-axis, cap, 0) ]
+            edges = [(4, 0), (6, 1), (8, 2), (10, 3), (1, 5), (2, 7), (3, 9), (0, 11), (16, 12), (0, 21),
+                     (2, 17), (20, 13), (12, 15), (0, 2), (18, 2), (13, 19), (12, 13), (1, 29), (22, 1), (3, 25),
+                     (13, 27), (14, 0), (26, 3), (28, 13), (24, 12), (12, 23), (3, 1) ]
+        mesh = obj.data
+        mesh.from_pydata(verts, edges, [])
+        mesh.update()
+        return obj
+    else:
+        return None



More information about the Bf-extensions-cvs mailing list