split up metarig hierarchy evaluation and modifying the metarig into 2 steps,
[blender.git] / release / scripts / modules / rigify / leg.py
index 54dc76dafcfbc63acf7011bdd51db45a3ce15c89..589e295101c3862761c043f8b95a45d5d198aef1 100644 (file)
 # ##### END GPL LICENSE BLOCK #####
 
 import bpy
-from rigify import bone_class_instance, copy_bone_simple, add_pole_target_bone, add_stretch_to
+from rigify import bone_class_instance, copy_bone_simple, copy_bone_simple_list, add_pole_target_bone, add_stretch_to
 from rna_prop_ui import rna_idprop_ui_get, rna_idprop_ui_prop_get
 
+METARIG_NAMES = "hips", "thigh", "shin", "foot", "toe", "heel"
+
 def metarig_template():
     # generated by rigify.write_meta_rig
     bpy.ops.object.mode_set(mode='EDIT')
@@ -65,37 +67,60 @@ def metarig_template():
     pbone = obj.pose.bones['thigh']
     pbone['type'] = 'leg'
 
-
-def validate(obj, orig_bone_name):
+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 Exception("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
+    while chain < 2: # first 2 bones only have 1 child
         children = bone.children
+
         if len(children) != 1:
-            return "expected the thigh bone to have 3 children without a fork"
+            raise Exception("expected the thigh bone to have 3 children without a fork")
         bone = children[0]
+        bone_definition.append(bone.name) # shin, foot
         chain += 1
         
     children = bone.children
     # Now there must be 2 children, only one connected
     if len(children) != 2:
-        return "expected the foot to have 2 children"
+        raise Exception("expected the foot to have 2 children")
 
     if children[0].connected == children[1].connected:
-        return "expected one bone to be connected"
+        raise Exception("expected one bone to be connected")
     
-    return ''
+    toe, heel = children
+    if heel.connected:
+        toe, heel = heel, toe
+    
+    
+    bone_definition.append(toe.name)
+    bone_definition.append(heel.name)
+    
+    if len(bone_definition) != len(METARIG_NAMES):
+        raise Exception("internal problem, expected %d bones" % len(METARIG_NAMES))
+    
+    return bone_definition
 
 
-def main(obj, orig_bone_name):
+def ik(obj, bone_definition, base_names):
     from Mathutils import Vector
     arm = obj.data
     
@@ -107,55 +132,26 @@ def main(obj, orig_bone_name):
     # children of ik_foot
     ik = bone_class_instance(obj, ["foot", "foot_roll", "foot_roll_01", "foot_roll_02", "knee_target"])
     
-    mt_chain.thigh_e = arm.edit_bones[orig_bone_name]
-    mt_chain.thigh = orig_bone_name
-    
-    mt.hips_e = mt_chain.thigh_e.parent
-    mt.hips_e.name = "ORG-" + mt.hips_e.name
-    mt.hips = mt.hips_e.name
-    
-    mt_chain.shin_e = mt_chain.thigh_e.children[0]
-    mt_chain.shin = mt_chain.shin_e.name
-    
-    mt_chain.foot_e = mt_chain.shin_e.children[0]
-    mt_chain.foot = mt_chain.foot_e.name
-    
-    mt_chain.toe_e, mt.heel_e = mt_chain.foot_e.children
-
-    # We dont know which is which, but know the heel is disconnected
-    if not mt_chain.toe_e.connected:
-        mt_chain.toe_e, mt.heel_e = mt.heel_e, mt_chain.toe_e
-    mt.heel_e.name = "ORG-" + mt.heel_e.name
-    mt_chain.toe, mt.heel = mt_chain.toe_e.name, mt.heel_e.name
-
-    ex.thigh_socket_e = copy_bone_simple(arm, mt_chain.thigh, "MCH-%s_socket" % mt_chain.thigh, parent=True)
-    ex.thigh_socket = ex.thigh_socket_e.name
-    ex.thigh_socket_e.tail = ex.thigh_socket_e.head + Vector(0.0, 0.0, ex.thigh_socket_e.length / 4.0)
-
-    ex.thigh_hinge_e = copy_bone_simple(arm, mt_chain.thigh, "MCH-%s_hinge" % mt_chain.thigh, parent=True)
-    ex.thigh_hinge = ex.thigh_hinge_e.name
-    ex.thigh_hinge_e.tail = ex.thigh_hinge_e.head + Vector(0.0, 0.0, mt_chain.thigh_e.head.length)
-    ex.thigh_hinge_e.translate(Vector(-(mt.hips_e.head.x - mt_chain.thigh_e.head.x), 0.0, 0.0))
-    ex.thigh_hinge_e.length = mt.hips_e.length
-    
+    # 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
 
 
     # Make a new chain, ORG are the original bones renamed.
-    fk_chain = mt_chain.copy(from_prefix="ORG-") # fk has no prefix!
-    ik_chain = fk_chain.copy(to_prefix="MCH-")
-    
-    fk_chain.thigh_e.connected = False
-    fk_chain.thigh_e.parent = ex.thigh_hinge_e
-
-    # fk_chain.thigh_socket_e.parent = MCH-leg_hinge
+    ik_chain = mt_chain.copy(to_prefix="MCH-")
 
     # simple rename
     ik_chain.rename("thigh", ik_chain.thigh + "_ik")
     ik_chain.rename("shin", ik_chain.shin + "_ik")
 
     # ik foot, no parents
-    base_foot_name = fk_chain.foot # whatever the foot is called, use that!
-    ik.foot_e = copy_bone_simple(arm, fk_chain.foot, "%s_ik" % base_foot_name)
+    base_foot_name = base_names[mt_chain.foot] # whatever the foot is called, use that!, XXX - ORG!
+    ik.foot_e = copy_bone_simple(arm, mt_chain.foot, "%s_ik" % base_foot_name)
     ik.foot = ik.foot_e.name
     ik.foot_e.tail.z = ik.foot_e.head.z
     ik.foot_e.roll = 0.0
@@ -183,7 +179,7 @@ def main(obj, orig_bone_name):
     
     # rename 'MCH-toe' --> to 'toe_ik' and make the child of ik.foot_roll_01
     # ------------------ FK or IK?
-    ik_chain.rename("toe", fk_chain.toe + "_ik") # only fk for the basename
+    ik_chain.rename("toe", base_names[mt_chain.toe] + "_ik")
     ik_chain.toe_e.connected = False
     ik_chain.toe_e.parent = ik.foot_roll_01_e
     
@@ -213,43 +209,6 @@ def main(obj, orig_bone_name):
     ex.update()
     mt_chain.update()
     ik_chain.update()
-    fk_chain.update()
-
-    con = fk_chain.thigh_p.constraints.new('COPY_LOCATION')
-    con.target = obj
-    con.subtarget = ex.thigh_socket
-
-    # hinge
-    prop = rna_idprop_ui_prop_get(fk_chain.thigh_p, "hinge", create=True)
-    fk_chain.thigh_p["hinge"] = 0.5
-    prop["soft_min"] = 0.0
-    prop["soft_max"] = 1.0
-    
-    con = ex.thigh_hinge_p.constraints.new('COPY_ROTATION')
-    con.target = obj
-    con.subtarget = mt.hips
-    
-    # add driver
-    hinge_driver_path = fk_chain.thigh_p.path_to_id() + '["hinge"]'
-    
-    fcurve = con.driver_add("influence", 0)
-    driver = fcurve.driver
-    tar = driver.targets.new()
-    driver.type = 'AVERAGE'
-    tar.name = "var"
-    tar.id_type = 'OBJECT'
-    tar.id = obj
-    tar.rna_path = hinge_driver_path
-
-    mod = fcurve.modifiers[0]
-    mod.poly_order = 1
-    mod.coefficients[0] = 1.0
-    mod.coefficients[1] = -1.0
-    
-    
-    # adds constraints to the original bones.
-    mt_chain.blend(fk_chain, ik_chain, target_bone=ik.foot, target_prop="ik", use_loc=False)
-    
     
     # IK
     con = ik_chain.shin_p.constraints.new('IK')
@@ -290,3 +249,79 @@ def main(obj, orig_bone_name):
         else:
             con.minimum_x = -180.0 # XXX -deg
             con.maximum_x = 0.0
+
+    return None, ik_chain.thigh, ik_chain.shin, ik_chain.foot, ik_chain.toe, None
+
+
+def fk(obj, bone_definition, base_names):
+    from Mathutils import Vector
+    arm = obj.data
+    
+    # these account for all bones in METARIG_NAMES
+    mt_chain = bone_class_instance(obj, ["thigh", "shin", "foot", "toe"])
+    mt = bone_class_instance(obj, ["hips", "heel"])
+    
+    # new bones
+    ex = bone_class_instance(obj, ["thigh_socket", "thigh_hinge"])
+    
+    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()
+
+    ex.thigh_socket_e = copy_bone_simple(arm, mt_chain.thigh, "MCH-%s_socket" % base_names[mt_chain.thigh], parent=True)
+    ex.thigh_socket = ex.thigh_socket_e.name
+    ex.thigh_socket_e.tail = ex.thigh_socket_e.head + Vector(0.0, 0.0, ex.thigh_socket_e.length / 4.0)
+
+    ex.thigh_hinge_e = copy_bone_simple(arm, mt_chain.thigh, "MCH-%s_hinge" % base_names[mt_chain.thigh], parent=True)
+    ex.thigh_hinge = ex.thigh_hinge_e.name
+    ex.thigh_hinge_e.tail = ex.thigh_hinge_e.head + Vector(0.0, 0.0, mt_chain.thigh_e.head.length)
+    ex.thigh_hinge_e.translate(Vector(-(mt.hips_e.head.x - mt_chain.thigh_e.head.x), 0.0, 0.0))
+    ex.thigh_hinge_e.length = mt.hips_e.length
+    
+    fk_chain = mt_chain.copy() # fk has no prefix!
+    
+    fk_chain.thigh_e.connected = False
+    fk_chain.thigh_e.parent = ex.thigh_hinge_e
+
+    bpy.ops.object.mode_set(mode='OBJECT')
+
+    ex.update()
+    mt_chain.update()
+    fk_chain.update()
+
+    con = fk_chain.thigh_p.constraints.new('COPY_LOCATION')
+    con.target = obj
+    con.subtarget = ex.thigh_socket
+
+    # hinge
+    prop = rna_idprop_ui_prop_get(fk_chain.thigh_p, "hinge", create=True)
+    fk_chain.thigh_p["hinge"] = 0.5
+    prop["soft_min"] = 0.0
+    prop["soft_max"] = 1.0
+    
+    con = ex.thigh_hinge_p.constraints.new('COPY_ROTATION')
+    con.target = obj
+    con.subtarget = mt.hips
+    
+    # add driver
+    hinge_driver_path = fk_chain.thigh_p.path_to_id() + '["hinge"]'
+    
+    fcurve = con.driver_add("influence", 0)
+    driver = fcurve.driver
+    tar = driver.targets.new()
+    driver.type = 'AVERAGE'
+    tar.name = "var"
+    tar.id_type = 'OBJECT'
+    tar.id = obj
+    tar.rna_path = hinge_driver_path
+
+    mod = fcurve.modifiers[0]
+    mod.poly_order = 1
+    mod.coefficients[0] = 1.0
+    mod.coefficients[1] = -1.0
+    
+    # dont blend the hips or heel
+    return None, fk_chain.thigh, fk_chain.shin, fk_chain.foot, fk_chain.toe, None