patch from Cessen, update to metarigs and some changes to the rigging main loop.

- property names dont need the bone type prefix anymore
- always add a root bone that all non parented bones are parented to
- x/y/z axis properties for bones.
This commit is contained in:
Campbell Barton 2010-01-10 18:53:15 +00:00
parent c8966e5373
commit 57e96e4472
11 changed files with 186 additions and 93 deletions

@ -19,6 +19,7 @@
# <pep8 compliant>
from _bpy import types as bpy_types
from Mathutils import Vector
StructRNA = bpy_types.Struct.__bases__[0]
# StructRNA = bpy_types.Struct
@ -89,6 +90,24 @@ class _GenericBone:
return 0
@property
def x_axis(self):
""" Vector pointing down the x-axis of the bone.
"""
return self.matrix.rotationPart() * Vector(1,0,0)
@property
def y_axis(self):
""" Vector pointing down the x-axis of the bone.
"""
return self.matrix.rotationPart() * Vector(0,1,0)
@property
def z_axis(self):
""" Vector pointing down the x-axis of the bone.
"""
return self.matrix.rotationPart() * Vector(0,0,1)
@property
def basename(self):
"""The name of this bone before any '.' character"""

@ -29,7 +29,13 @@ LAYER_TYPES = "main", "extra", "ik", "fk"
ORG_LAYERS = [n==31 for n in range(0,32)]
MCH_LAYERS = [n==30 for n in range(0,32)]
DEF_LAYERS = [n==29 for n in range(0,32)]
ROOT_LAYERS = [n==28 for n in range(0,32)]
ORG_PREFIX = "ORG-"
MCH_PREFIX = "MCH-"
DEF_PREFIX = "DEF-"
WGT_PREFIX = "WGT-"
@ -79,11 +85,15 @@ def get_bone_type_options(pbone, type_name):
options = {}
bone_name = pbone.name
for key, value in pbone.items():
key_pair = key.split(".")
key_pair = key.rsplit(".")
# get all bone properties
""""
if key_pair[0] == type_name:
if len(key_pair) != 2:
raise RigifyError("option error for bone '%s', property name was not a pair '%s'" % (bone_name, key_pair))
options[key_pair[1]] = value
"""
options[key] = value
return options
@ -174,18 +184,22 @@ def generate_rig(context, obj_orig, prefix="ORG-", META_DEF=True):
arm = obj.data
# original name mapping
# prepend the ORG prefix to the bones, and create the base_names mapping
base_names = {}
# add all new parentless children to this bone
root_bone = None
bpy.ops.object.mode_set(mode='EDIT')
for bone in arm.edit_bones:
bone_name = bone.name
if obj.pose.bones[bone_name].get("type", "") != "root":
bone.name = prefix + bone_name
base_names[bone.name] = bone_name # new -> old mapping
bone.name = ORG_PREFIX + bone_name
base_names[bone.name] = bone_name
# create root_bone
bpy.ops.object.mode_set(mode='EDIT')
edit_bone = obj.data.edit_bones.new("root")
root_bone = edit_bone.name
edit_bone.head = (0.0, 0.0, 0.0)
edit_bone.tail = (0.0, 1.0, 0.0)
edit_bone.roll = 0.0
edit_bone.layer = ROOT_LAYERS
bpy.ops.object.mode_set(mode='OBJECT')
# key: bone name
@ -218,12 +232,6 @@ def generate_rig(context, obj_orig, prefix="ORG-", META_DEF=True):
else:
bone_type_list = []
if bone_type_list == ["root"]: # special case!
if root_bone:
raise RigifyError("cant have more then 1 root bone, found '%s' and '%s' to have type==root" % (root_bone, bone_name))
root_bone = bone_name
bone_type_list[:] = []
for bone_type in bone_type_list:
type_name, submod, type_func = submodule_func_from_type(bone_type)
reload(submod)
@ -292,9 +300,11 @@ def generate_rig(context, obj_orig, prefix="ORG-", META_DEF=True):
# need a reverse lookup on bone_genesis so as to know immediately
# where a bone comes from
bone_genesis_reverse = {}
'''
for bone_name, bone_children in bone_genesis.items():
for bone_child_name in bone_children:
bone_genesis_reverse[bone_child_name] = bone_name
'''
if root_bone:
@ -304,6 +314,9 @@ def generate_rig(context, obj_orig, prefix="ORG-", META_DEF=True):
root_ebone = arm.edit_bones[root_bone]
for ebone in arm.edit_bones:
bone_name = ebone.name
if ebone.parent is None:
ebone.parent = root_ebone
'''
if ebone.parent is None and bone_name not in base_names:
# check for override
bone_creator = bone_genesis_reverse[bone_name]
@ -317,6 +330,7 @@ def generate_rig(context, obj_orig, prefix="ORG-", META_DEF=True):
ebone.connected = False
ebone.parent = root_ebone_tmp
'''
bpy.ops.object.mode_set(mode='OBJECT')
@ -348,18 +362,22 @@ def generate_rig(context, obj_orig, prefix="ORG-", META_DEF=True):
for bone_name, bone in arm.bones.items():
bone.deform = False # Non DEF bones shouldn't deform
if bone_name.startswith(prefix):
if bone_name.startswith(ORG_PREFIX):
bone.layer = ORG_LAYERS
elif bone_name.startswith("MCH-"): # XXX fixme
elif bone_name.startswith(MCH_PREFIX): # XXX fixme
bone.layer = MCH_LAYERS
elif bone_name.startswith("DEF-"): # XXX fixme
elif bone_name.startswith(DEF_PREFIX): # XXX fixme
bone.layer = DEF_LAYERS
bone.deform = True
else:
# Assign bone appearance if there is a widget for it
obj.pose.bones[bone_name].custom_shape = context.scene.objects.get(WGT_PREFIX+bone_name)
layer_tot[:] = [max(lay) for lay in zip(layer_tot, bone.layer)]
# Only for demo'ing
arm.layer = layer_tot
layer_show = [a and not (b or c or d) for a,b,c,d in zip(layer_tot, ORG_LAYERS, MCH_LAYERS, DEF_LAYERS)]
arm.layer = layer_show
# obj.restrict_view = True

