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
This commit is contained in:
@@ -91,6 +91,7 @@ def _bone_class_instance_copy(self, from_prefix="", to_prefix=""):
|
|||||||
|
|
||||||
new_slot_ls.append(attr)
|
new_slot_ls.append(attr)
|
||||||
from_name_ls.append(bone_name)
|
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_name_ls.append(to_prefix + bone_name_orig)
|
||||||
|
|
||||||
new_bones = copy_bone_simple_list(self.obj.data, from_name_ls, new_name_ls, True)
|
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
|
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.
|
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 :(
|
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:
|
if self.attr_names != from_bc.attr_names or self.attr_names != to_bc.attr_names:
|
||||||
raise Exception("can only blend between matching chains")
|
raise Exception("can only blend between matching chains")
|
||||||
|
|
||||||
obj = self.obj
|
apply_bones = [getattr(self, attr) for attr in self.attr_names]
|
||||||
|
from_bones = [getattr(from_bc, attr) for attr in from_bc.attr_names]
|
||||||
if obj.mode == 'EDIT':
|
to_bones = [getattr(to_bc, attr) for attr in to_bc.attr_names]
|
||||||
raise Exception("blending cant be called in editmode")
|
|
||||||
|
|
||||||
# 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"):
|
def bone_class_instance(obj, slots, name="BoneContainer"):
|
||||||
attr_names = tuple(slots) # dont modify the original
|
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)):
|
for i in range(len(slots)):
|
||||||
member = slots[i]
|
member = slots[i]
|
||||||
slots.append(member + "_b") # bone bone
|
slots.append(member + "_b") # bone bone
|
||||||
@@ -196,6 +140,7 @@ def bone_class_instance(obj, slots, name="BoneContainer"):
|
|||||||
"attr_names":attr_names, \
|
"attr_names":attr_names, \
|
||||||
"update":_bone_class_instance_update, \
|
"update":_bone_class_instance_update, \
|
||||||
"rename":_bone_class_instance_rename, \
|
"rename":_bone_class_instance_rename, \
|
||||||
|
"names":_bone_class_instance_names, \
|
||||||
"copy":_bone_class_instance_copy, \
|
"copy":_bone_class_instance_copy, \
|
||||||
"blend":_bone_class_instance_blend, \
|
"blend":_bone_class_instance_blend, \
|
||||||
}
|
}
|
||||||
@@ -254,6 +199,78 @@ def copy_bone_simple_list(arm, from_bones, to_bones, parent=False):
|
|||||||
|
|
||||||
return copy_bones
|
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):
|
def add_stretch_to(obj, from_name, to_name, name):
|
||||||
'''
|
'''
|
||||||
@@ -342,7 +359,8 @@ def add_pole_target_bone(obj, base_name, name, mode='CROSS'):
|
|||||||
return poll_name
|
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
|
global_undo = context.user_preferences.edit.global_undo
|
||||||
context.user_preferences.edit.global_undo = False
|
context.user_preferences.edit.global_undo = False
|
||||||
@@ -351,50 +369,118 @@ def generate_rig(context, ob):
|
|||||||
|
|
||||||
|
|
||||||
# copy object and data
|
# copy object and data
|
||||||
ob.selected = False
|
obj_orig.selected = False
|
||||||
ob_new = ob.copy()
|
obj = obj_orig.copy()
|
||||||
ob_new.data = ob.data.copy()
|
obj.data = obj_orig.data.copy()
|
||||||
scene = context.scene
|
scene = context.scene
|
||||||
scene.objects.link(ob_new)
|
scene.objects.link(obj)
|
||||||
scene.objects.active = ob_new
|
scene.objects.active = obj
|
||||||
ob_new.selected = True
|
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
|
# original name mapping
|
||||||
pose_names = [pbone.name for pbone in ob_new.pose.bones if "type" in pbone]
|
base_names = {}
|
||||||
|
|
||||||
#for pbone_name in ob_new.pose.bones.keys():
|
bpy.ops.object.mode_set(mode='EDIT')
|
||||||
for pbone_name in pose_names:
|
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 = {}
|
||||||
|
|
||||||
if bone_type == "":
|
# 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, {})
|
||||||
|
|
||||||
|
# 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))
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
continue
|
||||||
|
|
||||||
# submodule = getattr(self, bone_type)
|
bone_def_dict = bone_definitions[bone_name]
|
||||||
# exec("from rigify import %s as submodule")
|
|
||||||
submodule = __import__(name="%s.%s" % (__package__, bone_type), fromlist=[bone_type])
|
|
||||||
|
|
||||||
reload(submodule) # XXX, dev only
|
# 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]
|
||||||
|
|
||||||
# Toggle editmode so the pose data is always up to date
|
|
||||||
bpy.ops.object.mode_set(mode='EDIT')
|
bpy.ops.object.mode_set(mode='EDIT')
|
||||||
submodule.main(ob_new, pbone_name)
|
ret = type_func(obj, definition, base_names)
|
||||||
bpy.ops.object.mode_set(mode='OBJECT')
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
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
|
# needed to update driver deps
|
||||||
# context.scene.update()
|
# context.scene.update()
|
||||||
|
|
||||||
# Only for demo'ing
|
# Only for demo'ing
|
||||||
|
|
||||||
# ob.restrict_view = True
|
# obj.restrict_view = True
|
||||||
ob_new.data.draw_axes = False
|
obj.data.draw_axes = False
|
||||||
|
|
||||||
context.user_preferences.edit.global_undo = global_undo
|
context.user_preferences.edit.global_undo = global_undo
|
||||||
|
|
||||||
return ob_new
|
return obj
|
||||||
|
|
||||||
|
|
||||||
def write_meta_rig(obj, func_name="metarig_template"):
|
def write_meta_rig(obj, func_name="metarig_template"):
|
||||||
@@ -462,11 +548,11 @@ def generate_test(context):
|
|||||||
|
|
||||||
scene = context.scene
|
scene = context.scene
|
||||||
def create_empty_armature(name):
|
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)
|
armature = bpy.data.add_armature(name)
|
||||||
ob_new.data = armature
|
obj_new.data = armature
|
||||||
scene.objects.link(ob_new)
|
scene.objects.link(obj_new)
|
||||||
scene.objects.active = ob_new
|
scene.objects.active = obj_new
|
||||||
|
|
||||||
files = os.listdir(os.path.dirname(__file__))
|
files = os.listdir(os.path.dirname(__file__))
|
||||||
for f in files:
|
for f in files:
|
||||||
@@ -484,10 +570,10 @@ def generate_test(context):
|
|||||||
if metarig_template:
|
if metarig_template:
|
||||||
create_empty_armature("meta_" + module_name) # sets active
|
create_empty_armature("meta_" + module_name) # sets active
|
||||||
metarig_template()
|
metarig_template()
|
||||||
ob = context.object
|
obj = context.object
|
||||||
ob_new = generate_rig(context, ob)
|
obj_new = generate_rig(context, obj)
|
||||||
|
|
||||||
new_objects.append((ob, ob_new))
|
new_objects.append((obj, obj_new))
|
||||||
else:
|
else:
|
||||||
print("note: rig type '%s' has no metarig_template(), can't test this", module_name)
|
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]
|
base_name = os.path.splitext(bpy.data.filename)[0]
|
||||||
for obj, obj_new in new_objects:
|
for obj, obj_new in new_objects:
|
||||||
for ob in (obj, obj_new):
|
for obj in (obj, obj_new):
|
||||||
fn = base_name + "-" + bpy.utils.clean_name(ob.name)
|
fn = base_name + "-" + bpy.utils.clean_name(obj.name)
|
||||||
|
|
||||||
path_dot = fn + ".dot"
|
path_dot = fn + ".dot"
|
||||||
path_png = fn + ".png"
|
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:
|
#if saved:
|
||||||
# os.system("dot -Tpng %s > %s; eog %s" % (path_dot, path_png, path_png))
|
# os.system("dot -Tpng %s > %s; eog %s" % (path_dot, path_png, path_png))
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ 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
|
||||||
from rna_prop_ui import rna_idprop_ui_get, rna_idprop_ui_prop_get
|
from rna_prop_ui import rna_idprop_ui_get, rna_idprop_ui_prop_get
|
||||||
|
|
||||||
|
METARIG_NAMES = "shoulder", "arm", "forearm", "hand"
|
||||||
|
|
||||||
def metarig_template():
|
def metarig_template():
|
||||||
bpy.ops.object.mode_set(mode='EDIT')
|
bpy.ops.object.mode_set(mode='EDIT')
|
||||||
@@ -54,31 +55,8 @@ def metarig_template():
|
|||||||
pbone['type'] = 'arm'
|
pbone['type'] = 'arm'
|
||||||
|
|
||||||
|
|
||||||
def main(obj, orig_bone_name):
|
def metarig_definition(obj, orig_bone_name):
|
||||||
"""
|
mt = bone_class_instance(obj, METARIG_NAMES) # meta
|
||||||
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, ["shoulder", "arm", "forearm", "hand"]) # meta
|
|
||||||
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.arm = orig_bone_name
|
||||||
mt.update()
|
mt.update()
|
||||||
|
|
||||||
@@ -86,8 +64,7 @@ def main(obj, orig_bone_name):
|
|||||||
mt.shoulder = mt.shoulder_p.name
|
mt.shoulder = mt.shoulder_p.name
|
||||||
|
|
||||||
if not mt.shoulder_p:
|
if not mt.shoulder_p:
|
||||||
print("could not find 'arm' parent, skipping:", orig_bone_name)
|
raise Exception("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
|
# We could have some bones attached, find the bone that has this as its 2nd parent
|
||||||
hands = []
|
hands = []
|
||||||
@@ -97,8 +74,7 @@ def main(obj, orig_bone_name):
|
|||||||
hands.append(pbone)
|
hands.append(pbone)
|
||||||
|
|
||||||
if len(hands) > 1:
|
if len(hands) > 1:
|
||||||
print("more then 1 hand found on:", orig_bone_name)
|
raise Exception("more then 1 hand found on:", orig_bone_name)
|
||||||
return
|
|
||||||
|
|
||||||
# first add the 2 new bones
|
# first add the 2 new bones
|
||||||
mt.hand_p = hands[0]
|
mt.hand_p = hands[0]
|
||||||
@@ -107,6 +83,32 @@ def main(obj, orig_bone_name):
|
|||||||
mt.forearm_p = mt.hand_p.parent
|
mt.forearm_p = mt.hand_p.parent
|
||||||
mt.forearm = mt.forearm_p.name
|
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]
|
||||||
|
...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
|
||||||
|
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
|
||||||
|
|
||||||
arm = obj.data
|
arm = obj.data
|
||||||
|
|
||||||
|
|
||||||
@@ -346,3 +348,5 @@ def main(obj, orig_bone_name):
|
|||||||
|
|
||||||
# Shoulder with its delta and hinge.
|
# Shoulder with its delta and hinge.
|
||||||
|
|
||||||
|
# TODO - return a list for fk and IK
|
||||||
|
return None
|
||||||
|
|||||||
@@ -19,23 +19,39 @@
|
|||||||
import bpy
|
import bpy
|
||||||
from rigify import get_bone_data
|
from rigify import get_bone_data
|
||||||
|
|
||||||
def main(obj, delta_name):
|
# not used, defined for completeness
|
||||||
'''
|
METARIG_NAMES = tuple()
|
||||||
Use this bone to define a delta thats applied to its child in pose mode.
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
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
|
arm = obj.data
|
||||||
|
delta = arm.bones[orig_bone_name]
|
||||||
mode_orig = obj.mode
|
children = delta.children
|
||||||
bpy.ops.object.mode_set(mode='OBJECT')
|
|
||||||
|
|
||||||
delta_pbone = obj.pose.bones[delta_name]
|
|
||||||
children = delta_pbone.children
|
|
||||||
|
|
||||||
if len(children) != 1:
|
if len(children) != 1:
|
||||||
print("only 1 child supported for delta")
|
print("only 1 child supported for delta")
|
||||||
|
|
||||||
child_name = children[0].name
|
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_name, child_name = bone_definition
|
||||||
|
|
||||||
|
delta_pbone = obj.pose.bones[delta_name]
|
||||||
|
|
||||||
arm, child_pbone, child_bone = get_bone_data(obj, child_name)
|
arm, child_pbone, child_bone = get_bone_data(obj, child_name)
|
||||||
|
|
||||||
delta_phead = delta_pbone.head.copy()
|
delta_phead = delta_pbone.head.copy()
|
||||||
@@ -62,7 +78,7 @@ def main(obj, delta_name):
|
|||||||
child_tail = child_ebone.tail.copy()
|
child_tail = child_ebone.tail.copy()
|
||||||
|
|
||||||
arm.edit_bones.remove(delta_ebone)
|
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')
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
|
|
||||||
@@ -107,3 +123,6 @@ def main(obj, delta_name):
|
|||||||
|
|
||||||
bpy.ops.object.mode_set(mode=mode_orig)
|
bpy.ops.object.mode_set(mode=mode_orig)
|
||||||
|
|
||||||
|
# no blendeing
|
||||||
|
return None
|
||||||
|
|
||||||
@@ -17,10 +17,11 @@
|
|||||||
# ##### END GPL LICENSE BLOCK #####
|
# ##### END GPL LICENSE BLOCK #####
|
||||||
|
|
||||||
import bpy
|
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 rna_prop_ui import rna_idprop_ui_get, rna_idprop_ui_prop_get
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
|
||||||
|
METARIG_NAMES = "finger_01", "finger_02", "finger_03"
|
||||||
|
|
||||||
def metarig_template():
|
def metarig_template():
|
||||||
bpy.ops.object.mode_set(mode='EDIT')
|
bpy.ops.object.mode_set(mode='EDIT')
|
||||||
@@ -48,13 +49,43 @@ def metarig_template():
|
|||||||
pbone = obj.pose.bones['finger.01']
|
pbone = obj.pose.bones['finger.01']
|
||||||
pbone['type'] = 'finger'
|
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
|
||||||
|
'''
|
||||||
|
|
||||||
def main(obj, orig_bone_name):
|
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, bone_definition, base_names):
|
||||||
|
|
||||||
# *** EDITMODE
|
# *** EDITMODE
|
||||||
|
|
||||||
# get assosiated data
|
# 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
|
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
|
children = orig_pbone.children_recursive
|
||||||
tot_len = reduce(lambda f, pbone: f + pbone.bone.length, children, orig_pbone.bone.length)
|
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
|
# 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_bone_name = control_ebone.name # we dont know if we get the name requested
|
||||||
|
|
||||||
control_ebone.connected = orig_ebone.connected
|
control_ebone.connected = orig_ebone.connected
|
||||||
control_ebone.parent = orig_ebone.parent
|
control_ebone.parent = orig_ebone.parent
|
||||||
|
control_ebone.length = tot_len
|
||||||
# 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
|
# 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 = child_bone_name.split('.')
|
||||||
driver_bone_name = driver_bone_name[0] + "_driver." + ".".join(driver_bone_name[1:])
|
driver_bone_name = driver_bone_name[0] + "_driver." + ".".join(driver_bone_name[1:])
|
||||||
|
|
||||||
driver_ebone = arm.edit_bones.new(driver_bone_name)
|
driver_ebone = copy_bone_simple(arm, child_ebone.name, driver_bone_name)
|
||||||
driver_bone_name = driver_ebone.name # cant be too sure!
|
driver_ebone.length *= 0.5
|
||||||
driver_ebone.layer = other_layer
|
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
|
# Insert driver_ebone in the chain without connected parents
|
||||||
driver_ebone.connected = False
|
driver_ebone.connected = False
|
||||||
driver_ebone.parent = child_ebone.parent
|
driver_ebone.parent = child_ebone.parent
|
||||||
@@ -129,7 +145,7 @@ def main(obj, orig_bone_name):
|
|||||||
bpy.ops.object.mode_set(mode='OBJECT')
|
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)
|
arm, control_pbone, control_bone= get_bone_data(obj, control_bone_name)
|
||||||
|
|
||||||
|
|
||||||
@@ -199,3 +215,5 @@ def main(obj, orig_bone_name):
|
|||||||
|
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
|
# no blending the result of this
|
||||||
|
return None
|
||||||
|
|||||||
@@ -17,9 +17,11 @@
|
|||||||
# ##### END GPL LICENSE BLOCK #####
|
# ##### END GPL LICENSE BLOCK #####
|
||||||
|
|
||||||
import bpy
|
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
|
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():
|
def metarig_template():
|
||||||
# generated by rigify.write_meta_rig
|
# generated by rigify.write_meta_rig
|
||||||
bpy.ops.object.mode_set(mode='EDIT')
|
bpy.ops.object.mode_set(mode='EDIT')
|
||||||
@@ -65,37 +67,60 @@ def metarig_template():
|
|||||||
pbone = obj.pose.bones['thigh']
|
pbone = obj.pose.bones['thigh']
|
||||||
pbone['type'] = 'leg'
|
pbone['type'] = 'leg'
|
||||||
|
|
||||||
|
def metarig_definition(obj, orig_bone_name):
|
||||||
def validate(obj, orig_bone_name):
|
|
||||||
'''
|
'''
|
||||||
The bone given is the first in a chain
|
The bone given is the first in a chain
|
||||||
Expects a chain of at least 3 children.
|
Expects a chain of at least 3 children.
|
||||||
eg.
|
eg.
|
||||||
thigh -> shin -> foot -> [toe, heel]
|
thigh -> shin -> foot -> [toe, heel]
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
bone_definition = []
|
||||||
|
|
||||||
orig_bone = obj.data.bones[orig_bone_name]
|
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
|
bone = orig_bone
|
||||||
chain = 0
|
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
|
children = bone.children
|
||||||
|
|
||||||
if len(children) != 1:
|
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 = children[0]
|
||||||
|
bone_definition.append(bone.name) # shin, foot
|
||||||
chain += 1
|
chain += 1
|
||||||
|
|
||||||
children = bone.children
|
children = bone.children
|
||||||
# Now there must be 2 children, only one connected
|
# Now there must be 2 children, only one connected
|
||||||
if len(children) != 2:
|
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:
|
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
|
||||||
|
|
||||||
|
|
||||||
def main(obj, orig_bone_name):
|
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 ik(obj, bone_definition, base_names):
|
||||||
from Mathutils import Vector
|
from Mathutils import Vector
|
||||||
arm = obj.data
|
arm = obj.data
|
||||||
|
|
||||||
@@ -107,55 +132,26 @@ def main(obj, orig_bone_name):
|
|||||||
# children of ik_foot
|
# children of ik_foot
|
||||||
ik = bone_class_instance(obj, ["foot", "foot_roll", "foot_roll_01", "foot_roll_02", "knee_target"])
|
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]
|
# XXX - duplicate below
|
||||||
mt_chain.thigh = orig_bone_name
|
for bone_class in (mt, mt_chain):
|
||||||
|
for attr in bone_class.attr_names:
|
||||||
mt.hips_e = mt_chain.thigh_e.parent
|
i = METARIG_NAMES.index(attr)
|
||||||
mt.hips_e.name = "ORG-" + mt.hips_e.name
|
ebone = arm.edit_bones[bone_definition[i]]
|
||||||
mt.hips = mt.hips_e.name
|
setattr(bone_class, attr, ebone.name)
|
||||||
|
bone_class.update()
|
||||||
mt_chain.shin_e = mt_chain.thigh_e.children[0]
|
# XXX - end dupe
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Make a new chain, ORG are the original bones renamed.
|
# Make a new chain, ORG are the original bones renamed.
|
||||||
fk_chain = mt_chain.copy(from_prefix="ORG-") # fk has no prefix!
|
ik_chain = mt_chain.copy(to_prefix="MCH-")
|
||||||
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
|
|
||||||
|
|
||||||
# simple rename
|
# simple rename
|
||||||
ik_chain.rename("thigh", ik_chain.thigh + "_ik")
|
ik_chain.rename("thigh", ik_chain.thigh + "_ik")
|
||||||
ik_chain.rename("shin", ik_chain.shin + "_ik")
|
ik_chain.rename("shin", ik_chain.shin + "_ik")
|
||||||
|
|
||||||
# ik foot, no parents
|
# ik foot, no parents
|
||||||
base_foot_name = fk_chain.foot # whatever the foot is called, use that!
|
base_foot_name = base_names[mt_chain.foot] # whatever the foot is called, use that!, XXX - ORG!
|
||||||
ik.foot_e = copy_bone_simple(arm, fk_chain.foot, "%s_ik" % base_foot_name)
|
ik.foot_e = copy_bone_simple(arm, mt_chain.foot, "%s_ik" % base_foot_name)
|
||||||
ik.foot = ik.foot_e.name
|
ik.foot = ik.foot_e.name
|
||||||
ik.foot_e.tail.z = ik.foot_e.head.z
|
ik.foot_e.tail.z = ik.foot_e.head.z
|
||||||
ik.foot_e.roll = 0.0
|
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
|
# rename 'MCH-toe' --> to 'toe_ik' and make the child of ik.foot_roll_01
|
||||||
# ------------------ FK or IK?
|
# ------------------ 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.connected = False
|
||||||
ik_chain.toe_e.parent = ik.foot_roll_01_e
|
ik_chain.toe_e.parent = ik.foot_roll_01_e
|
||||||
|
|
||||||
@@ -213,43 +209,6 @@ def main(obj, orig_bone_name):
|
|||||||
ex.update()
|
ex.update()
|
||||||
mt_chain.update()
|
mt_chain.update()
|
||||||
ik_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
|
# IK
|
||||||
con = ik_chain.shin_p.constraints.new('IK')
|
con = ik_chain.shin_p.constraints.new('IK')
|
||||||
@@ -290,3 +249,79 @@ def main(obj, orig_bone_name):
|
|||||||
else:
|
else:
|
||||||
con.minimum_x = -180.0 # XXX -deg
|
con.minimum_x = -180.0 # XXX -deg
|
||||||
con.maximum_x = 0.0
|
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
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ import bpy
|
|||||||
from rigify import bone_class_instance, copy_bone_simple
|
from rigify import bone_class_instance, copy_bone_simple
|
||||||
from rna_prop_ui import rna_idprop_ui_prop_get
|
from rna_prop_ui import rna_idprop_ui_prop_get
|
||||||
|
|
||||||
|
# not used, defined for completeness
|
||||||
|
METARIG_NAMES = ("body", "head")
|
||||||
|
|
||||||
def metarig_template():
|
def metarig_template():
|
||||||
bpy.ops.object.mode_set(mode='EDIT')
|
bpy.ops.object.mode_set(mode='EDIT')
|
||||||
@@ -72,30 +74,43 @@ def metarig_template():
|
|||||||
pbone['type'] = 'neck'
|
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
|
from Mathutils import Vector
|
||||||
|
|
||||||
arm = obj.data
|
arm = obj.data
|
||||||
|
|
||||||
# Initialize container classes for convenience
|
# Initialize container classes for convenience
|
||||||
mt = bone_class_instance(obj, ["body", "head"]) # meta
|
mt = bone_class_instance(obj, ["body", "head"]) # meta
|
||||||
mt.head = orig_bone_name
|
mt.body = bone_definition[0]
|
||||||
mt.update()
|
mt.head = bone_definition[1]
|
||||||
mt.body = mt.head_e.parent.name
|
|
||||||
mt.update()
|
mt.update()
|
||||||
|
|
||||||
# child chain of the 'head'
|
neck_chain = bone_definition[2:]
|
||||||
children = mt.head_e.children
|
|
||||||
if len(children) != 1:
|
|
||||||
print("expected the head to have only 1 child.")
|
|
||||||
|
|
||||||
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?
|
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):
|
for i, attr in enumerate(mt_chain.attr_names):
|
||||||
setattr(mt_chain, ("neck_%.2d" % (i + 1)), child_name)
|
setattr(mt_chain, attr, neck_chain[i])
|
||||||
mt_chain.update()
|
mt_chain.update()
|
||||||
|
|
||||||
neck_chain_basename = mt_chain.neck_01_e.basename
|
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.head.y += head_length / 4.0
|
||||||
mt.head_e.tail.y += head_length / 4.0
|
mt.head_e.tail.y += head_length / 4.0
|
||||||
|
|
||||||
for i in range(len(neck_chain)):
|
for i, attr in enumerate(mt_chain.attr_names):
|
||||||
neck_e = getattr(mt_chain, "neck_%.2d_e" % (i + 1))
|
neck_e = getattr(mt_chain, attr + "_e")
|
||||||
|
|
||||||
# dont store parent names, re-reference as each chain bones parent.
|
# dont store parent names, re-reference as each chain bones parent.
|
||||||
neck_e_parent = arm.edit_bones.new("MCH-rot_%s" % neck_e.name)
|
neck_e_parent = arm.edit_bones.new("MCH-rot_%s" % neck_e.name)
|
||||||
@@ -206,8 +221,8 @@ def main(obj, orig_bone_name):
|
|||||||
expression_suffix = "/max(0.001,%s)" % "+".join(target_names)
|
expression_suffix = "/max(0.001,%s)" % "+".join(target_names)
|
||||||
|
|
||||||
|
|
||||||
for i in range(len(neck_chain)):
|
for i, attr in enumerate(mt_chain.attr_names):
|
||||||
neck_p = getattr(mt_chain, "neck_%.2d_p" % (i + 1))
|
neck_p = getattr(mt_chain, attr + "_p")
|
||||||
neck_p.lock_location = True, True, True
|
neck_p.lock_location = True, True, True
|
||||||
neck_p.lock_location = True, True, True
|
neck_p.lock_location = True, True, True
|
||||||
neck_p.lock_rotations_4d = True
|
neck_p.lock_rotations_4d = True
|
||||||
@@ -243,3 +258,6 @@ def main(obj, orig_bone_name):
|
|||||||
tar.id_type = 'OBJECT'
|
tar.id_type = 'OBJECT'
|
||||||
tar.id = obj
|
tar.id = obj
|
||||||
tar.rna_path = head_driver_path + ('["bend_%.2d"]' % (j + 1))
|
tar.rna_path = head_driver_path + ('["bend_%.2d"]' % (j + 1))
|
||||||
|
|
||||||
|
# no blending the result of this
|
||||||
|
return None
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ import bpy
|
|||||||
from rigify import get_bone_data, copy_bone_simple
|
from rigify import get_bone_data, copy_bone_simple
|
||||||
from rna_prop_ui import rna_idprop_ui_get, rna_idprop_ui_prop_get
|
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():
|
def metarig_template():
|
||||||
bpy.ops.object.mode_set(mode='EDIT')
|
bpy.ops.object.mode_set(mode='EDIT')
|
||||||
@@ -72,20 +74,39 @@ def metarig_template():
|
|||||||
pbone['type'] = 'palm'
|
pbone['type'] = 'palm'
|
||||||
|
|
||||||
|
|
||||||
def main(obj, orig_bone_name):
|
def metarig_definition(obj, orig_bone_name):
|
||||||
arm, palm_pbone, palm_ebone = get_bone_data(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 = [ebone.name for ebone in palm_ebone.children]
|
||||||
children.sort() # simply assume the pinky has the lowest name
|
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
|
# Make a copy of the pinky
|
||||||
|
# simply assume the pinky has the lowest name
|
||||||
pinky_ebone = arm.edit_bones[children[0]]
|
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_ebone = copy_bone_simple(arm, pinky_ebone.name, "palm_control", parent=True)
|
||||||
control_name = control_ebone.name
|
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.translate(offset)
|
||||||
control_ebone.tail += offset
|
|
||||||
|
|
||||||
bpy.ops.object.mode_set(mode='OBJECT')
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
|
|
||||||
@@ -180,3 +201,5 @@ def main(obj, orig_bone_name):
|
|||||||
child_pbone = obj.pose.bones[children[-1]]
|
child_pbone = obj.pose.bones[children[-1]]
|
||||||
child_pbone.rotation_mode = 'QUATERNION'
|
child_pbone.rotation_mode = 'QUATERNION'
|
||||||
|
|
||||||
|
# no blending the result of this
|
||||||
|
return None
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ import bpy
|
|||||||
from rigify import bone_class_instance, copy_bone_simple
|
from rigify import bone_class_instance, copy_bone_simple
|
||||||
from rna_prop_ui import rna_idprop_ui_prop_get
|
from rna_prop_ui import rna_idprop_ui_prop_get
|
||||||
|
|
||||||
|
# not used, defined for completeness
|
||||||
|
METARIG_NAMES = ("pelvis", "ribcage")
|
||||||
|
|
||||||
def metarig_template():
|
def metarig_template():
|
||||||
bpy.ops.object.mode_set(mode='EDIT')
|
bpy.ops.object.mode_set(mode='EDIT')
|
||||||
@@ -84,30 +86,32 @@ def metarig_template():
|
|||||||
pbone['type'] = 'spine'
|
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.
|
The bone given is the second in a chain.
|
||||||
Expects at least 1 parent and a chain of children withe the same basename
|
Expects at least 1 parent and a chain of children withe the same basename
|
||||||
eg.
|
eg.
|
||||||
pelvis -> rib_cage -> spine.01 -> spine.02 -> spine.03
|
pelvis -> rib_cage -> spine.01 -> spine.02 -> spine.03
|
||||||
|
|
||||||
|
note: same as neck.
|
||||||
'''
|
'''
|
||||||
orig_bone = obj.data.bones[orig_bone_name]
|
arm = obj.data
|
||||||
if not orig_bone.parent:
|
ribcage = arm.bones[orig_bone_name]
|
||||||
return "expected spine bone '%s' to have a parent" % orig_bone_name
|
pelvis = ribcage.parent
|
||||||
|
|
||||||
children = orig_bone.children
|
|
||||||
|
|
||||||
|
children = ribcage.children
|
||||||
if len(children) != 1:
|
if len(children) != 1:
|
||||||
return "expected spine bone '%s' to have only 1 child for the sine chain" % orig_bone_name
|
print("expected the ribcage to have only 1 child.")
|
||||||
|
|
||||||
children_spine = children[0].children_recursive_basename
|
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
|
||||||
|
|
||||||
if len(children_spine) == 0:
|
def fk(*args):
|
||||||
return "expected '%s' to define a chain of children with its basename (2 or more)" % children[0]
|
main(*args)
|
||||||
|
|
||||||
return ''
|
def main(obj, bone_definition, base_names):
|
||||||
|
|
||||||
def main(obj, orig_bone_name):
|
|
||||||
from Mathutils import Vector, Matrix, RotationMatrix
|
from Mathutils import Vector, Matrix, RotationMatrix
|
||||||
from math import radians, pi
|
from math import radians, pi
|
||||||
|
|
||||||
@@ -115,17 +119,26 @@ def main(obj, orig_bone_name):
|
|||||||
|
|
||||||
# Initialize container classes for convenience
|
# Initialize container classes for convenience
|
||||||
mt = bone_class_instance(obj, ["pelvis", "ribcage"]) # meta
|
mt = bone_class_instance(obj, ["pelvis", "ribcage"]) # meta
|
||||||
mt.ribcage = orig_bone_name
|
mt.pelvis = bone_definition[0]
|
||||||
mt.update()
|
mt.ribcage = bone_definition[1]
|
||||||
mt.pelvis = mt.ribcage_e.parent.name
|
|
||||||
mt.update()
|
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
|
children = mt.ribcage_e.children
|
||||||
child = children[0] # validate checks for 1 only.
|
child = children[0] # validate checks for 1 only.
|
||||||
spine_chain_basename = child.basename # probably 'spine'
|
spine_chain_basename = child.basename # probably 'spine'
|
||||||
spine_chain_segment_length = child.length
|
spine_chain_segment_length = child.length
|
||||||
spine_chain = [child] + child.children_recursive_basename
|
spine_chain = [child] + child.children_recursive_basename
|
||||||
spine_chain_orig = [child.name for child in spine_chain]
|
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
|
child.parent = mt.pelvis_e # was mt.ribcage
|
||||||
|
|
||||||
# The first bone in the chain happens to be the basis of others, create them now
|
# 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_*)
|
# - original (ORG_*)
|
||||||
# - copy (*use original name*)
|
# - copy (*use original name*)
|
||||||
# - reverse (MCH-rev_*)
|
# - 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_*
|
mt_chain = bone_class_instance(obj, spine_chain_attrs) # ORG_*
|
||||||
rv_chain = bone_class_instance(obj, spine_chain_attrs) # *
|
rv_chain = bone_class_instance(obj, spine_chain_attrs) # *
|
||||||
ex_chain = bone_class_instance(obj, spine_chain_attrs) # MCH-rev_*
|
ex_chain = bone_class_instance(obj, spine_chain_attrs) # MCH-rev_*
|
||||||
|
del spine_chain_attrs
|
||||||
|
|
||||||
for i, child_name in enumerate(spine_chain):
|
for i, child_name in enumerate(spine_chain):
|
||||||
child_name_orig = spine_chain_orig[i]
|
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
|
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
|
# Now we need to re-parent these chains
|
||||||
for i, child_name in enumerate(spine_chain_orig):
|
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:
|
if i == 0:
|
||||||
getattr(ex_chain, attr).parent = mt.pelvis_e
|
getattr(ex_chain, attr).parent = mt.pelvis_e
|
||||||
else:
|
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)
|
getattr(ex_chain, attr).parent = getattr(ex_chain, attr_parent)
|
||||||
|
|
||||||
# intentional! get the parent from the other paralelle chain member
|
# 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!
|
# ex_chain needs to interlace bones!
|
||||||
# Note, skip the first bone
|
# 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]
|
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.
|
# dont store parent names, re-reference as each chain bones parent.
|
||||||
spine_e_parent = arm.edit_bones.new("MCH-rot_%s" % child_name_orig)
|
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.tail = spine_e.head + Vector(0.0, 0.0, spine_chain_segment_length / 2.0)
|
||||||
spine_e_parent.roll = 0.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
|
orig_parent = spine_e.parent
|
||||||
spine_e.connected = False
|
spine_e.connected = False
|
||||||
spine_e.parent = spine_e_parent
|
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
|
# 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
|
pivot = (rv_chain.spine_01_e.head + rv_chain.spine_01_e.tail) * 0.5
|
||||||
matrix = RotationMatrix(radians(180), 3, 'X')
|
matrix = RotationMatrix(radians(180), 3, 'X')
|
||||||
for i in range(len(spine_chain_attrs)): # similar to neck
|
for i, attr in enumerate(rv_chain.attr_names): # similar to neck
|
||||||
spine_e = getattr(rv_chain, spine_chain_attrs[i] + "_e")
|
spine_e = getattr(rv_chain, attr + "_e")
|
||||||
# use the first bone as the pivot
|
# use the first bone as the pivot
|
||||||
|
|
||||||
spine_e.head = ((spine_e.head - pivot) * matrix) + 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
|
# ex.ribcage_p / MCH-wgt_rib_cage
|
||||||
con = ex.ribcage_p.constraints.new('COPY_LOCATION')
|
con = ex.ribcage_p.constraints.new('COPY_LOCATION')
|
||||||
con.target = obj
|
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.head_tail = 0.0
|
||||||
|
|
||||||
con = ex.ribcage_p.constraints.new('COPY_ROTATION')
|
con = ex.ribcage_p.constraints.new('COPY_ROTATION')
|
||||||
con.target = obj
|
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
|
# mt.pelvis_p / rib_cage
|
||||||
con = mt.ribcage_p.constraints.new('COPY_LOCATION')
|
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)
|
prop = rna_idprop_ui_prop_get(mt.ribcage_p, "pivot_slide", create=True)
|
||||||
mt.ribcage_p["pivot_slide"] = 0.5
|
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
|
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_name = "bend_%.2d" % (i + 1)
|
||||||
prop = rna_idprop_ui_prop_get(mt.ribcage_p, prop_name, create=True)
|
prop = rna_idprop_ui_prop_get(mt.ribcage_p, prop_name, create=True)
|
||||||
mt.ribcage_p[prop_name] = 1.0
|
mt.ribcage_p[prop_name] = 1.0
|
||||||
@@ -361,9 +375,9 @@ def main(obj, orig_bone_name):
|
|||||||
# positioned at the tip.
|
# positioned at the tip.
|
||||||
|
|
||||||
# reverse bones / MCH-rev_spine.##
|
# reverse bones / MCH-rev_spine.##
|
||||||
for i in range(1, len(spine_chain_attrs)):
|
for i in range(1, spine_chain_len):
|
||||||
spine_p = getattr(rv_chain, spine_chain_attrs[i] + "_p")
|
spine_p = getattr(rv_chain, rv_chain.attr_names[i] + "_p")
|
||||||
spine_fake_parent_name = getattr(rv_chain, spine_chain_attrs[i - 1])
|
spine_fake_parent_name = getattr(rv_chain, rv_chain.attr_names[i - 1])
|
||||||
|
|
||||||
con = spine_p.constraints.new('COPY_LOCATION')
|
con = spine_p.constraints.new('COPY_LOCATION')
|
||||||
con.target = obj
|
con.target = obj
|
||||||
@@ -375,14 +389,14 @@ def main(obj, orig_bone_name):
|
|||||||
# Constrain 'inbetween' bones
|
# Constrain 'inbetween' bones
|
||||||
|
|
||||||
# b01/max(0.001,b01+b02+b03+b04+b05)
|
# 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)
|
expression_suffix = "/max(0.001,%s)" % "+".join(target_names)
|
||||||
|
|
||||||
rib_driver_path = mt.ribcage_p.path_to_id()
|
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
|
spine_p_parent = spine_p.parent # interlaced bone
|
||||||
|
|
||||||
con = spine_p_parent.constraints.new('COPY_ROTATION')
|
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
|
driver.expression = target_names[i - 1] + expression_suffix
|
||||||
fcurve.modifiers.remove(0) # grr dont need a modifier
|
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 = driver.targets.new()
|
||||||
tar.name = target_names[j]
|
tar.name = target_names[j]
|
||||||
tar.id_type = 'OBJECT'
|
tar.id_type = 'OBJECT'
|
||||||
@@ -410,12 +424,12 @@ def main(obj, orig_bone_name):
|
|||||||
|
|
||||||
# original bone drivers
|
# original bone drivers
|
||||||
# note: the first bone has a lot more constraints, but also this simple one is first.
|
# note: the first bone has a lot more constraints, but also this simple one is first.
|
||||||
for i in range(len(spine_chain_attrs)):
|
for i in attr, enumerate(mt_chain.attr_names):
|
||||||
spine_p = getattr(mt_chain, spine_chain_attrs[i] + "_p")
|
spine_p = getattr(mt_chain, attr + "_p")
|
||||||
|
|
||||||
con = spine_p.constraints.new('COPY_ROTATION')
|
con = spine_p.constraints.new('COPY_ROTATION')
|
||||||
con.target = obj
|
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
|
del spine_p
|
||||||
|
|
||||||
# pivot slide: - lots of copy location constraints.
|
# pivot slide: - lots of copy location constraints.
|
||||||
@@ -425,19 +439,19 @@ def main(obj, orig_bone_name):
|
|||||||
con.target = obj
|
con.target = obj
|
||||||
con.subtarget = rv_chain.spine_01 # lock to the reverse location
|
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 = mt_chain.spine_01_p.constraints.new('COPY_LOCATION')
|
||||||
con.name = "slide_%d" % i
|
con.name = "slide_%d" % i
|
||||||
con.target = obj
|
con.target = obj
|
||||||
|
|
||||||
if i == len(spine_chain_attrs):
|
if i == spine_chain_len:
|
||||||
attr = spine_chain_attrs[i - 1]
|
attr = mt_chain.attr_names[i - 1]
|
||||||
else:
|
else:
|
||||||
attr = spine_chain_attrs[i]
|
attr = mt_chain.attr_names[i]
|
||||||
|
|
||||||
con.subtarget = getattr(rv_chain, attr) # lock to the reverse location
|
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
|
con.head_tail = 1.0
|
||||||
|
|
||||||
fcurve = con.driver_add("influence", 0)
|
fcurve = con.driver_add("influence", 0)
|
||||||
@@ -452,5 +466,8 @@ def main(obj, orig_bone_name):
|
|||||||
mod = fcurve.modifiers[0]
|
mod = fcurve.modifiers[0]
|
||||||
mod.poly_order = 1
|
mod.poly_order = 1
|
||||||
mod.coefficients[0] = - (i - 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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user