Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2009-12-05 22:26:28 +0300
committerCampbell Barton <ideasman42@gmail.com>2009-12-05 22:26:28 +0300
commit65edb7341f999f576e98ca70b15a46985a6ed9df (patch)
tree555590484c409000bb6f48b85e2859d0fed29f3e /release
parentf287762678d8c55fc2495e7a0ffe71c3ee3006b1 (diff)
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
Diffstat (limited to 'release')
-rw-r--r--release/scripts/modules/rigify/__init__.py292
-rw-r--r--release/scripts/modules/rigify/arm.py78
-rw-r--r--release/scripts/modules/rigify/delta.py39
-rw-r--r--release/scripts/modules/rigify/finger.py70
-rw-r--r--release/scripts/modules/rigify/leg.py209
-rw-r--r--release/scripts/modules/rigify/neck.py56
-rw-r--r--release/scripts/modules/rigify/palm.py35
-rw-r--r--release/scripts/modules/rigify/spine.py109
8 files changed, 554 insertions, 334 deletions
diff --git a/release/scripts/modules/rigify/__init__.py b/release/scripts/modules/rigify/__init__.py
index 7ae2481619f..f6397fa94dc 100644
--- a/release/scripts/modules/rigify/__init__.py
+++ b/release/scripts/modules/rigify/__init__.py
@@ -91,6 +91,7 @@ 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)
new_bones = copy_bone_simple_list(self.obj.data, from_name_ls, new_name_ls, True)
@@ -103,8 +104,10 @@ def _bone_class_instance_copy(self, from_prefix="", to_prefix=""):
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 @@ def _bone_class_instance_blend(self, from_bc, to_bc, target_bone=None, target_pr
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]
-
- 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)
-
+ blend_bone_list(self.obj, apply_bones, from_bones, to_bones, target_bone, target_prop)
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 @@ def bone_class_instance(obj, slots, name="BoneContainer"):
"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,6 +199,78 @@ def copy_bone_simple_list(arm, from_bones, to_bones, parent=False):
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):
'''
@@ -342,8 +359,9 @@ def add_pole_target_bone(obj, base_name, name, mode='CROSS'):
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 @@ def generate_rig(context, ob):
# 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()]
+
+ 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, {})
- if bone_type == "":
- continue
+ # 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)
+ bone_typeinfo.append((submod_name, type_func))
- # submodule = getattr(self, bone_type)
- # exec("from rigify import %s as submodule")
- submodule = __import__(name="%s.%s" % (__package__, bone_type), fromlist=[bone_type])
+
+ # now we have all the info about bones we can start operating on them
+
+ for pbone in obj.pose.bones:
+ bone_name = pbone.name
+
+ if bone_name not in bone_typeinfos:
+ continue
+
+ bone_def_dict = bone_definitions[bone_name]
+
+ # Only blend results from the same submodule, eg.
+ # leg.ik and arm.fk could not be blended.
+ results = OrderedDict()
+
+ for submod_name, type_func in bone_typeinfos[bone_name]:
+ # this bones definition of the current typeinfo
+ definition = bone_def_dict[submod_name]
+
+ bpy.ops.object.mode_set(mode='EDIT')
+ ret = type_func(obj, definition, base_names)
+ bpy.ops.object.mode_set(mode='OBJECT')
- reload(submodule) # XXX, dev only
+ if ret:
+ result_submod = results.setdefault(submod_name, [])
+
+ if result_submod and len(result_submod[-1]) != len(ret):
+ raise Exception("bone lists not compatible: %s, %s" % (result_submod[-1], ret))
+ result_submod.append(ret)
- # Toggle editmode so the pose data is always up to date
- bpy.ops.object.mode_set(mode='EDIT')
- submodule.main(ob_new, pbone_name)
- bpy.ops.object.mode_set(mode='OBJECT')
+ for result_submod in results.values():
+ # blend 2 chains
+ definition = bone_def_dict[submod_name]
+
+ if len(result_submod) == 2:
+ blend_bone_list(obj, definition, result_submod[0], result_submod[1])
# needed to update driver deps
# context.scene.update()
# Only for demo'ing
- # ob.restrict_view = True
- ob_new.data.draw_axes = False
+ # obj.restrict_view = True
+ obj.data.draw_axes = False
context.user_preferences.edit.global_undo = global_undo
- return ob_new
+ return obj
def write_meta_rig(obj, func_name="metarig_template"):
@@ -462,11 +548,11 @@ def generate_test(context):
scene = context.scene
def create_empty_armature(name):
- ob_new = bpy.data.add_object('ARMATURE', name)
+ obj_new = bpy.data.add_object('ARMATURE', name)
armature = bpy.data.add_armature(name)
- ob_new.data = armature
- scene.objects.link(ob_new)
- scene.objects.active = ob_new
+ obj_new.data = armature
+ scene.objects.link(obj_new)
+ scene.objects.active = obj_new
files = os.listdir(os.path.dirname(__file__))
for f in files:
@@ -484,10 +570,10 @@ def generate_test(context):
if metarig_template:
create_empty_armature("meta_" + module_name) # sets active
metarig_template()
- ob = context.object
- ob_new = generate_rig(context, ob)
+ obj = context.object
+ obj_new = generate_rig(context, obj)
- new_objects.append((ob, ob_new))
+ new_objects.append((obj, obj_new))
else:
print("note: rig type '%s' has no metarig_template(), can't test this", module_name)
@@ -505,12 +591,12 @@ def generate_test_all(context):
base_name = os.path.splitext(bpy.data.filename)[0]
for obj, obj_new in new_objects:
- for ob in (obj, obj_new):
- fn = base_name + "-" + bpy.utils.clean_name(ob.name)
+ for obj in (obj, obj_new):
+ fn = base_name + "-" + bpy.utils.clean_name(obj.name)
path_dot = fn + ".dot"
path_png = fn + ".png"
- saved = graphviz_export.graph_armature(ob, path_dot, CONSTRAINTS=True, DRIVERS=True)
+ saved = graphviz_export.graph_armature(obj, path_dot, CONSTRAINTS=True, DRIVERS=True)
#if saved:
# os.system("dot -Tpng %s > %s; eog %s" % (path_dot, path_png, path_png))
diff --git a/release/scripts/modules/rigify/arm.py b/release/scripts/modules/rigify/arm.py
index 36217ed5247..af2d08307dd 100644
--- a/release/scripts/modules/rigify/arm.py
+++ b/release/scripts/modules/rigify/arm.py
@@ -20,6 +20,7 @@ import bpy
from rigify import bone_class_instance, copy_bone_simple, add_pole_target_bone, add_stretch_to
from rna_prop_ui import rna_idprop_ui_get, rna_idprop_ui_prop_get
+METARIG_NAMES = "shoulder", "arm", "forearm", "hand"
def metarig_template():
bpy.ops.object.mode_set(mode='EDIT')
@@ -54,7 +55,38 @@ def metarig_template():
pbone['type'] = 'arm'
-def main(obj, orig_bone_name):
+def metarig_definition(obj, orig_bone_name):
+ mt = bone_class_instance(obj, METARIG_NAMES) # meta
+ mt.arm = orig_bone_name
+ mt.update()
+
+ mt.shoulder_p = mt.arm_p.parent
+ mt.shoulder = mt.shoulder_p.name
+
+ if not mt.shoulder_p:
+ raise Exception("could not find 'arm' parent, skipping:", orig_bone_name)
+
+ # We could have some bones attached, find the bone that has this as its 2nd parent
+ hands = []
+ for pbone in obj.pose.bones:
+ index = pbone.parent_index(mt.arm_p)
+ if index == 2:
+ hands.append(pbone)
+
+ if len(hands) > 1:
+ raise Exception("more then 1 hand found on:", orig_bone_name)
+
+ # first add the 2 new bones
+ mt.hand_p = hands[0]
+ mt.hand = mt.hand_p.name
+
+ mt.forearm_p = mt.hand_p.parent
+ mt.forearm = mt.forearm_p.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]
@@ -64,49 +96,19 @@ def main(obj, orig_bone_name):
- 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, ["shoulder", "arm", "forearm", "hand"]) # meta
+ mt = bone_class_instance(obj, METARIG_NAMES) # meta
+ mt.shoulder, mt.arm, mt.forearm, mt.hand = definitions
+
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
-
- def chain_init():
- '''
- Sanity check and return the arm as a list of bone names.
- '''
- # do a sanity check
- mt.arm = orig_bone_name
- mt.update()
-
- mt.shoulder_p = mt.arm_p.parent
- mt.shoulder = mt.shoulder_p.name
-
- if not mt.shoulder_p:
- print("could not find 'arm' parent, skipping:", orig_bone_name)
- return
-
- # We could have some bones attached, find the bone that has this as its 2nd parent
- hands = []
- for pbone in obj.pose.bones:
- index = pbone.parent_index(mt.arm_p)
- if index == 2:
- hands.append(pbone)
-
- if len(hands) > 1:
- print("more then 1 hand found on:", orig_bone_name)
- return
-
- # first add the 2 new bones
- mt.hand_p = hands[0]
- mt.hand = mt.hand_p.name
-
- mt.forearm_p = mt.hand_p.parent
- mt.forearm = mt.forearm_p.name
-
arm = obj.data
@@ -345,4 +347,6 @@ def main(obj, orig_bone_name):
chain_shoulder()
# Shoulder with its delta and hinge.
-
+
+ # TODO - return a list for fk and IK
+ return None
diff --git a/release/scripts/modules/rigify/delta.py b/release/scripts/modules/rigify/delta.py
index a8458537c12..74cfb6150d2 100644
--- a/release/scripts/modules/rigify/delta.py
+++ b/release/scripts/modules/rigify/delta.py
@@ -19,23 +19,39 @@
import bpy
from rigify import get_bone_data
-def main(obj, delta_name):
+# not used, defined for completeness
+METARIG_NAMES = tuple()
+
+def metarig_definition(obj, orig_bone_name):
'''
- Use this bone to define a delta thats applied to its child in pose mode.
+ The bone given is the head, its parent is the body,
+ # its only child the first of a chain with matching basenames.
+ eg.
+ body -> head -> neck_01 -> neck_02 -> neck_03.... etc
'''
-
arm = obj.data
+ delta = arm.bones[orig_bone_name]
+ children = delta.children
+
+ if len(children) != 1:
+ print("only 1 child supported for delta")
+
+ bone_definition = [delta.name, children[0].name]
+
+ return bone_definition
+
+def main(obj, bone_definition, base_names):
+ '''
+ Use this bone to define a delta thats applied to its child in pose mode.
+ '''
mode_orig = obj.mode
bpy.ops.object.mode_set(mode='OBJECT')
- delta_pbone = obj.pose.bones[delta_name]
- children = delta_pbone.children
+ delta_name, child_name = bone_definition
- if len(children) != 1:
- print("only 1 child supported for delta")
-
- child_name = children[0].name
+ delta_pbone = obj.pose.bones[delta_name]
+
arm, child_pbone, child_bone = get_bone_data(obj, child_name)
delta_phead = delta_pbone.head.copy()
@@ -62,7 +78,7 @@ def main(obj, delta_name):
child_tail = child_ebone.tail.copy()
arm.edit_bones.remove(delta_ebone)
- del delta_ebone # cant use thz
+ del delta_ebone # cant use this
bpy.ops.object.mode_set(mode='OBJECT')
@@ -107,3 +123,6 @@ def main(obj, delta_name):
bpy.ops.object.mode_set(mode=mode_orig)
+ # no blendeing
+ return None
+ \ No newline at end of file
diff --git a/release/scripts/modules/rigify/finger.py b/release/scripts/modules/rigify/finger.py
index a9040830e4e..c839f20e71f 100644
--- a/release/scripts/modules/rigify/finger.py
+++ b/release/scripts/modules/rigify/finger.py
@@ -17,10 +17,11 @@
# ##### END GPL LICENSE BLOCK #####
import bpy
-from rigify import get_bone_data, empty_layer
+from rigify import get_bone_data, empty_layer, copy_bone_simple
from rna_prop_ui import rna_idprop_ui_get, rna_idprop_ui_prop_get
from functools import reduce
+METARIG_NAMES = "finger_01", "finger_02", "finger_03"
def metarig_template():
bpy.ops.object.mode_set(mode='EDIT')
@@ -48,13 +49,43 @@ def metarig_template():
pbone = obj.pose.bones['finger.01']
pbone['type'] = 'finger'
+def metarig_definition(obj, orig_bone_name):
+ '''
+ The bone given is the first in a chain
+ Expects a chain of at least 2 children.
+ eg.
+ finger -> finger_01 -> finger_02
+ '''
+
+ bone_definition = []
+
+ orig_bone = obj.data.bones[orig_bone_name]
+
+ bone_definition.append(orig_bone.name)
+
+ bone = orig_bone
+ chain = 0
+ while chain < 2: # first 2 bones only have 1 child
+ children = bone.children
+
+ if len(children) != 1:
+ raise Exception("expected the chain to have 2 children without a fork")
+ bone = children[0]
+ bone_definition.append(bone.name) # finger_02, finger_03
+ chain += 1
+
+ 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 main(obj, bone_definition, base_names):
# *** EDITMODE
# get assosiated data
- arm, orig_pbone, orig_ebone = get_bone_data(obj, orig_bone_name)
+ arm, orig_pbone, orig_ebone = get_bone_data(obj, bone_definition[0])
obj.animation_data_create() # needed if its a new armature with no keys
@@ -63,22 +94,16 @@ def main(obj, orig_bone_name):
children = orig_pbone.children_recursive
tot_len = reduce(lambda f, pbone: f + pbone.bone.length, children, orig_pbone.bone.length)
- base_name = orig_pbone.basename
+ base_name = base_names[bone_definition[0]].rsplit(".", 1)[0]
# first make a new bone at the location of the finger
- control_ebone = arm.edit_bones.new(base_name)
+ #control_ebone = arm.edit_bones.new(base_name)
+ control_ebone = copy_bone_simple(arm, base_name, base_name)
control_bone_name = control_ebone.name # we dont know if we get the name requested
control_ebone.connected = orig_ebone.connected
control_ebone.parent = orig_ebone.parent
-
- # 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
+ control_ebone.length = tot_len
# now add bones inbetween this and its children recursively
@@ -99,19 +124,10 @@ def main(obj, orig_bone_name):
driver_bone_name = child_bone_name.split('.')
driver_bone_name = driver_bone_name[0] + "_driver." + ".".join(driver_bone_name[1:])
- driver_ebone = arm.edit_bones.new(driver_bone_name)
- driver_bone_name = driver_ebone.name # cant be too sure!
+ driver_ebone = copy_bone_simple(arm, child_ebone.name, driver_bone_name)
+ driver_ebone.length *= 0.5
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
@@ -129,7 +145,7 @@ def main(obj, orig_bone_name):
bpy.ops.object.mode_set(mode='OBJECT')
- arm, orig_pbone, orig_bone = get_bone_data(obj, orig_bone_name)
+ arm, orig_pbone, orig_bone = get_bone_data(obj, bone_definition[0])
arm, control_pbone, control_bone= get_bone_data(obj, control_bone_name)
@@ -198,4 +214,6 @@ def main(obj, orig_bone_name):
driver_pbone.lock_rotation = child_pbone.lock_rotation = (False, True, True)
i += 1
-
+
+ # no blending the result of this
+ return None
diff --git a/release/scripts/modules/rigify/leg.py b/release/scripts/modules/rigify/leg.py
index 54dc76dafcf..589e295101c 100644
--- a/release/scripts/modules/rigify/leg.py
+++ b/release/scripts/modules/rigify/leg.py
@@ -17,9 +17,11 @@
# ##### 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
diff --git a/release/scripts/modules/rigify/neck.py b/release/scripts/modules/rigify/neck.py
index 524de6e2f3d..a075b797c1a 100644
--- a/release/scripts/modules/rigify/neck.py
+++ b/release/scripts/modules/rigify/neck.py
@@ -20,6 +20,8 @@ import bpy
from rigify import bone_class_instance, copy_bone_simple
from rna_prop_ui import rna_idprop_ui_prop_get
+# not used, defined for completeness
+METARIG_NAMES = ("body", "head")
def metarig_template():
bpy.ops.object.mode_set(mode='EDIT')
@@ -72,30 +74,43 @@ def metarig_template():
pbone['type'] = 'neck'
-def main(obj, orig_bone_name):
+def metarig_definition(obj, orig_bone_name):
+ '''
+ The bone given is the head, its parent is the body,
+ # its only child the first of a chain with matching basenames.
+ eg.
+ body -> head -> neck_01 -> neck_02 -> neck_03.... etc
+ '''
+ arm = obj.data
+ head = arm.bones[orig_bone_name]
+ body = head.parent
+
+ children = head.children
+ if len(children) != 1:
+ print("expected the head to have only 1 child.")
+
+ child = children[0]
+ bone_definition = [body.name, head.name, child.name]
+ bone_definition.extend([child.name for child in child.children_recursive_basename])
+ return bone_definition
+
+
+def main(obj, bone_definition, base_names):
from Mathutils import Vector
arm = obj.data
# Initialize container classes for convenience
mt = bone_class_instance(obj, ["body", "head"]) # meta
- mt.head = orig_bone_name
- mt.update()
- mt.body = mt.head_e.parent.name
+ mt.body = bone_definition[0]
+ mt.head = bone_definition[1]
mt.update()
- # child chain of the 'head'
- children = mt.head_e.children
- if len(children) != 1:
- print("expected the head to have only 1 child.")
+ neck_chain = bone_definition[2:]
- child = children[0]
- neck_chain = [child] + child.children_recursive_basename
- neck_chain = [child.name for child in neck_chain]
-
mt_chain = bone_class_instance(obj, [("neck_%.2d" % (i + 1)) for i in range(len(neck_chain))]) # 99 bones enough eh?
- for i, child_name in enumerate(neck_chain):
- setattr(mt_chain, ("neck_%.2d" % (i + 1)), child_name)
+ for i, attr in enumerate(mt_chain.attr_names):
+ setattr(mt_chain, attr, neck_chain[i])
mt_chain.update()
neck_chain_basename = mt_chain.neck_01_e.basename
@@ -135,8 +150,8 @@ def main(obj, orig_bone_name):
mt.head_e.head.y += head_length / 4.0
mt.head_e.tail.y += head_length / 4.0
- for i in range(len(neck_chain)):
- neck_e = getattr(mt_chain, "neck_%.2d_e" % (i + 1))
+ for i, attr in enumerate(mt_chain.attr_names):
+ neck_e = getattr(mt_chain, attr + "_e")
# dont store parent names, re-reference as each chain bones parent.
neck_e_parent = arm.edit_bones.new("MCH-rot_%s" % neck_e.name)
@@ -205,9 +220,9 @@ def main(obj, orig_bone_name):
target_names = [("b%.2d" % (i + 1)) for i in range(len(neck_chain))]
expression_suffix = "/max(0.001,%s)" % "+".join(target_names)
-
- for i in range(len(neck_chain)):
- neck_p = getattr(mt_chain, "neck_%.2d_p" % (i + 1))
+
+ for i, attr in enumerate(mt_chain.attr_names):
+ neck_p = getattr(mt_chain, attr + "_p")
neck_p.lock_location = True, True, True
neck_p.lock_location = True, True, True
neck_p.lock_rotations_4d = True
@@ -243,3 +258,6 @@ def main(obj, orig_bone_name):
tar.id_type = 'OBJECT'
tar.id = obj
tar.rna_path = head_driver_path + ('["bend_%.2d"]' % (j + 1))
+
+ # no blending the result of this
+ return None
diff --git a/release/scripts/modules/rigify/palm.py b/release/scripts/modules/rigify/palm.py
index b9df113167c..ea90133e8af 100644
--- a/release/scripts/modules/rigify/palm.py
+++ b/release/scripts/modules/rigify/palm.py
@@ -20,6 +20,8 @@ import bpy
from rigify import get_bone_data, copy_bone_simple
from rna_prop_ui import rna_idprop_ui_get, rna_idprop_ui_prop_get
+# not used, defined for completeness
+METARIG_NAMES = tuple()
def metarig_template():
bpy.ops.object.mode_set(mode='EDIT')
@@ -72,20 +74,39 @@ def metarig_template():
pbone['type'] = 'palm'
-def main(obj, orig_bone_name):
- arm, palm_pbone, palm_ebone = get_bone_data(obj, orig_bone_name)
+def metarig_definition(obj, orig_bone_name):
+ '''
+ The bone given is the first in a chain
+ Expects an array of children sorted with the little finger lowest.
+ eg.
+ parent -> [pinky, ring... etc]
+ '''
+ arm = obj.data
+ bone_definition = [orig_bone_name]
+ palm_ebone = arm.bones[orig_bone_name]
+
children = [ebone.name for ebone in palm_ebone.children]
children.sort() # simply assume the pinky has the lowest name
+ bone_definition.extend(children)
+
+ return bone_definition
+
+
+def main(obj, bone_definition, base_names):
+ arm, palm_pbone, palm_ebone = get_bone_data(obj, bone_definition[0])
+ children = bone_definition[1:]
# Make a copy of the pinky
+ # simply assume the pinky has the lowest name
pinky_ebone = arm.edit_bones[children[0]]
+ ring_ebone = arm.edit_bones[children[1]]
+
control_ebone = copy_bone_simple(arm, pinky_ebone.name, "palm_control", parent=True)
control_name = control_ebone.name
- offset = (arm.edit_bones[children[0]].head - arm.edit_bones[children[1]].head)
+ offset = (pinky_ebone.head - ring_ebone.head)
- control_ebone.head += offset
- control_ebone.tail += offset
+ control_ebone.translate(offset)
bpy.ops.object.mode_set(mode='OBJECT')
@@ -179,4 +200,6 @@ def main(obj, orig_bone_name):
child_pbone = obj.pose.bones[children[-1]]
child_pbone.rotation_mode = 'QUATERNION'
-
+
+ # no blending the result of this
+ return None
diff --git a/release/scripts/modules/rigify/spine.py b/release/scripts/modules/rigify/spine.py
index f75575daacb..4fa8d363934 100644
--- a/release/scripts/modules/rigify/spine.py
+++ b/release/scripts/modules/rigify/spine.py
@@ -20,6 +20,8 @@ import bpy
from rigify import bone_class_instance, copy_bone_simple
from rna_prop_ui import rna_idprop_ui_prop_get
+# not used, defined for completeness
+METARIG_NAMES = ("pelvis", "ribcage")
def metarig_template():
bpy.ops.object.mode_set(mode='EDIT')
@@ -84,48 +86,59 @@ def metarig_template():
pbone['type'] = 'spine'
-def validate(obj, orig_bone_name):
+def metarig_definition(obj, orig_bone_name):
'''
The bone given is the second in a chain.
Expects at least 1 parent and a chain of children withe the same basename
eg.
pelvis -> rib_cage -> spine.01 -> spine.02 -> spine.03
+
+ note: same as neck.
'''
- orig_bone = obj.data.bones[orig_bone_name]
- if not orig_bone.parent:
- return "expected spine bone '%s' to have a parent" % orig_bone_name
+ arm = obj.data
+ ribcage = arm.bones[orig_bone_name]
+ pelvis = ribcage.parent
- children = orig_bone.children
-
+ children = ribcage.children
if len(children) != 1:
- return "expected spine bone '%s' to have only 1 child for the sine chain" % orig_bone_name
-
- children_spine = children[0].children_recursive_basename
+ print("expected the ribcage to have only 1 child.")
- if len(children_spine) == 0:
- return "expected '%s' to define a chain of children with its basename (2 or more)" % children[0]
+ child = children[0]
+ bone_definition = [pelvis.name, ribcage.name, child.name]
+ bone_definition.extend([child.name for child in child.children_recursive_basename])
+ return bone_definition
- return ''
+def fk(*args):
+ main(*args)
-def main(obj, orig_bone_name):
+def main(obj, bone_definition, base_names):
from Mathutils import Vector, Matrix, RotationMatrix
from math import radians, pi
-
+
arm = obj.data
# Initialize container classes for convenience
mt = bone_class_instance(obj, ["pelvis", "ribcage"]) # meta
- mt.ribcage = orig_bone_name
- mt.update()
- mt.pelvis = mt.ribcage_e.parent.name
+ mt.pelvis = bone_definition[0]
+ mt.ribcage = bone_definition[1]
mt.update()
+ spine_chain_orig = bone_definition[2:]
+ spine_chain = [arm.edit_bones[child_name] for child_name in spine_chain_orig]
+ spine_chain_basename = base_names[spine_chain[0].name].rsplit(".", 1) # probably 'ORG-spine.01' -> 'spine'
+ spine_chain_len = len(spine_chain_orig)
+
+ '''
children = mt.ribcage_e.children
child = children[0] # validate checks for 1 only.
spine_chain_basename = child.basename # probably 'spine'
spine_chain_segment_length = child.length
spine_chain = [child] + child.children_recursive_basename
spine_chain_orig = [child.name for child in spine_chain]
+ '''
+
+ child = spine_chain[0]
+ spine_chain_segment_length = child.length
child.parent = mt.pelvis_e # was mt.ribcage
# The first bone in the chain happens to be the basis of others, create them now
@@ -177,16 +190,17 @@ def main(obj, orig_bone_name):
# - original (ORG_*)
# - copy (*use original name*)
# - reverse (MCH-rev_*)
- spine_chain_attrs = [("spine_%.2d" % (i + 1)) for i in range(len(spine_chain_orig))]
+ spine_chain_attrs = [("spine_%.2d" % (i + 1)) for i in range(spine_chain_len)]
mt_chain = bone_class_instance(obj, spine_chain_attrs) # ORG_*
rv_chain = bone_class_instance(obj, spine_chain_attrs) # *
ex_chain = bone_class_instance(obj, spine_chain_attrs) # MCH-rev_*
+ del spine_chain_attrs
for i, child_name in enumerate(spine_chain):
child_name_orig = spine_chain_orig[i]
- attr = spine_chain_attrs[i] # eg. spine_04
+ attr = mt_chain.attr_names[i] # eg. spine_04
setattr(mt_chain, attr, spine_chain[i]) # use the new name
@@ -203,12 +217,12 @@ def main(obj, orig_bone_name):
# Now we need to re-parent these chains
for i, child_name in enumerate(spine_chain_orig):
- attr = spine_chain_attrs[i] + "_e"
+ attr = ex_chain.attr_names[i] + "_e"
if i == 0:
getattr(ex_chain, attr).parent = mt.pelvis_e
else:
- attr_parent = spine_chain_attrs[i-1] + "_e"
+ attr_parent = ex_chain.attr_names[i-1] + "_e"
getattr(ex_chain, attr).parent = getattr(ex_chain, attr_parent)
# intentional! get the parent from the other paralelle chain member
@@ -217,9 +231,9 @@ def main(obj, orig_bone_name):
# ex_chain needs to interlace bones!
# Note, skip the first bone
- for i in range(1, len(spine_chain_attrs)): # similar to neck
+ for i in range(1, spine_chain_len): # similar to neck
child_name_orig = spine_chain_orig[i]
- spine_e = getattr(mt_chain, spine_chain_attrs[i] + "_e")
+ spine_e = getattr(mt_chain, mt_chain.attr_names[i] + "_e")
# dont store parent names, re-reference as each chain bones parent.
spine_e_parent = arm.edit_bones.new("MCH-rot_%s" % child_name_orig)
@@ -227,7 +241,7 @@ def main(obj, orig_bone_name):
spine_e_parent.tail = spine_e.head + Vector(0.0, 0.0, spine_chain_segment_length / 2.0)
spine_e_parent.roll = 0.0
- spine_e = getattr(ex_chain, spine_chain_attrs[i] + "_e")
+ spine_e = getattr(ex_chain, ex_chain.attr_names[i] + "_e")
orig_parent = spine_e.parent
spine_e.connected = False
spine_e.parent = spine_e_parent
@@ -239,8 +253,8 @@ def main(obj, orig_bone_name):
# Rotate the rev chain 180 about the by the first bones center point
pivot = (rv_chain.spine_01_e.head + rv_chain.spine_01_e.tail) * 0.5
matrix = RotationMatrix(radians(180), 3, 'X')
- for i in range(len(spine_chain_attrs)): # similar to neck
- spine_e = getattr(rv_chain, spine_chain_attrs[i] + "_e")
+ for i, attr in enumerate(rv_chain.attr_names): # similar to neck
+ spine_e = getattr(rv_chain, attr + "_e")
# use the first bone as the pivot
spine_e.head = ((spine_e.head - pivot) * matrix) + pivot
@@ -326,12 +340,12 @@ def main(obj, orig_bone_name):
# ex.ribcage_p / MCH-wgt_rib_cage
con = ex.ribcage_p.constraints.new('COPY_LOCATION')
con.target = obj
- con.subtarget = getattr(mt_chain, spine_chain_attrs[-1])
+ con.subtarget = getattr(mt_chain, mt_chain.attr_names[-1])
con.head_tail = 0.0
con = ex.ribcage_p.constraints.new('COPY_ROTATION')
con.target = obj
- con.subtarget = getattr(mt_chain, spine_chain_attrs[-1])
+ con.subtarget = getattr(mt_chain, mt_chain.attr_names[-1])
# mt.pelvis_p / rib_cage
con = mt.ribcage_p.constraints.new('COPY_LOCATION')
@@ -347,10 +361,10 @@ def main(obj, orig_bone_name):
prop = rna_idprop_ui_prop_get(mt.ribcage_p, "pivot_slide", create=True)
mt.ribcage_p["pivot_slide"] = 0.5
- prop["soft_min"] = 1.0 / len(spine_chain_attrs)
+ prop["soft_min"] = 1.0 / spine_chain_len
prop["soft_max"] = 1.0
- for i in range(len(spine_chain_attrs) - 1):
+ for i in range(spine_chain_len - 1):
prop_name = "bend_%.2d" % (i + 1)
prop = rna_idprop_ui_prop_get(mt.ribcage_p, prop_name, create=True)
mt.ribcage_p[prop_name] = 1.0
@@ -361,9 +375,9 @@ def main(obj, orig_bone_name):
# positioned at the tip.
# reverse bones / MCH-rev_spine.##
- for i in range(1, len(spine_chain_attrs)):
- spine_p = getattr(rv_chain, spine_chain_attrs[i] + "_p")
- spine_fake_parent_name = getattr(rv_chain, spine_chain_attrs[i - 1])
+ for i in range(1, spine_chain_len):
+ spine_p = getattr(rv_chain, rv_chain.attr_names[i] + "_p")
+ spine_fake_parent_name = getattr(rv_chain, rv_chain.attr_names[i - 1])
con = spine_p.constraints.new('COPY_LOCATION')
con.target = obj
@@ -375,14 +389,14 @@ def main(obj, orig_bone_name):
# Constrain 'inbetween' bones
# b01/max(0.001,b01+b02+b03+b04+b05)
- target_names = [("b%.2d" % (i + 1)) for i in range(len(spine_chain_attrs) - 1)]
+ target_names = [("b%.2d" % (i + 1)) for i in range(spine_chain_len - 1)]
expression_suffix = "/max(0.001,%s)" % "+".join(target_names)
rib_driver_path = mt.ribcage_p.path_to_id()
- for i in range(1, len(spine_chain_attrs)):
+ for i in range(1, spine_chain_len):
- spine_p = getattr(ex_chain, spine_chain_attrs[i] + "_p")
+ spine_p = getattr(ex_chain, ex_chain.attr_names[i] + "_p")
spine_p_parent = spine_p.parent # interlaced bone
con = spine_p_parent.constraints.new('COPY_ROTATION')
@@ -400,7 +414,7 @@ def main(obj, orig_bone_name):
driver.expression = target_names[i - 1] + expression_suffix
fcurve.modifiers.remove(0) # grr dont need a modifier
- for j in range(len(spine_chain_attrs) - 1):
+ for j in range(spine_chain_len - 1):
tar = driver.targets.new()
tar.name = target_names[j]
tar.id_type = 'OBJECT'
@@ -410,12 +424,12 @@ def main(obj, orig_bone_name):
# original bone drivers
# note: the first bone has a lot more constraints, but also this simple one is first.
- for i in range(len(spine_chain_attrs)):
- spine_p = getattr(mt_chain, spine_chain_attrs[i] + "_p")
+ for i in attr, enumerate(mt_chain.attr_names):
+ spine_p = getattr(mt_chain, attr + "_p")
con = spine_p.constraints.new('COPY_ROTATION')
con.target = obj
- con.subtarget = getattr(ex_chain, spine_chain_attrs[i]) # lock to the copy's rotation
+ con.subtarget = getattr(ex_chain, attr) # lock to the copy's rotation
del spine_p
# pivot slide: - lots of copy location constraints.
@@ -425,19 +439,19 @@ def main(obj, orig_bone_name):
con.target = obj
con.subtarget = rv_chain.spine_01 # lock to the reverse location
- for i in range(1, len(spine_chain_attrs) + 1):
+ for i in range(1, spine_chain_len + 1):
con = mt_chain.spine_01_p.constraints.new('COPY_LOCATION')
con.name = "slide_%d" % i
con.target = obj
- if i == len(spine_chain_attrs):
- attr = spine_chain_attrs[i - 1]
+ if i == spine_chain_len:
+ attr = mt_chain.attr_names[i - 1]
else:
- attr = spine_chain_attrs[i]
+ attr = mt_chain.attr_names[i]
con.subtarget = getattr(rv_chain, attr) # lock to the reverse location
- if i == len(spine_chain_attrs):
+ if i == spine_chain_len:
con.head_tail = 1.0
fcurve = con.driver_add("influence", 0)
@@ -452,5 +466,8 @@ def main(obj, orig_bone_name):
mod = fcurve.modifiers[0]
mod.poly_order = 1
mod.coefficients[0] = - (i - 1)
- mod.coefficients[1] = len(spine_chain_attrs)
+ mod.coefficients[1] = spine_chain_len
+
+ # no support for blending chains
+ return None