@ -20,7 +20,7 @@
import bpy
from math import radians
from rigify import RigifyError, get_layer_dict
from rigify import RigifyError, get_layer_dict, ORG_PREFIX
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
from Mathutils import Vector
@ -126,7 +126,7 @@ def ik(obj, definitions, base_names, options):
if elbow_parent_name:
try:
elbow_parent_e = arm.edit_bones[elbow_parent_name]
elbow_parent_e = arm.edit_bones[ORG_PREFIX + elbow_parent_name]
except:
# TODO, old/new parent mapping
raise RigifyError("parent bone from property 'arm_biped_generic.elbow_parent' not found '%s'" % elbow_parent_name)
@ -165,13 +165,14 @@ def ik(obj, definitions, base_names, options):
con.pole_angle = -90.0 # XXX, RAD2DEG
# last step setup layers
layers = get_layer_dict(options)
lay = layers["ik"]
for attr in ik_chain.attr_names:
getattr(ik_chain, attr + "_b").layer = lay
for attr in ik.attr_names:
getattr(ik, attr + "_b").layer = lay
if "ik_layer" in options:
layer = [n==options["ik_layer"] for n in range(0,32)]
else:
layer = list(mt.arm_b.layer)
ik_chain.hand_b.layer = layer
ik.hand_vis_b.layer = layer
ik.pole_b.layer = layer
ik.pole_vis_b.layer = layer
bpy.ops.object.mode_set(mode='EDIT')
# don't blend the shoulder
@ -200,9 +201,9 @@ def fk(obj, definitions, base_names, options):
ex.socket_e.parent = mt.shoulder_e
ex.socket_e.length *= 0.5
# insert the 'DLT-hand', between the forearm and the hand
# insert the 'MCH-delta_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_e = copy_bone_simple(arm, fk_chain.hand, "MCH-delta_%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
@ -267,17 +268,14 @@ def fk(obj, definitions, base_names, options):
hinge_setup()
# last step setup layers
layers = get_layer_dict(options)
lay = layers["fk"]
for attr in fk_chain.attr_names:
getattr(fk_chain, attr + "_b").layer = lay
lay = layers["extra"]
for attr in ex.attr_names:
getattr(ex, attr + "_b").layer = lay
if "fk_layer" in options:
layer = [n==options["fk_layer"] for n in range(0,32)]
else:
layer = list(mt.arm_b.layer)
fk_chain.arm_b.layer = layer
fk_chain.forearm_b.layer = layer
fk_chain.hand_b.layer = layer
bpy.ops.object.mode_set(mode='EDIT')
return None, fk_chain.arm, fk_chain.forearm, fk_chain.hand
@ -378,4 +376,3 @@ def main(obj, bone_definition, base_names, options):
bpy.ops.object.mode_set(mode='OBJECT')
blend_bone_list(obj, bone_definition, bones_fk, bones_ik, target_bone=bones_ik[3], target_prop="ik", blend_default=0.0)

