Adds a new set of bones to rig types which are to be used for weight paint vgroups, in some these have some more segments to account for twist. also use Aligoriths new copy transform constraint.
225 lines
7.5 KiB
Python
225 lines
7.5 KiB
Python
# ##### BEGIN GPL LICENSE BLOCK #####
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software Foundation,
|
|
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
#
|
|
# ##### END GPL LICENSE BLOCK #####
|
|
|
|
# <pep8 compliant>
|
|
|
|
import bpy
|
|
from rigify import RigifyError
|
|
from rigify_utils import bone_class_instance, copy_bone_simple, add_pole_target_bone
|
|
from Mathutils import Vector
|
|
|
|
METARIG_NAMES = "hips", "thigh", "shin", "foot", "toe"
|
|
|
|
|
|
def metarig_template():
|
|
# generated by rigify.write_meta_rig
|
|
bpy.ops.object.mode_set(mode='EDIT')
|
|
obj = bpy.context.active_object
|
|
arm = obj.data
|
|
bone = arm.edit_bones.new('body')
|
|
bone.head[:] = -0.0728, -0.2427, 0.0000
|
|
bone.tail[:] = -0.0728, -0.2427, 0.2427
|
|
bone.roll = 0.0000
|
|
bone.connected = False
|
|
bone = arm.edit_bones.new('thigh')
|
|
bone.head[:] = 0.0000, 0.0000, -0.0000
|
|
bone.tail[:] = 0.0813, -0.2109, -0.3374
|
|
bone.roll = -0.4656
|
|
bone.connected = False
|
|
bone.parent = arm.edit_bones['body']
|
|
bone = arm.edit_bones.new('shin')
|
|
bone.head[:] = 0.0813, -0.2109, -0.3374
|
|
bone.tail[:] = 0.0714, -0.0043, -0.5830
|
|
bone.roll = -0.2024
|
|
bone.connected = True
|
|
bone.parent = arm.edit_bones['thigh']
|
|
bone = arm.edit_bones.new('foot')
|
|
bone.head[:] = 0.0714, -0.0043, -0.5830
|
|
bone.tail[:] = 0.0929, -0.0484, -0.7652
|
|
bone.roll = -0.3766
|
|
bone.connected = True
|
|
bone.parent = arm.edit_bones['shin']
|
|
bone = arm.edit_bones.new('toe')
|
|
bone.head[:] = 0.0929, -0.0484, -0.7652
|
|
bone.tail[:] = 0.1146, -0.1244, -0.7652
|
|
bone.roll = -0.0000
|
|
bone.connected = True
|
|
bone.parent = arm.edit_bones['foot']
|
|
|
|
bpy.ops.object.mode_set(mode='OBJECT')
|
|
pbone = obj.pose.bones['thigh']
|
|
pbone['type'] = 'leg_quadruped_generic'
|
|
|
|
|
|
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 RigifyError("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
|
|
children = bone.children
|
|
|
|
if len(children) != 1:
|
|
raise RigifyError("expected the thigh bone to have 3 children without a fork")
|
|
bone = children[0]
|
|
bone_definition.append(bone.name) # shin, foot
|
|
chain += 1
|
|
|
|
if len(bone_definition) != len(METARIG_NAMES):
|
|
raise RigifyError("internal problem, expected %d bones" % len(METARIG_NAMES))
|
|
|
|
return bone_definition
|
|
|
|
|
|
def ik(obj, bone_definition, base_names, options):
|
|
arm = obj.data
|
|
|
|
# setup the existing bones, use names from METARIG_NAMES
|
|
mt = bone_class_instance(obj, ["hips"])
|
|
mt_chain = bone_class_instance(obj, ["thigh", "shin", "foot", "toe"])
|
|
|
|
mt.attr_initialize(METARIG_NAMES, bone_definition)
|
|
mt_chain.attr_initialize(METARIG_NAMES, bone_definition)
|
|
|
|
ik_chain = mt_chain.copy(to_fmt="%s", base_names=base_names)
|
|
|
|
ik_chain.thigh_e.connected = False
|
|
ik_chain.thigh_e.parent = mt.hips_e
|
|
|
|
ik_chain.foot_e.parent = None
|
|
ik_chain.rename("foot", get_base_name(ik_chain.foot) + "_ik" + get_side_name(ik_chain.foot))
|
|
|
|
# keep the foot_ik as the parent
|
|
ik_chain.toe_e.connected = False
|
|
|
|
# must be after disconnecting the toe
|
|
ik_chain.foot_e.align_orientation(mt_chain.toe_e)
|
|
|
|
# children of ik_foot
|
|
ik = bone_class_instance(obj, ["foot", "foot_roll", "foot_roll_01", "foot_roll_02", "knee_target", "foot_target"])
|
|
|
|
ik.knee_target = add_pole_target_bone(obj, mt_chain.shin, "knee_target" + get_side_name(base_names[mt_chain.foot])) #XXX - pick a better name
|
|
ik.update()
|
|
ik.knee_target_e.parent = mt.hips_e
|
|
|
|
# foot roll is an interesting one!
|
|
# plot a vector from the toe bones head, bactwards to the length of the foot
|
|
# then align it with the foot but reverse direction.
|
|
ik.foot_roll_e = copy_bone_simple(arm, mt_chain.toe, get_base_name(base_names[mt_chain.foot]) + "_roll" + get_side_name(base_names[mt_chain.foot]))
|
|
ik.foot_roll = ik.foot_roll_e.name
|
|
ik.foot_roll_e.parent = ik_chain.foot_e
|
|
ik.foot_roll_e.translate(- (mt_chain.toe_e.vector.normalize() * mt_chain.foot_e.length))
|
|
ik.foot_roll_e.align_orientation(mt_chain.foot_e)
|
|
ik.foot_roll_e.tail = ik.foot_roll_e.head - ik.foot_roll_e.vector # flip
|
|
ik.foot_roll_e.align_roll(mt_chain.foot_e.matrix.rotationPart() * Vector(0.0, 0.0, -1.0))
|
|
|
|
# MCH-foot
|
|
ik.foot_roll_01_e = copy_bone_simple(arm, mt_chain.foot, "MCH-" + base_names[mt_chain.foot])
|
|
ik.foot_roll_01 = ik.foot_roll_01_e.name
|
|
ik.foot_roll_01_e.parent = ik_chain.foot_e
|
|
ik.foot_roll_01_e.head, ik.foot_roll_01_e.tail = mt_chain.foot_e.tail, mt_chain.foot_e.head
|
|
ik.foot_roll_01_e.roll = ik.foot_roll_e.roll
|
|
|
|
# ik_target, child of MCH-foot
|
|
ik.foot_target_e = copy_bone_simple(arm, mt_chain.foot, base_names[mt_chain.foot] + "_ik_target")
|
|
ik.foot_target = ik.foot_target_e.name
|
|
ik.foot_target_e.parent = ik.foot_roll_01_e
|
|
ik.foot_target_e.align_orientation(ik_chain.foot_e)
|
|
ik.foot_target_e.length = ik_chain.foot_e.length / 2.0
|
|
ik.foot_target_e.connected = True
|
|
|
|
# MCH-foot.02 child of MCH-foot
|
|
ik.foot_roll_02_e = copy_bone_simple(arm, mt_chain.foot, "MCH-%s_02" % base_names[mt_chain.foot])
|
|
ik.foot_roll_02 = ik.foot_roll_02_e.name
|
|
ik.foot_roll_02_e.parent = ik.foot_roll_01_e
|
|
|
|
|
|
bpy.ops.object.mode_set(mode='OBJECT')
|
|
|
|
mt.update()
|
|
mt_chain.update()
|
|
ik.update()
|
|
ik_chain.update()
|
|
|
|
# simple constraining of orig bones
|
|
con = mt_chain.thigh_p.constraints.new('COPY_TRANSFORMS')
|
|
con.target = obj
|
|
con.subtarget = ik_chain.thigh
|
|
|
|
con = mt_chain.shin_p.constraints.new('COPY_TRANSFORMS')
|
|
con.target = obj
|
|
con.subtarget = ik_chain.shin
|
|
|
|
con = mt_chain.foot_p.constraints.new('COPY_TRANSFORMS')
|
|
con.target = obj
|
|
con.subtarget = ik.foot_roll_02
|
|
|
|
con = mt_chain.toe_p.constraints.new('COPY_TRANSFORMS')
|
|
con.target = obj
|
|
con.subtarget = ik_chain.toe
|
|
|
|
# others...
|
|
con = ik.foot_roll_01_p.constraints.new('COPY_ROTATION')
|
|
con.target = obj
|
|
con.subtarget = ik.foot_roll
|
|
|
|
|
|
# IK
|
|
con = ik_chain.shin_p.constraints.new('IK')
|
|
con.chain_length = 2
|
|
con.iterations = 500
|
|
con.pole_angle = -90.0 # XXX - in deg!
|
|
con.use_tail = True
|
|
con.use_stretch = True
|
|
con.use_target = True
|
|
con.use_rotation = False
|
|
con.weight = 1.0
|
|
|
|
con.target = obj
|
|
con.subtarget = ik.foot_target
|
|
|
|
con.pole_target = obj
|
|
con.pole_subtarget = ik.knee_target
|
|
|
|
|
|
bpy.ops.object.mode_set(mode='EDIT')
|
|
|
|
return None, ik_chain.thigh, ik_chain.shin, ik_chain.foot, ik_chain.toe
|
|
|
|
|
|
def main(obj, bone_definition, base_names, options):
|
|
bones_ik = ik(obj, bone_definition, base_names, options)
|
|
return bones_ik
|