[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [24843] trunk/blender/release/scripts/ modules: rig-generation from metadata, the idea is to input a simple rig with metadata matching preset definitions
Campbell Barton
ideasman42 at gmail.com
Tue Nov 24 01:02:45 CET 2009
Revision: 24843
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=24843
Author: campbellbarton
Date: 2009-11-24 01:02:21 +0100 (Tue, 24 Nov 2009)
Log Message:
-----------
rig-generation from metadata, the idea is to input a simple rig with metadata matching preset definitions
these are applied by adding constraints, drivers, control bones etc. making it possible to re-apply changes & improvements to many rigs at once.
testcase makes a finger rig (like in BBB) from 3 bones, the base tagged with an id property "type":"finger".
still missing is a way to update the driver dep's
also fixed an error in the property UI when the active bone is not on the active layer.
Modified Paths:
--------------
trunk/blender/release/scripts/modules/rna_prop_ui.py
Added Paths:
-----------
trunk/blender/release/scripts/modules/rigify.py
Added: trunk/blender/release/scripts/modules/rigify.py
===================================================================
--- trunk/blender/release/scripts/modules/rigify.py (rev 0)
+++ trunk/blender/release/scripts/modules/rigify.py 2009-11-24 00:02:21 UTC (rev 24843)
@@ -0,0 +1,237 @@
+# ##### 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 #####
+
+import bpy
+from functools import reduce
+
+# TODO, have these in a more general module
+from rna_prop_ui import rna_idprop_ui_get, rna_idprop_ui_prop_get
+
+
+empty_layer = [False] * 16
+
+
+def gen_none(obj, orig_bone_name):
+ pass
+
+def get_bone_data(obj, bone_name):
+ arm = obj.data
+ pbone = obj.pose.bones[bone_name]
+ if obj.mode == 'EDIT':
+ bone = arm.edit_bones[bone_name]
+ else:
+ bone = arm.bones[bone_name]
+
+ return obj, arm, pbone, bone
+
+def bone_basename(name):
+ return name.split(".")[0]
+
+def add_bone(arm, name):
+ '''Must be in editmode'''
+ bpy.ops.armature.bone_primitive_add(name=name)
+ return arm.edit_bones[-1]
+
+def gen_finger(obj, orig_bone_name):
+
+ # *** EDITMODE
+
+ # get assosiated data
+ obj, arm, orig_pbone, orig_ebone = get_bone_data(obj, orig_bone_name)
+
+ obj.animation_data_create() # needed if its a new armature with no keys
+
+ arm.layer[0] = arm.layer[8] = True
+
+ children = orig_pbone.children_recursive
+ tot_len = reduce(lambda f, pbone: f + pbone.bone.length, children, orig_pbone.bone.length)
+
+ base_name = bone_basename(orig_pbone.name)
+
+ # first make a new bone at the location of the finger
+ control_ebone = add_bone(arm, base_name)
+ control_bone_name = control_ebone.name # we dont know if we get the name requested
+
+ # Place the finger bone
+ head = orig_ebone.head.copy()
+ tail = orig_ebone.tail.copy()
+
+ control_ebone.head = head
+ control_ebone.tail = head + ((tail - head).normalize() * tot_len)
+ control_ebone.roll = orig_ebone.roll
+
+ # now add bones inbetween this and its children recursively
+
+ # switching modes so store names only!
+ children = [pbone.name for pbone in children]
+
+ # set an alternate layer for driver bones
+ other_layer = empty_layer[:]
+ other_layer[8] = True
+
+
+ driver_bone_pairs = []
+
+ for child_bone_name in children:
+ obj, arm, pbone_child, child_ebone = get_bone_data(obj, child_bone_name)
+
+ # finger.02 --> finger_driver.02
+ driver_bone_name = child_bone_name.split('.')
+ driver_bone_name = driver_bone_name[0] + "_driver." + ".".join(driver_bone_name[1:])
+
+ driver_ebone = add_bone(arm, driver_bone_name)
+ driver_bone_name = driver_ebone.name # cant be too sure!
+ driver_ebone.layer = other_layer
+
+ new_len = pbone_child.bone.length / 2.0
+
+ head = child_ebone.head.copy()
+ tail = child_ebone.tail.copy()
+
+ driver_ebone.head = head
+ driver_ebone.tail = head + ((tail - head).normalize() * new_len)
+ driver_ebone.roll = child_ebone.roll
+
+ # Insert driver_ebone in the chain without connected parents
+ driver_ebone.connected = False
+ driver_ebone.parent = child_ebone.parent
+
+ child_ebone.connected = False
+ child_ebone.parent = driver_ebone
+
+ # Add the drivers to these when in posemode.
+ driver_bone_pairs.append((child_bone_name, driver_bone_name))
+
+ del control_ebone
+
+
+ # *** POSEMODE
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+
+ obj, arm, orig_pbone, orig_bone = get_bone_data(obj, orig_bone_name)
+ obj, arm, control_pbone, control_bone= get_bone_data(obj, control_bone_name)
+
+
+ # only allow Y scale
+ control_pbone.lock_scale = (True, False, True)
+
+ control_pbone["bend_ratio"]= 0.4
+ prop = rna_idprop_ui_prop_get(control_pbone, "bend_ratio", create=True)
+ prop["min"] = 0.0
+ prop["max"] = 1.0
+
+ con = orig_pbone.constraints.new('COPY_LOCATION')
+ con.target = obj
+ con.subtarget = control_bone_name
+
+ con = orig_pbone.constraints.new('COPY_ROTATION')
+ con.target = obj
+ con.subtarget = control_bone_name
+
+
+
+ # setup child drivers on each new smaller bone added. assume 2 for now.
+
+ # drives the bones
+ controller_path = control_pbone.path_to_id() # 'pose.bones["%s"]' % control_bone_name
+
+ i = 0
+ for child_bone_name, driver_bone_name in driver_bone_pairs:
+
+ # XXX - todo, any number
+ if i==2:
+ break
+
+ obj, arm, driver_pbone, driver_bone = get_bone_data(obj, driver_bone_name)
+
+ driver_pbone.rotation_mode = 'YZX'
+ driver_pbone.driver_add("rotation_euler", 0)
+
+ #obj.driver_add('pose.bones["%s"].scale', 1)
+ fcurve_driver = obj.animation_data.drivers[-1] # XXX, WATCH THIS
+ driver = fcurve_driver.driver
+
+ # scale target
+ tar = driver.targets.new()
+ tar.name = "scale"
+ tar.id_type = 'OBJECT'
+ tar.id = obj
+ tar.array_index = 1 # Y scale
+ tar.rna_path = controller_path + '.scale'
+
+ # bend target
+ tar = driver.targets.new()
+ tar.name = "br"
+ tar.id_type = 'OBJECT'
+ tar.id = obj
+ tar.rna_path = controller_path + '["bend_ratio"]'
+
+ # XXX - todo, any number
+ if i==0:
+ driver.expression = '(-scale+1.0)*pi*2.0*(1.0-br)'
+ elif i==1:
+ driver.expression = '(-scale+1.0)*pi*2.0*br'
+
+ obj, arm, child_pbone, child_bone = get_bone_data(obj, child_bone_name)
+
+ # only allow X rotation
+ driver_pbone.lock_rotation = child_pbone.lock_rotation = (False, True, True)
+
+ i += 1
+
+
+gen_table = {
+ "":gen_none, \
+ "finger":gen_finger, \
+}
+
+def generate_rig(context, ob):
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+
+ # copy object and data
+ ob.selected = False
+ ob_new = ob.copy()
+ ob_new.data = ob.data.copy()
+ scene = context.scene
+ scene.objects.link(ob_new)
+ scene.objects.active = ob_new
+ ob_new.selected = True
+
+ # enter armature editmode
+
+
+ for pbone_name in ob_new.pose.bones.keys():
+ bone_type = ob_new.pose.bones[pbone_name].get("type", "")
+
+ try:
+ func = gen_table[bone_type]
+ except KeyError:
+ print("\tunknown type '%s', bone '%s'" % (bone_type, pbone_name))
+
+
+ # Toggle editmode so the pose data is always up to date
+ bpy.ops.object.mode_set(mode='EDIT')
+ func(ob_new, pbone_name)
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+
+if __name__ == "__main__":
+ generate_rig(bpy.context, bpy.context.object)
Modified: trunk/blender/release/scripts/modules/rna_prop_ui.py
===================================================================
--- trunk/blender/release/scripts/modules/rna_prop_ui.py 2009-11-23 23:17:23 UTC (rev 24842)
+++ trunk/blender/release/scripts/modules/rna_prop_ui.py 2009-11-24 00:02:21 UTC (rev 24843)
@@ -69,6 +69,10 @@
pass
rna_item = eval("context." + context_member)
+
+ # poll should really get this...
+ if not rna_item:
+ return
items = rna_item.items()
items.sort()
More information about the Bf-blender-cvs
mailing list