[Bf-extensions-cvs] [efd3869] rigify_fixes: Pitchipoy FK/IK switch implemented

Lucio Rossi noreply at git.blender.org
Fri Jul 29 13:27:29 CEST 2016


Commit: efd386991e12320590ae9943496d4a90961f132f
Author: Lucio Rossi
Date:   Thu Jul 28 18:32:36 2016 +0200
Branches: rigify_fixes
https://developer.blender.org/rBAefd386991e12320590ae9943496d4a90961f132f

Pitchipoy FK/IK switch implemented

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

M	rigify/generate.py
A	rigify/rig_ui_pitchipoy_template.py
M	rigify/rigs/pitchipoy/limbs/ui.py

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

diff --git a/rigify/generate.py b/rigify/generate.py
index 4fb83f5..0536377 100644
--- a/rigify/generate.py
+++ b/rigify/generate.py
@@ -32,6 +32,8 @@ from .utils import create_root_widget
 from .utils import random_id
 from .utils import copy_attributes
 from .rig_ui_template import UI_SLIDERS, layers_ui, UI_REGISTER
+from .rig_ui_pitchipoy_template import UI_P_SLIDERS, layers_P_ui, UI_P_REGISTER
+
 
 RIG_MODULE = "rigs"
 ORG_LAYER = [n == 31 for n in range(0, 32)]  # Armature layer that original bones should be moved to.
@@ -385,18 +387,35 @@ def generate_rig(context, metarig):
         print( l.name )
         layer_layout += [(l.name, l.row)]
 
-    # Generate the UI script
-    if "rig_ui.py" in bpy.data.texts:
-        script = bpy.data.texts["rig_ui.py"]
-        script.clear()
+
+    if isPitchipoy(metarig):
+
+        # Generate the UI Pitchipoy script
+        if "rig_ui.py" in bpy.data.texts:
+            script = bpy.data.texts["rig_ui.py"]
+            script.clear()
+        else:
+            script = bpy.data.texts.new("rig_ui.py")
+        script.write(UI_P_SLIDERS % rig_id)
+        for s in ui_scripts:
+            script.write("\n        " + s.replace("\n", "\n        ") + "\n")
+        script.write(layers_P_ui(vis_layers, layer_layout))
+        script.write(UI_P_REGISTER)
+        script.use_module = True
+
     else:
-        script = bpy.data.texts.new("rig_ui.py")
-    script.write(UI_SLIDERS % rig_id)
-    for s in ui_scripts:
-        script.write("\n        " + s.replace("\n", "\n        ") + "\n")
-    script.write(layers_ui(vis_layers, layer_layout))
-    script.write(UI_REGISTER)
-    script.use_module = True
+        # Generate the UI script
+        if "rig_ui.py" in bpy.data.texts:
+            script = bpy.data.texts["rig_ui.py"]
+            script.clear()
+        else:
+            script = bpy.data.texts.new("rig_ui.py")
+        script.write(UI_SLIDERS % rig_id)
+        for s in ui_scripts:
+            script.write("\n        " + s.replace("\n", "\n        ") + "\n")
+        script.write(layers_ui(vis_layers, layer_layout))
+        script.write(UI_REGISTER)
+        script.use_module = True
 
     # Run UI script
     exec(script.as_string(), {})
@@ -451,3 +470,13 @@ def param_name(param_name, rig_type):
     """ Get the actual parameter name, sans-rig-type.
     """
     return param_name[len(rig_type) + 1:]
