[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [25139] trunk/blender/release/scripts/ modules/rigify: split up metarig hierarchy evaluation and modifying the metarig into 2 steps ,
Campbell Barton
ideasman42 at gmail.com
Sat Dec 5 20:26:28 CET 2009
Revision: 25139
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=25139
Author: campbellbarton
Date: 2009-12-05 20:26:28 +0100 (Sat, 05 Dec 2009)
Log Message:
-----------
split up metarig hierarchy evaluation and modifying the metarig into 2 steps,
original bone names cant be changed anymore but this means the bones can be re-parented without confusing scripts that run after the rig is modified.
support for defining a bone to have multiple types and automatically blending between 2 generated rigs
Modified Paths:
--------------
trunk/blender/release/scripts/modules/rigify/__init__.py
trunk/blender/release/scripts/modules/rigify/arm.py
trunk/blender/release/scripts/modules/rigify/delta.py
trunk/blender/release/scripts/modules/rigify/finger.py
trunk/blender/release/scripts/modules/rigify/leg.py
trunk/blender/release/scripts/modules/rigify/neck.py
trunk/blender/release/scripts/modules/rigify/palm.py
trunk/blender/release/scripts/modules/rigify/spine.py
Modified: trunk/blender/release/scripts/modules/rigify/__init__.py
===================================================================
--- trunk/blender/release/scripts/modules/rigify/__init__.py 2009-12-05 19:05:21 UTC (rev 25138)
+++ trunk/blender/release/scripts/modules/rigify/__init__.py 2009-12-05 19:26:28 UTC (rev 25139)
@@ -91,6 +91,7 @@
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)
new_bones = copy_bone_simple_list(self.obj.data, from_name_ls, new_name_ls, True)
@@ -103,8 +104,10 @@
return new_bc
+def _bone_class_instance_names(self):
+ return [getattr(self, attr) for attr in self.attr_names]
-def _bone_class_instance_blend(self, from_bc, to_bc, target_bone=None, target_prop="blend", use_loc=True, use_rot=True):
+def _bone_class_instance_blend(self, from_bc, to_bc, target_bone=None, target_prop="blend"):
'''
Use for blending bone chains.
@@ -113,78 +116,19 @@
XXX - toggles editmode, need to re-validate all editbones :(
'''
+
if self.attr_names != from_bc.attr_names or self.attr_names != to_bc.attr_names:
raise Exception("can only blend between matching chains")
-
- obj = self.obj
- if obj.mode == 'EDIT':
- raise Exception("blending cant be called in editmode")
+ apply_bones = [getattr(self, attr) for attr in self.attr_names]
+ from_bones = [getattr(from_bc, attr) for attr in from_bc.attr_names]
+ to_bones = [getattr(to_bc, attr) for attr in to_bc.attr_names]
- # setup the blend property
- if target_bone is None:
- target_bone = self.attr_names[-1]
+ blend_bone_list(self.obj, apply_bones, from_bones, to_bones, target_bone, target_prop)
- prop_pbone = obj.pose.bones[target_bone]
- if prop_pbone.get(target_bone, None) is None:
- prop = rna_idprop_ui_prop_get(prop_pbone, target_prop, create=True)
- prop_pbone[target_prop] = 0.5
- prop["soft_min"] = 0.0
- prop["soft_max"] = 1.0
-
- driver_path = prop_pbone.path_to_id() + ('["%s"]' % target_prop)
-
- def blend_target(driver):
- tar = driver.targets.new()
- tar.name = target_bone
- tar.id_type = 'OBJECT'
- tar.id = obj
- tar.rna_path = driver_path
-
- for attr in self.attr_names:
- new_pbone = getattr(self, attr + "_p")
- from_bone_name = getattr(from_bc, attr)
- to_bone_name = getattr(to_bc, attr)
-
- if from_bone_name == to_bone_name:
- raise Exception("Matching from/to bone names:" + from_bone_name)
-
- if use_loc:
- con = new_pbone.constraints.new('COPY_LOCATION')
- con.target = obj
- con.subtarget = from_bone_name
-
- con = new_pbone.constraints.new('COPY_LOCATION')
- con.target = obj
- con.subtarget = to_bone_name
-
- fcurve = con.driver_add("influence", 0)
- driver = fcurve.driver
- driver.type = 'AVERAGE'
- fcurve.modifiers.remove(0) # grr dont need a modifier
-
- blend_target(driver)
-
- if use_rot:
- con = new_pbone.constraints.new('COPY_ROTATION')
- con.target = obj
- con.subtarget = from_bone_name
-
- con = new_pbone.constraints.new('COPY_ROTATION')
- con.target = obj
- con.subtarget = to_bone_name
-
- fcurve = con.driver_add("influence", 0)
- driver = fcurve.driver
- driver.type = 'AVERAGE'
- fcurve.modifiers.remove(0) # grr dont need a modifier
-
- blend_target(driver)
-
-
def bone_class_instance(obj, slots, name="BoneContainer"):
attr_names = tuple(slots) # dont modify the original
- slots = slots[:] # dont modify the original
+ slots = list(slots) # dont modify the original
for i in range(len(slots)):
member = slots[i]
slots.append(member + "_b") # bone bone
@@ -196,6 +140,7 @@
"attr_names":attr_names, \
"update":_bone_class_instance_update, \
"rename":_bone_class_instance_rename, \
+ "names":_bone_class_instance_names, \
"copy":_bone_class_instance_copy, \
"blend":_bone_class_instance_blend, \
}
@@ -254,7 +199,79 @@
return copy_bones
+def blend_bone_list(obj, apply_bones, from_bones, to_bones, target_bone=None, target_prop="blend"):
+
+ if obj.mode == 'EDIT':
+ raise Exception("blending cant be called in editmode")
+
+ # setup the blend property
+ if target_bone is None:
+ target_bone = apply_bones[-1] # default to the last bone
+ prop_pbone = obj.pose.bones[target_bone]
+ if prop_pbone.get(target_bone, None) is None:
+ prop = rna_idprop_ui_prop_get(prop_pbone, target_prop, create=True)
+ prop_pbone[target_prop] = 0.5
+ prop["soft_min"] = 0.0
+ prop["soft_max"] = 1.0
+
+ driver_path = prop_pbone.path_to_id() + ('["%s"]' % target_prop)
+
+ def blend_target(driver):
+ tar = driver.targets.new()
+ tar.name = target_bone
+ tar.id_type = 'OBJECT'
+ tar.id = obj
+ tar.rna_path = driver_path
+
+ def blend_location(new_pbone, from_bone_name, to_bone_name):
+ con = new_pbone.constraints.new('COPY_LOCATION')
+ con.target = obj
+ con.subtarget = from_bone_name
+
+ con = new_pbone.constraints.new('COPY_LOCATION')
+ con.target = obj
+ con.subtarget = to_bone_name
+
+ fcurve = con.driver_add("influence", 0)
+ driver = fcurve.driver
+ driver.type = 'AVERAGE'
+ fcurve.modifiers.remove(0) # grr dont need a modifier
+
+ blend_target(driver)
+
+ def blend_rotation(new_pbone, from_bone_name, to_bone_name):
+ con = new_pbone.constraints.new('COPY_ROTATION')
+ con.target = obj
+ con.subtarget = from_bone_name
+
+ con = new_pbone.constraints.new('COPY_ROTATION')
+ con.target = obj
+ con.subtarget = to_bone_name
+
+ fcurve = con.driver_add("influence", 0)
+ driver = fcurve.driver
+ driver.type = 'AVERAGE'
+ fcurve.modifiers.remove(0) # grr dont need a modifier
+
+ blend_target(driver)
+
+ for i, new_bone_name in enumerate(apply_bones):
+ from_bone_name = from_bones[i]
+ to_bone_name = to_bones[i]
+
+ # allow skipping some bones by having None in the list
+ if None in (new_bone_name, from_bone_name, to_bone_name):
+ continue
+
+ new_pbone = obj.pose.bones[new_bone_name]
+
+ if not new_pbone.bone.connected:
+ blend_location(new_pbone, from_bone_name, to_bone_name)
+
+ blend_rotation(new_pbone, from_bone_name, to_bone_name)
+
+
def add_stretch_to(obj, from_name, to_name, name):
'''
Adds a bone that stretches from one to another
@@ -342,8 +359,9 @@
return poll_name
-def generate_rig(context, ob):
-
+def generate_rig(context, obj_orig, prefix="ORG-"):
+ from collections import OrderedDict
+
global_undo = context.user_preferences.edit.global_undo
context.user_preferences.edit.global_undo = False
@@ -351,50 +369,118 @@
# copy object and data
- ob.selected = False
- ob_new = ob.copy()
- ob_new.data = ob.data.copy()
+ obj_orig.selected = False
+ obj = obj_orig.copy()
+ obj.data = obj_orig.data.copy()
scene = context.scene
- scene.objects.link(ob_new)
- scene.objects.active = ob_new
- ob_new.selected = True
+ scene.objects.link(obj)
+ scene.objects.active = obj
+ obj.selected = True
- # enter armature editmode
+ arm = obj.data
- # Only reference bones that have a type, means we can rename any others without lookup errors
- pose_names = [pbone.name for pbone in ob_new.pose.bones if "type" in pbone]
+ # original name mapping
+ base_names = {}
- #for pbone_name in ob_new.pose.bones.keys():
- for pbone_name in pose_names:
+ bpy.ops.object.mode_set(mode='EDIT')
+ for bone in arm.edit_bones:
+ bone_name = bone.name
+ bone.name = prefix + bone_name
+ base_names[bone.name] = bone_name # new -> old mapping
+ bpy.ops.object.mode_set(mode='OBJECT')
- bone_type = ob_new.pose.bones[pbone_name].get("type", "")
+ # key: bone name
+ # value: {type:definition, ...}
+ # where type is the submodule name - leg, arm etc
+ # and definition is a list of bone names
+ bone_definitions = {}
+
+ # key: bone name
+ # value: [functions, ...]
+ # each function is from the module. eg leg.ik, arm.main
+ bone_typeinfos = {}
+
+ # inspect all bones and assign their definitions before modifying
+ for pbone in obj.pose.bones:
+ bone_name = pbone.name
+ bone_type = obj.pose.bones[bone_name].get("type", "")
+ bone_type_list = [bt for bt in bone_type.replace(",", " ").split()]
- if bone_type == "":
- continue
+ for bone_type in bone_type_list:
+ type_pair = bone_type.split(".")
+
+ # 'leg.ik' will look for an ik function in the leg module
+ # 'leg' will look up leg.main
+ if len(type_pair) == 1:
+ type_pair = type_pair[0], "main"
+
+ submod_name, func_name = type_pair
+
+ # from rigify import leg
+ submod = __import__(name="%s.%s" % (__package__, submod_name), fromlist=[submod_name])
+ reload(submod)
+
+ bone_def_dict = bone_definitions.setdefault(bone_name, {})
- # submodule = getattr(self, bone_type)
- # exec("from rigify import %s as submodule")
- submodule = __import__(name="%s.%s" % (__package__, bone_type), fromlist=[bone_type])
+ # Only calculate bone definitions once
+ if submod_name not in bone_def_dict:
+ metarig_definition_func = getattr(submod, "metarig_definition")
+ bone_def_dict[submod_name] = metarig_definition_func(obj, bone_name)
+
+
+ bone_typeinfo = bone_typeinfos.setdefault(bone_name, [])
+ type_func = getattr(submod, func_name)
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list