diff options
Diffstat (limited to 'rigify/rigs/biped/leg/deform.py')
-rw-r--r-- | rigify/rigs/biped/leg/deform.py | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/rigify/rigs/biped/leg/deform.py b/rigify/rigs/biped/leg/deform.py new file mode 100644 index 00000000..bb6b6f39 --- /dev/null +++ b/rigify/rigs/biped/leg/deform.py @@ -0,0 +1,263 @@ +#====================== 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +#======================= END GPL LICENSE BLOCK ======================== + +import bpy +from math import acos, degrees +from mathutils import Vector, Matrix +from rigify.utils import MetarigError +from rigify.utils import copy_bone, flip_bone, put_bone +from rigify.utils import connected_children_names, has_connected_children +from rigify.utils import strip_org, make_mechanism_name, make_deformer_name + + +def align_roll(obj, bone1, bone2): + bone1_e = obj.data.edit_bones[bone1] + bone2_e = obj.data.edit_bones[bone2] + + bone1_e.roll = 0.0 + + # Get the directions the bones are pointing in, as vectors + y1 = bone1_e.y_axis + x1 = bone1_e.x_axis + y2 = bone2_e.y_axis + x2 = bone2_e.x_axis + + # Get the shortest axis to rotate bone1 on to point in the same direction as bone2 + axis = y1.cross(y2) + axis.normalize() + + # Angle to rotate on that shortest axis + angle = y1.angle(y2) + + # Create rotation matrix to make bone1 point in the same direction as bone2 + rot_mat = Matrix.Rotation(angle, 3, axis) + + # Roll factor + x3 = x1 * rot_mat + dot = x2 * x3 + if dot > 1.0: + dot = 1.0 + elif dot < -1.0: + dot = -1.0 + roll = acos(dot) + + # Set the roll + bone1_e.roll = roll + + # Check if we rolled in the right direction + x3 = bone1_e.x_axis * rot_mat + check = x2 * x3 + + # If not, reverse + if check < 0.9999: + bone1_e.roll = -roll + + +class Rig: + """ A leg deform-bone setup. + + """ + def __init__(self, obj, bone, params): + """ Gather and validate data about the rig. + Store any data or references to data that will be needed later on. + In particular, store references to bones that will be needed, and + store names of bones that will be needed. + Do NOT change any data in the scene. This is a gathering phase only. + + """ + self.obj = obj + self.params = params + + # Get the chain of 2 connected bones + leg_bones = [bone] + connected_children_names(self.obj, bone)[:2] + + if len(leg_bones) != 2: + raise MetarigError("RIGIFY ERROR: Bone '%s': incorrect bone configuration for rig type." % (strip_org(bone))) + + # Get the foot and heel + foot = None + heel = None + for b in self.obj.data.bones[leg_bones[1]].children: + if b.use_connect == True: + if len(b.children) >= 1 and has_connected_children(b): + foot = b.name + else: + heel = b.name + + if foot is None or heel is None: + raise MetarigError("RIGIFY ERROR: Bone '%s': incorrect bone configuration for rig type." % (strip_org(bone))) + + # Get the toe + toe = None + for b in self.obj.data.bones[foot].children: + if b.use_connect == True: + toe = b.name + + if toe is None: + raise MetarigError("RIGIFY ERROR: Bone '%s': incorrect bone configuration for rig type." % (strip_org(bone))) + + self.org_bones = leg_bones + [foot, toe, heel] + + # Get rig parameters + self.use_thigh_twist = params.use_thigh_twist + self.use_shin_twist = params.use_shin_twist + + def generate(self): + """ Generate the rig. + Do NOT modify any of the original bones, except for adding constraints. + The main armature should be selected and active before this is called. + + """ + bpy.ops.object.mode_set(mode='EDIT') + + # Create upper arm bones + if self.use_thigh_twist: + thigh1 = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0] + ".01"))) + thigh2 = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0] + ".02"))) + utip = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(self.org_bones[0] + ".tip"))) + else: + thigh = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0]))) + + # Create forearm bones + if self.use_shin_twist: + shin1 = copy_bone(self.obj, self.org_bones[1], make_deformer_name(strip_org(self.org_bones[1] + ".01"))) + shin2 = copy_bone(self.obj, self.org_bones[1], make_deformer_name(strip_org(self.org_bones[1] + ".02"))) + stip = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(self.org_bones[1] + ".tip"))) + else: + shin = copy_bone(self.obj, self.org_bones[1], make_deformer_name(strip_org(self.org_bones[1]))) + + # Create foot bone + foot = copy_bone(self.obj, self.org_bones[2], make_deformer_name(strip_org(self.org_bones[2]))) + + # Create toe bone + toe = copy_bone(self.obj, self.org_bones[3], make_deformer_name(strip_org(self.org_bones[3]))) + + # Get edit bones + eb = self.obj.data.edit_bones + + org_thigh_e = eb[self.org_bones[0]] + if self.use_thigh_twist: + thigh1_e = eb[thigh1] + thigh2_e = eb[thigh2] + utip_e = eb[utip] + else: + thigh_e = eb[thigh] + + org_shin_e = eb[self.org_bones[1]] + if self.use_shin_twist: + shin1_e = eb[shin1] + shin2_e = eb[shin2] + stip_e = eb[stip] + else: + shin_e = eb[shin] + + org_foot_e = eb[self.org_bones[2]] + foot_e = eb[foot] + + org_toe_e = eb[self.org_bones[3]] + toe_e = eb[toe] + + # Parent and position thigh bones + if self.use_thigh_twist: + thigh1_e.use_connect = False + thigh2_e.use_connect = False + utip_e.use_connect = False + + thigh1_e.parent = org_thigh_e.parent + thigh2_e.parent = org_thigh_e + utip_e.parent = org_thigh_e + + center = Vector((org_thigh_e.head + org_thigh_e.tail) / 2) + + thigh1_e.tail = center + thigh2_e.head = center + put_bone(self.obj, utip, org_thigh_e.tail) + utip_e.length = org_thigh_e.length / 8 + else: + thigh_e.use_connect = False + thigh_e.parent = org_thigh_e + + # Parent and position shin bones + if self.use_shin_twist: + shin1_e.use_connect = False + shin2_e.use_connect = False + stip_e.use_connect = False + + shin1_e.parent = org_shin_e + shin2_e.parent = org_shin_e + stip_e.parent = org_shin_e + + center = Vector((org_shin_e.head + org_shin_e.tail) / 2) + + shin1_e.tail = center + shin2_e.head = center + put_bone(self.obj, stip, org_shin_e.tail) + stip_e.length = org_shin_e.length / 8 + + # Align roll of shin2 with foot + align_roll(self.obj, shin2, foot) + else: + shin_e.use_connect = False + shin_e.parent = org_shin_e + + # Parent foot + foot_e.use_connect = False + foot_e.parent = org_foot_e + + # Parent toe + toe_e.use_connect = False + toe_e.parent = org_toe_e + + # Object mode, get pose bones + bpy.ops.object.mode_set(mode='OBJECT') + pb = self.obj.pose.bones + + if self.use_thigh_twist: + thigh1_p = pb[thigh1] + if self.use_shin_twist: + shin2_p = pb[shin2] + foot_p = pb[foot] + + # Thigh constraints + if self.use_thigh_twist: + con = thigh1_p.constraints.new('COPY_LOCATION') + con.name = "copy_location" + con.target = self.obj + con.subtarget = self.org_bones[0] + + con = thigh1_p.constraints.new('COPY_SCALE') + con.name = "copy_scale" + con.target = self.obj + con.subtarget = self.org_bones[0] + + con = thigh1_p.constraints.new('DAMPED_TRACK') + con.name = "track_to" + con.target = self.obj + con.subtarget = utip + + # Shin constraints + if self.use_shin_twist: + con = shin2_p.constraints.new('COPY_ROTATION') + con.name = "copy_rotation" + con.target = self.obj + con.subtarget = foot + + con = shin2_p.constraints.new('DAMPED_TRACK') + con.name = "track_to" + con.target = self.obj + con.subtarget = stip |