* new metarig type for the durian dragon leg (original rig by Cessen)
authorCampbell Barton <ideasman42@gmail.com>
Mon, 14 Dec 2009 20:56:19 +0000 (20:56 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Mon, 14 Dec 2009 20:56:19 +0000 (20:56 +0000)
* option to roll the delta of the arm rig.
* fix to copy metarig type
* renamed EditBone.align() --> EditBone.align_roll()
* Added EditBone.align_orientation(other)
* Added bone.vector: same as (bone.tail - bone.head)

12 files changed:
release/scripts/modules/bpy_types.py
release/scripts/modules/rigify/arm_biped_generic.py
release/scripts/modules/rigify/copy.py
release/scripts/modules/rigify/leg_biped_generic.py
release/scripts/modules/rigify/leg_quadruped_generic.py [new file with mode: 0644]
release/scripts/modules/rigify/neck_flex.py
release/scripts/modules/rigify/spine_pivot_flex.py
release/scripts/modules/rigify_utils.py
release/scripts/ui/properties_data_bone.py
release/scripts/ui/properties_object_constraint.py
release/test/pep8.py
source/blender/makesrna/intern/rna_armature_api.c

index 239990e2bd5572895409fdb9f4ce065ac9d879a6..69618d77ecbfbb3681ce052bd93a78b80bf69490 100644 (file)
@@ -94,13 +94,17 @@ class _GenericBone:
 
     @property
     def length(self):
-        return (self.head - self.tail).length
+        return self.vector.length
 
     @length.setter
     def length(self, value):
         """The distance from head to tail"""
         self.tail = self.head + ((self.tail - self.head).normalize() * value)
 
+    @property
+    def vector(self):
+        return (self.tail - self.head)
+
     @property
     def children(self):
         return [child for child in self._other_bones if child.parent == self]
@@ -172,6 +176,15 @@ class Bone(StructRNA, _GenericBone):
 class EditBone(StructRNA, _GenericBone):
     __slots__ = ()
 
+    def align_orientation(self, other):
+        '''
+        Align this bone to another by moving its tail and settings its roll
+        the length of the other bone is not used.
+        '''
+        vec = other.vector.normalize() * self.length
+        self.tail = self.head + vec
+        self.roll = other.roll
+
 
 def ord_ind(i1, i2):
     if i1 < i2:
index 1c4c6fd2a6b19ac066ee96e36d847958116793c3..dc45ccf8ae8a317af3df0d941277fbc4f9aefd57 100644 (file)
@@ -19,6 +19,7 @@
 # <pep8 compliant>
 
 import bpy
+from math import radians
 from rigify import RigifyError, get_layer_dict
 from rigify_utils import bone_class_instance, copy_bone_simple, add_pole_target_bone, add_stretch_to, blend_bone_list, get_side_name, get_base_name
 from rna_prop_ui import rna_idprop_ui_prop_get
@@ -213,6 +214,8 @@ def fk(obj, definitions, base_names, options):
     ex.hand_delta = ex.hand_delta_e.name
     ex.hand_delta_e.length *= 0.5
     ex.hand_delta_e.connected = False
+    if "hand_roll" in options:
+        ex.hand_delta_e.roll += radians(options["hand_roll"])
 
     fk_chain.hand_e.connected = False
     fk_chain.hand_e.parent = ex.hand_delta_e
index d052ce6f32bc702869d06f86b5463b6846752eb3..11c16d2d1978948c7bd5a2c3806bdbf3ca3b6941 100644 (file)
@@ -53,25 +53,25 @@ def main(obj, bone_definition, base_names, options):
     cp = bone_class_instance(obj, ["cpy"])
     cp.cpy_e = copy_bone_simple(arm, mt.cpy, base_names[mt.cpy], parent=True)
     cp.cpy = cp.cpy_e.name
-    
+
     bpy.ops.object.mode_set(mode='OBJECT')
 
     cp.update()
     mt.update()
 
     if not cp.cpy_b.connected:
-        con = cp.cpy_p.constraints.new('COPY_LOCATION')
+        con = mt.cpy_p.constraints.new('COPY_LOCATION')
         con.target = obj
-        con.subtarget = mt.cpy
+        con.subtarget = cp.cpy
 
-    con = cp.cpy_p.constraints.new('COPY_ROTATION')
+    con = mt.cpy_p.constraints.new('COPY_ROTATION')
     con.target = obj
     con.subtarget = cp.cpy
 
     con = mt.cpy_p.constraints.new('COPY_SCALE')
     con.target = obj
     con.subtarget = cp.cpy
-    
+
     # Rotation mode and axis locks
     cp.cpy_p.rotation_mode = mt.cpy_p.rotation_mode
     cp.cpy_p.lock_location = tuple(mt.cpy_p.lock_location)
index 2c5481be1b7664cdb816af0448e3027ee7491978..2826a6b7b29d1cd6aa2b8b0a61c74bd852897528 100644 (file)
@@ -128,21 +128,15 @@ def metarig_definition(obj, orig_bone_name):
 def ik(obj, bone_definition, base_names, options):
     arm = obj.data
 
-    # setup the existing bones
+    # setup the existing bones, use names from METARIG_NAMES
     mt_chain = bone_class_instance(obj, ["thigh", "shin", "foot", "toe"])
     mt = bone_class_instance(obj, ["hips", "heel"])
-    # children of ik_foot
-    ik = bone_class_instance(obj, ["foot", "foot_roll", "foot_roll_01", "foot_roll_02", "knee_target"])
 
-    # XXX - duplicate below
-    for bone_class in (mt, mt_chain):
-        for attr in bone_class.attr_names:
-            i = METARIG_NAMES.index(attr)
-            ebone = arm.edit_bones[bone_definition[i]]
-            setattr(bone_class, attr, ebone.name)
-        bone_class.update()
-    # XXX - end dupe
+    mt.attr_initialize(METARIG_NAMES, bone_definition)
+    mt_chain.attr_initialize(METARIG_NAMES, bone_definition)
 
+    # children of ik_foot
+    ik = bone_class_instance(obj, ["foot", "foot_roll", "foot_roll_01", "foot_roll_02", "knee_target"])
 
     # Make a new chain
     ik_chain = mt_chain.copy(to_fmt="MCH-%s", base_names=base_names)
@@ -165,7 +159,7 @@ def ik(obj, bone_definition, base_names, options):
     # foot roll: heel pointing backwards, half length
     ik.foot_roll_e = copy_bone_simple(arm, mt.heel, base_foot_name + "_roll" + get_side_name(base_names[mt_chain.foot]))
     ik.foot_roll = ik.foot_roll_e.name
-    ik.foot_roll_e.tail = ik.foot_roll_e.head + (ik.foot_roll_e.head - ik.foot_roll_e.tail) / 2.0
+    ik.foot_roll_e.tail = ik.foot_roll_e.head + ik.foot_roll_e.vector / 2.0
     ik.foot_roll_e.parent = ik.foot_e # heel is disconnected
 
     # heel pointing forwards to the toe base, parent of the following 2 bones
@@ -208,7 +202,7 @@ def ik(obj, bone_definition, base_names, options):
 
     # roll the bone to point up... could also point in the same direction as ik.foot_roll
     # ik.foot_roll_02_e.matrix * Vector(0.0, 0.0, 1.0) # ACK!, no rest matrix in editmode
-    ik.foot_roll_01_e.align((0.0, 0.0, -1.0))
+    ik.foot_roll_01_e.align_roll((0.0, 0.0, -1.0))
 
     bpy.ops.object.mode_set(mode='OBJECT')
 
@@ -355,7 +349,6 @@ def fk(obj, bone_definition, base_names, options):
     mod.coefficients[1] = -1.0
 
 
-
     # last step setup layers
     layers = get_layer_dict(options)
     lay = layers["fk"]
diff --git a/release/scripts/modules/rigify/leg_quadruped_generic.py b/release/scripts/modules/rigify/leg_quadruped_generic.py
new file mode 100644 (file)
index 0000000..4ad90b9
--- /dev/null
@@ -0,0 +1,225 @@
+# ##### 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import bpy
+from rigify import RigifyError, get_layer_dict
+from rigify_utils import bone_class_instance, copy_bone_simple, blend_bone_list, get_side_name, get_base_name, add_pole_target_bone
+from rna_prop_ui import rna_idprop_ui_prop_get
+from Mathutils import Vector
+
+METARIG_NAMES = "hips", "thigh", "shin", "foot", "toe"
+
+
+def metarig_template():
+    # generated by rigify.write_meta_rig
+    bpy.ops.object.mode_set(mode='EDIT')
+    obj = bpy.context.active_object
+    arm = obj.data
+    bone = arm.edit_bones.new('body')
+    bone.head[:] = -0.3000, -1.0000, 0.0000
+    bone.tail[:] = -0.3000, -1.0000, 1.0000
+    bone.roll = 0.0000
+    bone.connected = False
+    bone = arm.edit_bones.new('thigh')
+    bone.head[:] = 0.0000, 0.0000, -0.0000
+    bone.tail[:] = 0.3351, -0.8690, -1.3903
+    bone.roll = -0.4656
+    bone.connected = False
+    bone.parent = arm.edit_bones['body']
+    bone = arm.edit_bones.new('shin')
+    bone.head[:] = 0.3351, -0.8690, -1.3903
+    bone.tail[:] = 0.2943, -0.0179, -2.4026
+    bone.roll = -0.2024
+    bone.connected = True
+    bone.parent = arm.edit_bones['thigh']
+    bone = arm.edit_bones.new('foot')
+    bone.head[:] = 0.2943, -0.0179, -2.4026
+    bone.tail[:] = 0.3830, -0.1995, -3.1531
+    bone.roll = -0.3766
+    bone.connected = True
+    bone.parent = arm.edit_bones['shin']
+    bone = arm.edit_bones.new('toe')
+    bone.head[:] = 0.3830, -0.1995, -3.1531
+    bone.tail[:] = 0.4724, -0.5126, -3.1531
+    bone.roll = 0.0000
+    bone.connected = True
+    bone.parent = arm.edit_bones['foot']
+
+    bpy.ops.object.mode_set(mode='OBJECT')
+    pbone = obj.pose.bones['thigh']
+    pbone['type'] = 'leg_quadruped_generic'
+
+
+def metarig_definition(obj, orig_bone_name):
+    '''
+    The bone given is the first in a chain
+    Expects a chain of at least 3 children.
+    eg.
+        thigh -> shin -> foot -> [toe, heel]
+    '''
+
+    bone_definition = []
+
+    orig_bone = obj.data.bones[orig_bone_name]
+    orig_bone_parent = orig_bone.parent
+
+    if orig_bone_parent is None:
+        raise RigifyError("expected the thigh bone to have a parent hip bone")
+
+    bone_definition.append(orig_bone_parent.name)
+    bone_definition.append(orig_bone.name)
+
+
+    bone = orig_bone
+    chain = 0
+    while chain < 3: # first 2 bones only have 1 child
+        children = bone.children
+
+        if len(children) != 1:
+            raise RigifyError("expected the thigh bone to have 3 children without a fork")
+        bone = children[0]
+        bone_definition.append(bone.name) # shin, foot
+        chain += 1
+
+    if len(bone_definition) != len(METARIG_NAMES):
+        raise RigifyError("internal problem, expected %d bones" % len(METARIG_NAMES))
+
+    return bone_definition
+
+
+def ik(obj, bone_definition, base_names, options):
+    arm = obj.data
+
+    # setup the existing bones, use names from METARIG_NAMES
+    mt = bone_class_instance(obj, ["hips"])
+    mt_chain = bone_class_instance(obj, ["thigh", "shin", "foot", "toe"])
+
+    mt.attr_initialize(METARIG_NAMES, bone_definition)
+    mt_chain.attr_initialize(METARIG_NAMES, bone_definition)
+
+    ik_chain = mt_chain.copy(to_fmt="%s", base_names=base_names)
+
+    ik_chain.thigh_e.connected = False
+    ik_chain.thigh_e.parent = mt.hips_e
+
+    ik_chain.foot_e.parent = None
+    ik_chain.rename("foot", ik_chain.foot + "_ik")
+
+    # keep the foot_ik as the parent
+    ik_chain.toe_e.connected = False
+
+    # must be after disconnecting the toe
+    ik_chain.foot_e.align_orientation(mt_chain.toe_e)
+
+    # children of ik_foot
+    ik = bone_class_instance(obj, ["foot", "foot_roll", "foot_roll_01", "foot_roll_02", "knee_target", "foot_target"])
+
+    ik.knee_target = add_pole_target_bone(obj, mt_chain.shin, "knee_target") #XXX - pick a better name
+    ik.update()
+    ik.knee_target_e.parent = mt.hips_e
+
+    # foot roll is an interesting one!
+    # plot a vector from the toe bones head, bactwards to the length of the foot
+    # then align it with the foot but reverse direction.
+    ik.foot_roll_e = copy_bone_simple(arm, mt_chain.toe, base_names[mt_chain.foot] + "_roll")
+    ik.foot_roll = ik.foot_roll_e.name
+    ik.foot_roll_e.parent = ik_chain.foot_e
+    ik.foot_roll_e.translate( - (mt_chain.toe_e.vector.normalize() * mt_chain.foot_e.length))
+    ik.foot_roll_e.align_orientation(mt_chain.foot_e)
+    ik.foot_roll_e.tail = ik.foot_roll_e.head - ik.foot_roll_e.vector # flip
+    ik.foot_roll_e.align_roll(mt_chain.foot_e.matrix.rotationPart() * Vector(0.0, 0.0, -1.0))
+
+    # MCH-foot
+    ik.foot_roll_01_e = copy_bone_simple(arm, mt_chain.foot, "MCH-" + base_names[mt_chain.foot])
+    ik.foot_roll_01 = ik.foot_roll_01_e.name
+    ik.foot_roll_01_e.parent = ik_chain.foot_e
+    ik.foot_roll_01_e.head, ik.foot_roll_01_e.tail = mt_chain.foot_e.tail, mt_chain.foot_e.head
+    ik.foot_roll_01_e.roll = ik.foot_roll_e.roll
+
+    # ik_target, child of MCH-foot
+    ik.foot_target_e = copy_bone_simple(arm, mt_chain.foot, base_names[mt_chain.foot] + "_ik_target")
+    ik.foot_target = ik.foot_target_e.name
+    ik.foot_target_e.parent = ik.foot_roll_01_e
+    ik.foot_target_e.align_orientation(ik_chain.foot_e)
+    ik.foot_target_e.length = ik_chain.foot_e.length / 2.0
+    ik.foot_target_e.connected = True
+
+    # MCH-foot.02 child of MCH-foot
+    ik.foot_roll_02_e = copy_bone_simple(arm, mt_chain.foot, "MCH-%s_02" % base_names[mt_chain.foot])
+    ik.foot_roll_02 = ik.foot_roll_02_e.name
+    ik.foot_roll_02_e.parent = ik.foot_roll_01_e
+
+
+    bpy.ops.object.mode_set(mode='OBJECT')
+
+    mt.update()
+    mt_chain.update()
+    ik.update()
+    ik_chain.update()
+
+    # simple constraining of orig bones
+    con = mt_chain.thigh_p.constraints.new('COPY_ROTATION')
+    con.target = obj
+    con.subtarget = ik_chain.thigh
+
+    con = mt_chain.shin_p.constraints.new('COPY_ROTATION')
+    con.target = obj
+    con.subtarget = ik_chain.shin
+
+    con = mt_chain.foot_p.constraints.new('COPY_ROTATION')
+    con.target = obj
+    con.subtarget = ik.foot_roll_02
+
+    con = mt_chain.toe_p.constraints.new('COPY_ROTATION')
+    con.target = obj
+    con.subtarget = ik_chain.toe
+
+    # others...
+    con = ik.foot_roll_01_p.constraints.new('COPY_ROTATION')
+    con.target = obj
+    con.subtarget = ik.foot_roll
+
+
+    # IK
+    con = ik_chain.shin_p.constraints.new('IK')
+    con.chain_length = 2
+    con.iterations = 500
+    con.pole_angle = -90.0 # XXX - in deg!
+    con.use_tail = True
+    con.use_stretch = True
+    con.use_target = True
+    con.use_rotation = False
+    con.weight = 1.0
+
+    con.target = obj
+    con.subtarget = ik.foot_target
+
+    con.pole_target = obj
+    con.pole_subtarget = ik.knee_target
+
+
+    bpy.ops.object.mode_set(mode='EDIT')
+
+    return None, ik_chain.thigh, ik_chain.shin, ik_chain.foot, ik_chain.toe
+
+
+def main(obj, bone_definition, base_names, options):
+    bones_ik = ik(obj, bone_definition, base_names, options)
+    return bones_ik
index 137fb626bcfbc7e1a3c11dede94970fa9dd74265..be548249433d36bdf926a890e6beb76b6597437e 100644 (file)
@@ -167,7 +167,7 @@ def main(obj, bone_definition, base_names, options):
         # dont store parent names, re-reference as each chain bones parent.
         neck_e_parent = arm.edit_bones.new("MCH-rot_%s" % base_names[getattr(mt_chain, attr)])
         neck_e_parent.head = neck_e.head
-        neck_e_parent.tail = neck_e.head + ((mt.head_e.tail - mt.head_e.head).normalize() * neck_chain_segment_length / 2.0)
+        neck_e_parent.tail = neck_e.head + (mt.head_e.vector.normalize() * neck_chain_segment_length / 2.0)
         neck_e_parent.roll = mt.head_e.roll
 
         orig_parent = neck_e.parent
index ca954eeef4f207832a0404b94e5d01a7dda2717c..848f54ef4e8f55adde1b54c1f71b682d7c817926 100644 (file)
@@ -244,7 +244,7 @@ def main(obj, bone_definition, base_names, options):
         # dont store parent names, re-reference as each chain bones parent.
         spine_e_parent = arm.edit_bones.new("MCH-rot_%s" % child_name_orig)
         spine_e_parent.head = spine_e.head
-        spine_e_parent.tail = spine_e.head + ((mt.ribcage_e.tail - mt.ribcage_e.head).normalize() * spine_chain_segment_length / 2.0)
+        spine_e_parent.tail = spine_e.head + (mt.ribcage_e.vector.normalize() * spine_chain_segment_length / 2.0)
         spine_e_parent.roll = mt.ribcage_e.roll
 
 
@@ -508,7 +508,7 @@ def main(obj, bone_definition, base_names, options):
     lay = layers["main"]
     for attr in df.attr_names:
         getattr(df, attr + "_b").layer = lay
-    for attr in rv_chain .attr_names:
+    for attr in rv_chain.attr_names:
         getattr(rv_chain , attr + "_b").layer = lay
 
     # no support for blending chains
index f4694023f12a97b053bd34005ce8c7857b287f13..371792a3633a7e45eb7f9d24e7f8e03d86040bff 100644 (file)
@@ -353,6 +353,7 @@ def bone_class_instance(obj, slots, name="BoneContainer"):
     class_dict = { \
         "obj": obj, \
         "attr_names": attr_names, \
+        "attr_initialize": _bone_class_instance_attr_initialize, \
         "update": _bone_class_instance_update, \
         "rename": _bone_class_instance_rename, \
         "names": _bone_class_instance_names, \
@@ -380,6 +381,16 @@ def auto_class_instance(slots, name="ContainerClass", class_dict=None):
     return auto_class(slots, name, class_dict)()
 
 
+def _bone_class_instance_attr_initialize(self, attr_names, bone_names):
+    ''' Initializes attributes, both lists must be aligned
+    '''
+    for attr in self.attr_names:
+        i = attr_names.index(attr)
+        setattr(self, attr, bone_names[i])
+
+    self.update()
+
+
 def _bone_class_instance_update(self):
     ''' Re-Assigns bones from the blender data
     '''
index 121fc3a5db3293a1e50a3c20018db47a8694ce95..99561a026e3f429c43d2e761e8da50a081c53649 100644 (file)
@@ -226,6 +226,7 @@ class BONE_PT_display(BoneButtonsPanel):
             col.label(text="Custom Shape:")
             col.prop(pchan, "custom_shape", text="")
 
+
 class BONE_PT_inverse_kinematics(BoneButtonsPanel):
     bl_label = "Inverse Kinematics"
     bl_default_closed = True
index dd874bf52a02432ff68d9ca0cc6a5c16e8e11bf0..12a12ff40dc31d77aac5beb33cc8bbe2fec707f1 100644 (file)
@@ -735,6 +735,7 @@ class OBJECT_PT_constraints(ConstraintButtonsPanel):
         for con in ob.constraints:
             self.draw_constraint(context, con)
 
+
 class BONE_PT_constraints(ConstraintButtonsPanel):
     bl_label = "Bone Constraints"
     bl_context = "bone_constraint"
index 0c0c013ad84de7729c78f1f53831fa9a2e2ce10b..68d09c2ee767f58dee47addec979cf1f7d0daf1c 100644 (file)
@@ -29,9 +29,9 @@ import os
 #   sudo pip install pep8
 #
 # in debian install pylint pyflakes pep8 with apt-get/aptitude/etc
-# 
+#
 # on *nix run
-#   python release/test/pep8.py > tmp.err 2>&1
+#   python release/test/pep8.py > pep8_error.txt 2>&1
 
 # how many lines to read into the file, pep8 comment
 # should be directly after the licence header, ~20 in most cases
@@ -67,7 +67,7 @@ def main():
 
         if pep8_type:
             # so we can batch them for each tool.
-            files.append((f, pep8_type))
+            files.append((os.path.abspath(f), pep8_type))
         else:
             if not [None for prefix in SKIP_PREFIX if f.startswith(prefix)]:
                 files_skip.append(f)
index 31bd72754872c952eb508b19ad0cb394b12051b6..22bd73131666a8d8dfcb87ea3a609e37a0948ac1 100644 (file)
@@ -40,7 +40,7 @@
 
 #include "ED_armature.h"
 
-void rna_EditBone_align(EditBone *ebo, float *no)
+void rna_EditBone_align_roll(EditBone *ebo, float *no)
 {
        if(!is_zero_v3(no)) {
                float normal[3];
@@ -57,7 +57,7 @@ void RNA_api_armature_edit_bone(StructRNA *srna)
        FunctionRNA *func;
        PropertyRNA *parm;
 
-       func= RNA_def_function(srna, "align", "rna_EditBone_align");
+       func= RNA_def_function(srna, "align_roll", "rna_EditBone_align_roll");
        RNA_def_function_ui_description(func, "Align the bone to a localspace vector.");
        parm= RNA_def_float_vector(func, "vector", 3, NULL, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX);
        RNA_def_property_flag(parm, PROP_REQUIRED);