@ -69,10 +69,12 @@ def deform(obj, definitions, base_names, options):
return (bone_name,)
def main(obj, bone_definition, base_names, options):
def control(obj, definitions, base_names, options):
bpy.ops.object.mode_set(mode='EDIT')
arm = obj.data
mt = bone_class_instance(obj, METARIG_NAMES)
mt.cpy = bone_definition[0]
mt.cpy = definitions[0]
mt.update()
cp = bone_class_instance(obj, ["cpy"])
cp.cpy_e = copy_bone_simple(arm, mt.cpy, base_names[mt.cpy], parent=True)
@ -96,12 +98,17 @@ def main(obj, bone_definition, base_names, options):
cp.cpy_p.lock_rotation_w = mt.cpy_p.lock_rotation_w
cp.cpy_p.lock_scale = tuple(mt.cpy_p.lock_scale)
# Create deform bone
deform_bone = deform(obj, bone_definition, base_names, options)[0]
# setup layers last
layers = get_layer_dict(options)
cp.cpy_b.layer = layers["main"]
# Layers
cp.cpy_b.layer = list(mt.cpy_b.layer)
return (mt.cpy,)
def main(obj, bone_definition, base_names, options):
# Create control bone
cpy = control(obj, bone_definition, base_names, options)[0]
# Create deform bone
deform(obj, bone_definition, base_names, options)
return (cpy,)

@ -209,6 +209,8 @@ def main(obj, bone_definition, base_names, options):
orig_pbone = obj.pose.bones[bone_definition[0]]
control_pbone = obj.pose.bones[control_bone_name]
control_bbone = arm.bones[control_bone_name]
control_pbone.rotation_mode = obj.pose.bones[bone_definition[0]].rotation_mode
# only allow Y scale
@ -279,13 +281,15 @@ def main(obj, bone_definition, base_names, options):
# last step setup layers
layers = get_layer_dict(options)
lay = layers["extra"]
if "ex_layer" in options:
layer = [n==options["ex_layer"] for n in range(0,32)]
else:
layer = list(arm.bones[bone_definition[0]].layer)
for child_bone_name, driver_bone_name in driver_bone_pairs:
arm.bones[driver_bone_name].layer = lay
arm.bones[driver_bone_name].layer = layer
lay = layers["main"]
arm.bones[control_bone_name].layer = lay
layer = list(arm.bones[bone_definition[0]].layer)
control_bbone.layer = layer
# no blending the result of this
return None