+
+def isPitchipoy(metarig):
+    """ Returns True if metarig is type pitchipoy.
+    """
+    pbones=metarig.pose.bones
+    for pb in pbones:
+        words = pb.rigify_type.partition('.')
+        if  words[0] == 'pitchipoy':
+            return True
+    return False
\ No newline at end of file
diff --git a/rigify/rig_ui_pitchipoy_template.py b/rigify/rig_ui_pitchipoy_template.py
new file mode 100644
index 0000000..da3bda7
--- /dev/null
+++ b/rigify/rig_ui_pitchipoy_template.py
@@ -0,0 +1,717 @@
+#====================== BEGIN GPL LICENSE BLOCK ======================
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#======================= END GPL LICENSE BLOCK ========================
+
+# <pep8 compliant>
+
+UI_P_SLIDERS = '''
+import bpy
+from mathutils import Matrix, Vector
+from math import acos, pi, radians
+
+rig_id = "%s"
+
+
+############################
+## Math utility functions ##
+############################
+
+def perpendicular_vector(v):
+    """ Returns a vector that is perpendicular to the one given.
+        The returned vector is _not_ guaranteed to be normalized.
+    """
+    # Create a vector that is not aligned with v.
+    # It doesn't matter what vector.  Just any vector
+    # that's guaranteed to not be pointing in the same
+    # direction.
+    if abs(v[0]) < abs(v[1]):
+        tv = Vector((1,0,0))
+    else:
+        tv = Vector((0,1,0))
+
+    # Use cross prouct to generate a vector perpendicular to
+    # both tv and (more importantly) v.
+    return v.cross(tv)
+
+
+def rotation_difference(mat1, mat2):
+    """ Returns the shortest-path rotational difference between two
+        matrices.
+    """
+    q1 = mat1.to_quaternion()
+    q2 = mat2.to_quaternion()
+    angle = acos(min(1,max(-1,q1.dot(q2)))) * 2
+    if angle > pi:
+        angle = -angle + (2*pi)
+    return angle
+
+def tail_distance(angle,bone_ik,bone_fk):
+    """ Returns the distance between the tails of two bones
+        after rotating bone_ik in AXIS_ANGLE mode.
+    """
+    rot_mod=bone_ik.rotation_mode
+    if rot_mod != 'AXIS_ANGLE':
+        bone_ik.rotation_mode = 'AXIS_ANGLE'
+    bone_ik.rotation_axis_angle[0] = angle
+    bpy.context.scene.update()
+
+    dv = (bone_fk.tail - bone_ik.tail).length
+
+    bone_ik.rotation_mode = rot_mod
+    return dv
+
+def find_min_range(bone_ik,bone_fk,f=tail_distance,delta=pi/8):
+    """ finds the range where lies the minimum of function f applied on bone_ik and bone_fk
+        at a certain angle.
+    """
+    rot_mod=bone_ik.rotation_mode
+    if rot_mod != 'AXIS_ANGLE':
+        bone_ik.rotation_mode = 'AXIS_ANGLE'
+
+    start_angle = bone_ik.rotation_axis_angle[0]
+    angle = start_angle
+    while (angle > (start_angle - 2*pi)) and (angle < (start_angle + 2*pi)):
+        l_dist = f(angle-delta,bone_ik,bone_fk)
+        c_dist = f(angle,bone_ik,bone_fk)
+        r_dist = f(angle+delta,bone_ik,bone_fk)
+        if min((l_dist,c_dist,r_dist)) == c_dist:
+            bone_ik.rotation_mode = rot_mod
+            return (angle-delta,angle+delta)
+        else:
+            angle=angle+delta
+
+def ternarySearch(f, left, right, bone_ik, bone_fk, absolutePrecision):
+    """
+    Find minimum of unimodal function f() within [left, right]
+    To find the maximum, revert the if/else statement or revert the comparison.
+    """
+    while True:
+        #left and right are the current bounds; the maximum is between them
+        if abs(right - left) < absolutePrecision:
+            return (left + right)/2
+
+        leftThird = left + (right - left)/3
+        rightThird = right - (right - left)/3
+
+        if f(leftThird, bone_ik, bone_fk) > f(rightThird, bone_ik, bone_fk):
+            left = leftThird
+        else:
+            right = rightThird
+
+#########################################
+## "Visual Transform" helper functions ##
+#########################################
+
+def get_pose_matrix_in_other_space(mat, pose_bone):
+    """ Returns the transform matrix relative to pose_bone's current
+        transform space.  In other words, presuming that mat is in
+        armature space, slapping the returned matrix onto pose_bone
+        should give it the armature-space transforms of mat.
+        TODO: try to handle cases with axis-scaled parents better.
+    """
+    rest = pose_bone.bone.matrix_local.copy()
+    rest_inv = rest.inverted()
+    if pose_bone.parent:
+        par_mat = pose_bone.parent.matrix.copy()
+        par_inv = par_mat.inverted()
+        par_rest = pose_bone.parent.bone.matrix_local.copy()
+    else:
+        par_mat = Matrix()
+        par_inv = Matrix()
+        par_rest = Matrix()
+
+    # Get matrix in bone's current transform space
+    smat = rest_inv * (par_rest * (par_inv * mat))
+
+    # Compensate for non-local location
+    #if not pose_bone.bone.use_local_location:
+    #    loc = smat.to_translation() * (par_rest.inverted() * rest).to_quaternion()
+    #    smat.translation = loc
+
+    return smat
+
+
+def get_local_pose_matrix(pose_bone):
+    """ Returns the local transform matrix of the given pose bone.
+    """
+    return get_pose_matrix_in_other_space(pose_bone.matrix, pose_bone)
+
+
+def set_pose_translation(pose_bone, mat):
+    """ Sets the pose bone's translation to the same translation as the given matrix.
+        Matrix should be given in bone's local space.
+    """
+    if pose_bone.bone.use_local_location == True:
+        pose_bone.location = mat.to_translation()
+    else:
+        loc = mat.to_translation()
+
+        rest = pose_bone.bone.matrix_local.copy()
+        if pose_bone.bone.parent:
+            par_rest = pose_bone.bone.parent.matrix_local.copy()
+        else:
+            par_rest = Matrix()
+
+        q = (par_rest.inverted() * rest).to_quaternion()
+        pose_bone.location = q * loc
+
+
+def set_pose_rotation(pose_bone, mat):
+    """ Sets the pose bone's rotation to the same rotation as the given matrix.
+        Matrix should be given in bone's local space.
+    """
+    q = mat.to_quaternion()
+
+    if pose_bone.rotation_mode == 'QUATERNION':
+        pose_bone.rotation_quaternion = q
+    elif pose_bone.rotation_mode == 'AXIS_ANGLE':
+        pose_bone.rotation_axis_angle[0] = q.angle
+        pose_bone.rotation_axis_angle[1] = q.axis[0]
+        pose_bone.rotation_axis_angle[2] = q.axis[1]
+        pose_bone.rotation_axis_angle[3] = q.axis[2]
+    else:
+        pose_bone.rotation_euler = q.to_euler(pose_bone.rotation_mode)
+
+
+def set_pose_scale(pose_bone, mat):
+    """ Sets the pose bone's scale to the same scale as the given matrix.
+        Matrix should be given in bone's local space.
+    """
+    pose_bone.scale = mat.to_scale()
+
+
+def match_pose_translation(pose_bone, target_bone):
+    """ Matches pose_bone's visual translation to target_bone's visual
+        translation.
+        This function assumes you are in pose mode on the relevant armature.
+    """
+    mat = get_pose_matrix_in_other_space(target_bone.matrix, pose_bone)
+    set_pose_translation(pose_bone, mat)
+    bpy.ops.object.mode_set(mode='OBJECT')
+    bpy.ops.object.mode_set(mode='POSE')
+
+
+def mat

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-extensions-cvs mailing list