From 0e713ba1d01c6bca4052b19f72045415cd6fea70 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 9 Dec 2009 12:00:28 +0000 Subject: [PATCH] - rewrote arm rig so it creates 2 chains and blend them automatically (like the leg) - use reverse order for palm fingers (pointer first) - allow copying bone class instances to exclude some bones - doc generation had a python error (incedently updated online docs linked from the splash) --- release/scripts/modules/rigify/__init__.py | 29 +- release/scripts/modules/rigify/arm.py | 341 ++++++++------------- release/scripts/modules/rigify/leg.py | 2 +- release/scripts/modules/rigify/palm.py | 17 +- source/blender/python/epy_doc_gen.py | 11 +- 5 files changed, 163 insertions(+), 237 deletions(-) diff --git a/release/scripts/modules/rigify/__init__.py b/release/scripts/modules/rigify/__init__.py index a7863d0caf5..09a17dffdd4 100644 --- a/release/scripts/modules/rigify/__init__.py +++ b/release/scripts/modules/rigify/__init__.py @@ -73,19 +73,23 @@ def _bone_class_instance_rename(self, attr, new_name): setattr(self, attr, ebone.name) -def _bone_class_instance_copy(self, from_prefix="", to_prefix=""): +def _bone_class_instance_copy(self, from_fmt="%s", to_fmt="%s", exclude_attrs=(), base_names=None): from_name_ls = [] new_name_ls = [] new_slot_ls = [] for attr in self.attr_names: + + if attr in exclude_attrs: + continue + bone_name_orig = getattr(self, attr) ebone = getattr(self, attr + "_e") # orig_names[attr] = bone_name_orig - # insert prefix - if from_prefix: - bone_name = from_prefix + bone_name_orig + # insert formatting + if from_fmt != "%s": + bone_name = from_fmt % bone_name_orig ebone.name = bone_name bone_name = ebone.name # cant be sure we get what we ask for else: @@ -95,8 +99,9 @@ def _bone_class_instance_copy(self, from_prefix="", to_prefix=""): new_slot_ls.append(attr) from_name_ls.append(bone_name) - bone_name_orig = bone_name_orig.replace("ORG-", "") # XXX - we need a better way to do this - new_name_ls.append(to_prefix + bone_name_orig) + if base_names: + bone_name_orig = base_names[bone_name_orig] + new_name_ls.append(to_fmt % bone_name_orig) new_bones = copy_bone_simple_list(self.obj.data, from_name_ls, new_name_ls, True) new_bc = bone_class_instance(self.obj, new_slot_ls) @@ -134,6 +139,10 @@ def _bone_class_instance_blend(self, from_bc, to_bc, target_bone=None, target_pr def bone_class_instance(obj, slots, name="BoneContainer"): + + if len(slots) != len(set(slots)): + raise Exception("duplicate entries found %s" % attr_names) + attr_names = tuple(slots) # dont modify the original slots = list(slots) # dont modify the original for i in range(len(slots)): @@ -210,6 +219,11 @@ def blend_bone_list(obj, apply_bones, from_bones, to_bones, target_bone=None, ta if obj.mode == 'EDIT': raise Exception("blending cant be called in editmode") + if len(apply_bones) != len(from_bones): + raise Exception("lists differ in length (from -> apply): \n\t%s\n\t%s" % (from_bones, apply_bones)) + if len(apply_bones) != len(to_bones): + raise Exception("lists differ in length (to -> apply): \n\t%s\n\t%s" % (to_bones, apply_bones)) + # setup the blend property if target_bone is None: target_bone = apply_bones[-1] # default to the last bone @@ -319,7 +333,8 @@ def add_stretch_to(obj, from_name, to_name, name): con.volume = 'NO_VOLUME' bpy.ops.object.mode_set(mode=mode_orig) - + + return stretch_name def add_pole_target_bone(obj, base_name, name, mode='CROSS'): ''' diff --git a/release/scripts/modules/rigify/arm.py b/release/scripts/modules/rigify/arm.py index 7408e349dca..0823f8ad331 100644 --- a/release/scripts/modules/rigify/arm.py +++ b/release/scripts/modules/rigify/arm.py @@ -19,13 +19,15 @@ # 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, add_pole_target_bone, add_stretch_to, blend_bone_list from rna_prop_ui import rna_idprop_ui_prop_get +from Mathutils import Vector METARIG_NAMES = "shoulder", "arm", "forearm", "hand" def metarig_template(): + # generated by rigify.write_meta_rig bpy.ops.object.mode_set(mode='EDIT') obj = bpy.context.object arm = obj.data @@ -66,8 +68,11 @@ def metarig_definition(obj, orig_bone_name): mt.shoulder_p = mt.arm_p.parent if not mt.shoulder_p: - raise Exception("could not find 'arm' parent, skipping:", orig_bone_name) - print(mt.shoulder_p) + raise Exception("could not find '%s' parent, skipping:" % orig_bone_name) + + if mt.arm_p.parent.bone.connected: + raise Exception("expected '%s' to be disconnected from its parent" % orig_bone_name) + mt.shoulder = mt.shoulder_p.name # We could have some bones attached, find the bone that has this as its 2nd parent @@ -90,232 +95,125 @@ def metarig_definition(obj, orig_bone_name): return mt.names() -def main(obj, definitions, base_names): - """ - the bone with the 'arm' property is the upper arm, this assumes a chain as follows. - [shoulder, upper_arm, forearm, hand] - ...where this bone is 'upper_arm' - - there are 3 chains - - Original - - IK, MCH-%s_ik - - IKSwitch, MCH-%s () - - - """ - - # Since there are 3 chains, this gets confusing so divide into 3 chains - # Initialize container classes for convenience - mt = bone_class_instance(obj, METARIG_NAMES) # meta +def ik(obj, definitions, base_names): + mt = bone_class_instance(obj, METARIG_NAMES) mt.shoulder, mt.arm, mt.forearm, mt.hand = definitions + mt.update() + + ik = bone_class_instance(obj, ["pole", "pole_vis", "hand_vis"]) + ik_chain = mt.copy(to_fmt="MCH-%s_ik", base_names=base_names, exclude_attrs=["shoulder"]) + + # IK needs no parent_index + ik_chain.hand_e.connected = False + ik_chain.hand_e.parent = None - ik = bone_class_instance(obj, ["arm", "forearm", "pole", "hand"]) # ik - sw = bone_class_instance(obj, ["socket", "shoulder", "arm", "forearm", "hand"]) # hinge - ex = bone_class_instance(obj, ["arm_hinge"]) # hinge & extras + ik_chain.arm_e.connected = False + ik_chain.arm_e.parent = mt.shoulder_e + + # Add the bone used for the arms poll target + ik.pole = add_pole_target_bone(obj, mt.forearm, "elbow_poll", mode='+Z') + + # update bones after this! + ik.hand_vis = add_stretch_to(obj, mt.hand, ik_chain.hand, "VIS-%s_ik" % base_names[mt.hand]) + ik.pole_vis = add_stretch_to(obj, mt.forearm, ik.pole, "VIS-%s_ik" % base_names[mt.forearm]) + + ik.update() + ik.hand_vis_e.restrict_select = True + ik.pole_vis_e.restrict_select = True + + bpy.ops.object.mode_set(mode='OBJECT') + + mt.update() + ik.update() + ik_chain.update() + + con = ik_chain.forearm_p.constraints.new('IK') + con.target = obj + con.subtarget = ik_chain.hand + con.pole_target = obj + con.pole_subtarget = ik.pole + con.use_tail = True + con.use_stretch = True + con.use_target = True + con.use_rotation = False + con.chain_length = 2 + con.pole_angle = -90.0 # XXX, RAD2DEG + + # ID Propery on the hand for IK/FK switch + + prop = rna_idprop_ui_prop_get(ik_chain.hand_p, "ik", create=True) + ik_chain.hand_p["ik"] = 0.5 + prop["soft_min"] = 0.0 + prop["soft_max"] = 1.0 + + bpy.ops.object.mode_set(mode='EDIT') + + # don't blend the shoulder + return [None] + ik_chain.names() + + +def fk(obj, definitions, base_names): + arm = obj.data + + mt = bone_class_instance(obj, METARIG_NAMES) + mt.shoulder, mt.arm, mt.forearm, mt.hand = definitions + mt.update() - def chain_ik(prefix="MCH-%s_ik"): + ex = bone_class_instance(obj, ["socket", "arm_hinge", "hand_delta"]) + fk_chain = mt.copy(base_names=base_names) - mt.update() + # shoulder is used as a hinge + fk_chain.rename("shoulder", "MCH-%s_hinge" % base_names[mt.arm]) + fk_chain.shoulder_e.translate(Vector(0.0, fk_chain.shoulder_e.length / 2, 0.0)) - # Add the edit bones - ik.hand_e = copy_bone_simple(arm, mt.hand, prefix % base_names[mt.hand]) - ik.hand = ik.hand_e.name + # upper arm constrains to this. + ex.socket_e = copy_bone_simple(arm, mt.arm, "MCH-%s_socket" % base_names[mt.arm]) + ex.socket = ex.socket_e.name + ex.socket_e.connected = False + ex.socket_e.parent = mt.shoulder_e + ex.socket_e.tail = mt.shoulder_e.tail + + # insert the 'DLT-hand', between the forearm and the hand + # copies forarm rotation + ex.hand_delta_e = copy_bone_simple(arm, fk_chain.hand, "DLT-%s" % base_names[mt.hand], parent=True) + ex.hand_delta = ex.hand_delta_e.name + ex.hand_delta_e.length *= 0.5 + ex.hand_delta_e.connected = False + + fk_chain.hand_e.connected = False + fk_chain.hand_e.parent = ex.hand_delta_e - ik.arm_e = copy_bone_simple(arm, mt.arm, prefix % base_names[mt.arm]) - ik.arm = ik.arm_e.name - - ik.forearm_e = copy_bone_simple(arm, mt.forearm, prefix % base_names[mt.forearm]) - ik.forearm = ik.forearm_e.name - - ik.arm_e.parent = mt.arm_e.parent - ik.forearm_e.connected = mt.arm_e.connected - - ik.forearm_e.parent = ik.arm_e - ik.forearm_e.connected = True - - - # Add the bone used for the arms poll target - ik.pole = add_pole_target_bone(obj, mt.forearm, "elbow_poll", mode='+Z') - - bpy.ops.object.mode_set(mode='OBJECT') - - ik.update() - - con = ik.forearm_p.constraints.new('IK') - con.target = obj - con.subtarget = ik.hand - con.pole_target = obj - con.pole_subtarget = ik.pole - - con.use_tail = True - con.use_stretch = True - con.use_target = True - con.use_rotation = False - con.chain_length = 2 - con.pole_angle = -90.0 # XXX, RAD2DEG - - # ID Propery on the hand for IK/FK switch - - prop = rna_idprop_ui_prop_get(ik.hand_p, "ik", create=True) - ik.hand_p["ik"] = 0.5 - prop["soft_min"] = 0.0 - prop["soft_max"] = 1.0 - - bpy.ops.object.mode_set(mode='EDIT') - - def chain_switch(prefix="MCH-%s"): - print(mt.obj.mode) - sw.update() - mt.update() - - sw.shoulder_e = copy_bone_simple(arm, mt.shoulder, prefix % base_names[mt.shoulder]) - sw.shoulder = sw.shoulder_e.name - sw.shoulder_e.parent = mt.shoulder_e.parent - sw.shoulder_e.connected = mt.shoulder_e.connected - - sw.arm_e = copy_bone_simple(arm, mt.arm, prefix % base_names[mt.arm]) - sw.arm = sw.arm_e.name - sw.arm_e.parent = sw.shoulder_e - sw.arm_e.connected = arm.edit_bones[mt.shoulder].connected - - sw.forearm_e = copy_bone_simple(arm, mt.forearm, prefix % base_names[mt.forearm]) - sw.forearm = sw.forearm_e.name - sw.forearm_e.parent = sw.arm_e - sw.forearm_e.connected = arm.edit_bones[mt.forearm].connected - - sw.hand_e = copy_bone_simple(arm, mt.hand, prefix % base_names[mt.hand]) - sw.hand = sw.hand_e.name - sw.hand_e.parent = sw.forearm_e - sw.hand_e.connected = arm.edit_bones[mt.hand].connected - - # The sw.hand_e needs to own all the children on the metarig's hand - for child in mt.hand_e.children: - child.parent = sw.hand_e - - - # These are made the children of sw.shoulder_e - - - bpy.ops.object.mode_set(mode='OBJECT') - - # Add constraints - sw.update() - - #dummy, ik.arm, ik.forearm, ik.hand, ik.pole = ik_chain_tuple - - ik_driver_path = obj.pose.bones[ik.hand].path_to_id() + '["ik"]' - - def ik_fk_driver(con): - ''' - 3 bones use this for ik/fk switching - ''' - fcurve = con.driver_add("influence", 0) - driver = fcurve.driver - tar = driver.targets.new() - driver.type = 'AVERAGE' - tar.name = "ik" - tar.id_type = 'OBJECT' - tar.id = obj - tar.rna_path = ik_driver_path - - # *********** - con = sw.arm_p.constraints.new('COPY_ROTATION') - con.name = "FK" - con.target = obj - con.subtarget = mt.arm - - con = sw.arm_p.constraints.new('COPY_ROTATION') - - con.target = obj - con.subtarget = ik.arm - con.influence = 0.5 - ik_fk_driver(con) - - # *********** - con = sw.forearm_p.constraints.new('COPY_ROTATION') - con.name = "FK" - con.target = obj - con.subtarget = mt.forearm - - con = sw.forearm_p.constraints.new('COPY_ROTATION') - con.name = "IK" - con.target = obj - con.subtarget = ik.forearm - con.influence = 0.5 - ik_fk_driver(con) - - # *********** - con = sw.hand_p.constraints.new('COPY_ROTATION') - con.name = "FK" - con.target = obj - con.subtarget = mt.hand - - con = sw.hand_p.constraints.new('COPY_ROTATION') - con.name = "IK" - con.target = obj - con.subtarget = ik.hand - con.influence = 0.5 - ik_fk_driver(con) - - - add_stretch_to(obj, sw.forearm, ik.pole, "VIS-elbow_ik_poll") - add_stretch_to(obj, sw.hand, ik.hand, "VIS-hand_ik") - - bpy.ops.object.mode_set(mode='EDIT') - - def chain_shoulder(prefix="MCH-%s"): - - sw.socket_e = copy_bone_simple(arm, mt.arm, (prefix % base_names[mt.arm]) + "_socket") - sw.socket = sw.socket_e.name - sw.socket_e.tail = arm.edit_bones[mt.shoulder].tail - - - # Set the shoulder as parent - ik.update() - sw.update() - mt.update() - - sw.socket_e.parent = sw.shoulder_e - ik.arm_e.parent = sw.shoulder_e - - - # ***** add the shoulder hinge - # yes this is correct, the shoulder copy gets the arm's name - ex.arm_hinge_e = copy_bone_simple(arm, mt.shoulder, (prefix % base_names[mt.arm]) + "_hinge") - ex.arm_hinge = ex.arm_hinge_e.name - offset = ex.arm_hinge_e.length / 2.0 - - ex.arm_hinge_e.head.y += offset - ex.arm_hinge_e.tail.y += offset - - # Note: meta arm becomes child of hinge - mt.arm_e.parent = ex.arm_hinge_e - - - bpy.ops.object.mode_set(mode='OBJECT') - - ex.update() - - con = mt.arm_p.constraints.new('COPY_LOCATION') - con.target = obj - con.subtarget = sw.socket + bpy.ops.object.mode_set(mode='OBJECT') + + mt.update() + ex.update() + fk_chain.update() + con = fk_chain.arm_p.constraints.new('COPY_LOCATION') + con.target = obj + con.subtarget = ex.socket + + fk_chain.hand_p.lock_location = True, True, True + con = ex.hand_delta_p.constraints.new('COPY_ROTATION') + con.target = obj + con.subtarget = fk_chain.forearm + def hinge_setup(): # Hinge constraint & driver - con = ex.arm_hinge_p.constraints.new('COPY_ROTATION') + con = fk_chain.shoulder_p.constraints.new('COPY_ROTATION') con.name = "hinge" con.target = obj - con.subtarget = sw.shoulder + con.subtarget = mt.shoulder driver_fcurve = con.driver_add("influence", 0) driver = driver_fcurve.driver - controller_path = mt.arm_p.path_to_id() + controller_path = fk_chain.arm_p.path_to_id() # add custom prop - mt.arm_p["hinge"] = 0.0 - prop = rna_idprop_ui_prop_get(mt.arm_p, "hinge", create=True) + fk_chain.arm_p["hinge"] = 0.0 + prop = rna_idprop_ui_prop_get(fk_chain.arm_p, "hinge", create=True) prop["soft_min"] = 0.0 prop["soft_max"] = 1.0 @@ -330,16 +228,21 @@ def main(obj, definitions, base_names): tar.id = obj tar.rna_path = controller_path + '["hinge"]' + mod = driver_fcurve.modifiers[0] + mod.poly_order = 1 + mod.coefficients[0] = 1.0 + mod.coefficients[1] = -1.0 - bpy.ops.object.mode_set(mode='EDIT') + hinge_setup() + + bpy.ops.object.mode_set(mode='EDIT') - # remove the shoulder and re-parent + return None, fk_chain.arm, fk_chain.forearm, fk_chain.hand - chain_ik() - chain_switch() - chain_shoulder() - # Shoulder with its delta and hinge. +def main(obj, bone_definition, base_names): + bones_ik = ik(obj, bone_definition, base_names) + bones_fk = fk(obj, bone_definition, base_names) - # TODO - return a list for fk and IK - return None + bpy.ops.object.mode_set(mode='OBJECT') + blend_bone_list(obj, bone_definition, bones_ik, bones_fk) diff --git a/release/scripts/modules/rigify/leg.py b/release/scripts/modules/rigify/leg.py index 499c0b4b6fa..f38b27c63de 100644 --- a/release/scripts/modules/rigify/leg.py +++ b/release/scripts/modules/rigify/leg.py @@ -146,7 +146,7 @@ def ik(obj, bone_definition, base_names): # Make a new chain, ORG are the original bones renamed. - ik_chain = mt_chain.copy(to_prefix="MCH-") + ik_chain = mt_chain.copy(to_fmt="MCH-%s") # simple rename ik_chain.rename("thigh", ik_chain.thigh + "_ik") diff --git a/release/scripts/modules/rigify/palm.py b/release/scripts/modules/rigify/palm.py index a0b86007974..5f4ada6128d 100644 --- a/release/scripts/modules/rigify/palm.py +++ b/release/scripts/modules/rigify/palm.py @@ -41,31 +41,31 @@ def metarig_template(): bone.roll = -3.1396 bone.connected = False bone.parent = arm.edit_bones['hand'] - bone = arm.edit_bones.new('palm.04') + bone = arm.edit_bones.new('palm.02') bone.head[:] = 0.5000, -0.0000, 0.0000 bone.tail[:] = 0.6433, 1.2444, -0.1299 bone.roll = -3.1357 bone.connected = False bone.parent = arm.edit_bones['hand'] - bone = arm.edit_bones.new('palm.05') + bone = arm.edit_bones.new('palm.01') bone.head[:] = 1.0000, 0.0000, 0.0000 bone.tail[:] = 1.3961, 1.0084, -0.1299 bone.roll = -3.1190 bone.connected = False bone.parent = arm.edit_bones['hand'] - bone = arm.edit_bones.new('palm.02') + bone = arm.edit_bones.new('palm.04') bone.head[:] = -0.5000, 0.0000, -0.0000 bone.tail[:] = -0.5674, 1.2022, -0.1299 bone.roll = 3.1386 bone.connected = False bone.parent = arm.edit_bones['hand'] - bone = arm.edit_bones.new('palm.01') + bone = arm.edit_bones.new('palm.05') bone.head[:] = -1.0000, 0.0000, -0.0000 bone.tail[:] = -1.3286, 1.0590, -0.1299 bone.roll = 3.1239 bone.connected = False bone.parent = arm.edit_bones['hand'] - bone = arm.edit_bones.new('palm.06') + bone = arm.edit_bones.new('thumb') bone.head[:] = 1.3536, -0.2941, 0.0000 bone.tail[:] = 2.1109, 0.4807, -0.1299 bone.roll = -3.0929 @@ -73,16 +73,16 @@ def metarig_template(): bone.parent = arm.edit_bones['hand'] bpy.ops.object.mode_set(mode='OBJECT') - pbone = obj.pose.bones['palm.05'] + pbone = obj.pose.bones['palm.01'] pbone['type'] = 'palm' def metarig_definition(obj, orig_bone_name): ''' The bone given is the first in an array of siblings with a matching basename - sorted with the little finger lowest. + sorted with pointer first, little finger last. eg. - [pinky, ring... etc] + [pointer, middle, ring, pinky... ] # any number of fingers ''' arm = obj.data @@ -91,6 +91,7 @@ def metarig_definition(obj, orig_bone_name): palm_base = palm_bone.basename bone_definition = [bone.name for bone in palm_parent.children if bone.basename == palm_base] bone_definition.sort() + bone_definition.reverse() return [palm_parent.name] + bone_definition diff --git a/source/blender/python/epy_doc_gen.py b/source/blender/python/epy_doc_gen.py index f16c7504cb2..8783cec93ab 100644 --- a/source/blender/python/epy_doc_gen.py +++ b/source/blender/python/epy_doc_gen.py @@ -691,8 +691,15 @@ def op2epy(BASEPATH): operators = dir(op_mod) for op in sorted(operators): # rna = getattr(bpy.types, op).bl_rna - rna = getattr(op_mod, op).get_rna() - write_func(rna, '', out, 'OPERATOR') + try: + rna = getattr(op_mod, op).get_rna() + except AttributeError: + rna = None + except TypeError: + rna = None + + if rna: + write_func(rna, '', out, 'OPERATOR') out.write('\n') out.close()