@ -150,16 +150,15 @@ def ik(obj, bone_definition, base_names, options):
# ik foot: no parents
base_foot_name = get_base_name(base_names[mt_chain.foot])
ik.foot_e = copy_bone_simple(arm, mt_chain.foot, base_foot_name + "_ik" + get_side_name(base_names[mt_chain.foot]))
ik.foot_e = copy_bone_simple(arm, mt.heel, base_foot_name + "_ik" + get_side_name(base_names[mt_chain.foot]))
ik.foot = ik.foot_e.name
ik.foot_e.tail.z = ik.foot_e.head.z
ik.foot_e.roll = 0.0
ik.foot_e.translate(mt_chain.foot_e.head - ik.foot_e.head)
ik.foot_e.local_location = False
# 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.vector / 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
@ -189,7 +188,7 @@ def ik(obj, bone_definition, base_names, options):
# knee target is the heel moved up and forward on its local axis
ik.knee_target_e = copy_bone_simple(arm, mt.heel, "knee_target")
ik.knee_target_e = copy_bone_simple(arm, mt.heel, "knee_target" + get_side_name(mt.heel))
ik.knee_target = ik.knee_target_e.name
offset = ik.knee_target_e.tail - ik.knee_target_e.head
offset.z = 0
@ -262,12 +261,14 @@ def ik(obj, bone_definition, base_names, options):
# last step setup layers
layers = get_layer_dict(options)
lay = layers["ik"]
if "ik_layer" in options:
layer = [n==options["ik_layer"] for n in range(0,32)]
else:
layer = list(mt_chain.thigh_b.layer)
for attr in ik_chain.attr_names:
getattr(ik_chain, attr + "_b").layer = lay
getattr(ik_chain, attr + "_b").layer = layer
for attr in ik.attr_names:
getattr(ik, attr + "_b").layer = lay
getattr(ik, attr + "_b").layer = layer
bpy.ops.object.mode_set(mode='EDIT')
@ -300,6 +301,17 @@ def fk(obj, bone_definition, base_names, options):
ex.thigh_hinge = ex.thigh_hinge_e.name
fk_chain = mt_chain.copy(base_names=base_names) # fk has no prefix!
fk_chain.foot_e.name = "MCH-" + fk_chain.foot
fk_chain.foot = fk_chain.foot_e.name
# Set up fk foot control
foot_e = copy_bone_simple(arm, mt.heel, base_names[mt_chain.foot])
foot = foot_e.name
foot_e.translate(mt_chain.foot_e.head - foot_e.head)
foot_e.parent = fk_chain.shin_e
foot_e.connected = fk_chain.foot_e.connected
fk_chain.foot_e.connected = False
fk_chain.foot_e.parent = foot_e
fk_chain.thigh_e.connected = False
fk_chain.thigh_e.parent = ex.thigh_hinge_e
@ -309,11 +321,12 @@ def fk(obj, bone_definition, base_names, options):
ex.update()
mt_chain.update()
fk_chain.update()
foot_p = obj.pose.bones[foot]
# Set rotation modes and axis locks
fk_chain.shin_p.rotation_mode = 'XYZ'
fk_chain.shin_p.lock_rotation = False, True, True
fk_chain.foot_p.rotation_mode = 'YXZ'
foot_p.rotation_mode = 'YXZ'
fk_chain.toe_p.rotation_mode = 'YXZ'
fk_chain.toe_p.lock_rotation = False, True, True
@ -350,14 +363,15 @@ def fk(obj, bone_definition, base_names, options):
# last step setup layers
layers = get_layer_dict(options)
lay = layers["fk"]
if "fk_layer" in options:
layer = [n==options["fk_layer"] for n in range(0,32)]
else:
layer = list(mt_chain.thigh_b.layer)
for attr in fk_chain.attr_names:
getattr(fk_chain, attr + "_b").layer = lay
lay = layers["extra"]
getattr(fk_chain, attr + "_b").layer = layer
for attr in ex.attr_names:
getattr(ex, attr + "_b").layer = lay
getattr(ex, attr + "_b").layer = layer
arm.bones[foot].layer = layer
bpy.ops.object.mode_set(mode='EDIT')

@ -20,7 +20,7 @@
import bpy
from rigify import RigifyError
from rigify_utils import bone_class_instance, copy_bone_simple, add_pole_target_bone, get_base_name, get_side_name
from rigify_utils import bone_class_instance, copy_bone_simple, add_pole_target_bone, get_side_name, get_base_name
from Mathutils import Vector
METARIG_NAMES = "hips", "thigh", "shin", "foot", "toe"
@ -105,6 +105,7 @@ def metarig_definition(obj, orig_bone_name):
def ik(obj, bone_definition, base_names, options):
arm = obj.data
bpy.ops.object.mode_set(mode='EDIT')
# setup the existing bones, use names from METARIG_NAMES
mt = bone_class_instance(obj, ["hips"])
@ -128,7 +129,7 @@ def ik(obj, bone_definition, base_names, options):
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 = bone_class_instance(obj, ["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" + get_side_name(base_names[mt_chain.foot])) #XXX - pick a better name
ik.update()
@ -153,7 +154,7 @@ def ik(obj, bone_definition, base_names, options):
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_e = copy_bone_simple(arm, mt_chain.foot, "MCH-" + 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)
@ -213,8 +214,20 @@ def ik(obj, bone_definition, base_names, options):
con.pole_target = obj
con.pole_subtarget = ik.knee_target
ik.update()
ik_chain.update()
# Set layers of the bones.
if "ik_layer" in options:
layer = [n==options["ik_layer"] for n in range(0,32)]
else:
layer = list(mt_chain.thigh_b.layer)
for attr in ik_chain.attr_names:
obj.data.bones[getattr(ik_chain, attr)].layer = layer
for attr in ik.attr_names:
obj.data.bones[getattr(ik, attr)].layer = layer
bpy.ops.object.mode_set(mode='EDIT')
return None, ik_chain.thigh, ik_chain.shin, ik_chain.foot, ik_chain.toe

@ -155,7 +155,7 @@ def main(obj, bone_definition, base_names, options):
# Copy the head bone and offset
ex.head_e = copy_bone_simple(arm, mt.head, "MCH_%s" % base_names[mt.head], parent=True)
ex.head_e = copy_bone_simple(arm, mt.head, "MCH-%s" % base_names[mt.head], parent=True)
ex.head_e.connected = False
ex.head = ex.head_e.name
# offset
@ -164,7 +164,7 @@ def main(obj, bone_definition, base_names, options):
ex.head_e.tail.y += head_length / 2.0
# Yes, use the body bone but call it a head hinge
ex.head_hinge_e = copy_bone_simple(arm, mt.body, "MCH_%s_hinge" % base_names[mt.head], parent=False)
ex.head_hinge_e = copy_bone_simple(arm, mt.body, "MCH-%s_hinge" % base_names[mt.head], parent=False)
ex.head_hinge_e.connected = False
ex.head_hinge = ex.head_hinge_e.name
ex.head_hinge_e.head.y += head_length / 4.0
@ -322,14 +322,25 @@ def main(obj, bone_definition, base_names, options):
con.subtarget = neck_p.name
# Set the head control's custom shape to use the last
# org neck bone for its transform
ex.head_ctrl_p.custom_shape_transform = obj.pose.bones[bone_definition[len(bone_definition)-1]]
# last step setup layers
layers = get_layer_dict(options)
lay = layers["extra"]
if "ex_layer" in options:
layer = [n==options["ex_layer"] for n in range(0,32)]
else:
layer = list(arm.bones[bone_definition[1]].layer)
for attr in ex_chain.attr_names:
getattr(ex_chain, attr + "_b").layer = lay
getattr(ex_chain, attr + "_b").layer = layer
for attr in ex.attr_names:
getattr(ex, attr + "_b").layer = lay
getattr(ex, attr + "_b").layer = layer
layer = list(arm.bones[bone_definition[1]].layer)
ex.head_ctrl_b.layer = layer
# no blending the result of this
return None

@ -261,8 +261,7 @@ def main(obj, bone_definition, base_names, options):
# last step setup layers
layers = get_layer_dict(options)
arm.bones[control_name].layer = layers["extra"]
arm.bones[control_name].layer = list(arm.bones[bone_definition[1]].layer)
# no blending the result of this

@ -522,19 +522,29 @@ def main(obj, bone_definition, base_names, options):
mod.coefficients[1] = spine_chain_len
# last step setup layers
layers = get_layer_dict(options)
lay = layers["extra"]
for attr in ex.attr_names:
getattr(ex, attr + "_b").layer = lay
for attr in ex_chain.attr_names:
getattr(ex_chain, attr + "_b").layer = lay
# Set pelvis and ribcage controls to use the first and last bone in the
# spine respectively for their custom shape transform
ex.ribcage_copy_p.custom_shape_transform = obj.pose.bones[bone_definition[len(bone_definition)-1]]
ex.pelvis_copy_p.custom_shape_transform = obj.pose.bones[bone_definition[2]]
lay = layers["main"]
# last step setup layers
if "ex_layer" in options:
layer = [n==options["ex_layer"] for n in range(0,32)]
else:
layer = list(arm.bones[bone_definition[1]].layer)
for attr in ex.attr_names:
getattr(ex, attr + "_b").layer = layer
for attr in ex_chain.attr_names:
getattr(ex_chain, attr + "_b").layer = layer
for attr in df.attr_names:
getattr(df, attr + "_b").layer = lay
getattr(df, attr + "_b").layer = layer
for attr in rv_chain.attr_names:
getattr(rv_chain, attr + "_b").layer = lay
getattr(rv_chain, attr + "_b").layer = layer
layer = list(arm.bones[bone_definition[1]].layer)
arm.bones[ex.pelvis_copy].layer = layer
arm.bones[ex.ribcage_copy].layer = layer
# no support for blending chains
return None

@ -87,6 +87,7 @@ def copy_bone_simple(arm, from_bone, name, parent=False):
ebone_new.head = ebone.head
ebone_new.tail = ebone.tail
ebone_new.roll = ebone.roll
ebone_new.layer = list(ebone.layer)
return ebone_new