[Bf-extensions-cvs] SVN commit: /data/svn/bf-extensions [1694] trunk/py/scripts/addons/rigify: Rigify:
Nathan Vegdahl
cessen at cessen.com
Thu Mar 10 10:18:10 CET 2011
Revision: 1694
http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-extensions&revision=1694
Author: cessen
Date: 2011-03-10 09:18:09 +0000 (Thu, 10 Mar 2011)
Log Message:
-----------
Rigify:
Clean-up of the IK/FK snapping code. Should be much more maintainable now.
Also changed rig id generation. Rig id's now consist of a random
alphanumeric string 8 characters long, with the smallest 8 digits of seconds
since the epoc (in hex) at the time of rig generation appended on the end.
This results in a 16-character string that is ludicrously unlikely to
have any collisions between rigs. 36^8 * 16^8, with the 16^8 being very well
distributed over time. Ah... paranoia.
Modified Paths:
--------------
trunk/py/scripts/addons/rigify/generate.py
trunk/py/scripts/addons/rigify/rig_ui_template.py
trunk/py/scripts/addons/rigify/ui.py
Modified: trunk/py/scripts/addons/rigify/generate.py
===================================================================
--- trunk/py/scripts/addons/rigify/generate.py 2011-03-10 06:01:25 UTC (rev 1693)
+++ trunk/py/scripts/addons/rigify/generate.py 2011-03-10 09:18:09 UTC (rev 1694)
@@ -52,8 +52,11 @@
"""
t = Timer()
- rig_id = random_string(12) # Random so that different rigs don't collide id's
+ # Random string with time appended so that
+ # different rigs don't collide id's
+ rig_id = random_string(8) + str(hex(int(time.time())))[2:][-8:].rjust(8, '0')
+
# Initial configuration
mode_orig = context.mode
rest_backup = metarig.data.pose_position
Modified: trunk/py/scripts/addons/rigify/rig_ui_template.py
===================================================================
--- trunk/py/scripts/addons/rigify/rig_ui_template.py 2011-03-10 06:01:25 UTC (rev 1693)
+++ trunk/py/scripts/addons/rigify/rig_ui_template.py 2011-03-10 09:18:09 UTC (rev 1694)
@@ -24,17 +24,21 @@
rig_id = "%s"
-def get_pose_matrix_in_other_space(mat, pbs):
- """ Returns the transform matrix relative to pbs's transform space.
- In other words, you could take the matrix returned from this, slap
- it into pbs, and it would have the same world transform as mat.
- This is with constraints applied.
+#########################################
+## "Visual Transform" helper functions ##
+#########################################
+
+def get_pose_matrix_in_other_space(mat, pose_bone):
+ """ Returns the transform matrix relative to pose_bone's current
+ transform space. In other words, presuming that mat is in
+ armature space, slapping the returned matrix onto pose_bone
+ should give it the armature-space transforms of mat.
"""
- rest_inv = pbs.bone.matrix_local.inverted()
+ rest_inv = pose_bone.bone.matrix_local.inverted()
- if pbs.parent:
- par_inv = pbs.parent.matrix.inverted()
- par_rest = pbs.parent.bone.matrix_local.copy()
+ if pose_bone.parent:
+ par_inv = pose_bone.parent.matrix.inverted()
+ par_rest = pose_bone.parent.bone.matrix_local.copy()
smat = rest_inv * (par_rest * (par_inv * mat))
else:
@@ -43,135 +47,130 @@
return smat
-def get_local_matrix_with_constraints(pose_bone):
- """ Returns the local matrix of the given pose bone, with constraints
- applied.
+def get_local_pose_matrix(pose_bone):
+ """ Returns the local transform matrix of the given pose bone.
"""
return get_pose_matrix_in_other_space(pose_bone.matrix, pose_bone)
-def set_pose_rotation(pb, mat):
- """ Sets the pose bone's rotation to the same rotation as the given matrix.
- Matrix should be given in local space.
- """
- q = mat.to_quaternion()
-
- if pb.rotation_mode == 'QUATERNION':
- pb.rotation_quaternion = q
- elif pb.rotation_mode == 'AXIS_ANGLE':
- pb.rotation_axis_angle[0] = q.angle
- pb.rotation_axis_angle[1] = q.axis[0]
- pb.rotation_axis_angle[2] = q.axis[1]
- pb.rotation_axis_angle[3] = q.axis[2]
- else:
- pb.rotation_euler = q.to_euler(pb.rotation_mode)
-
-
-def set_pose_scale(pb, mat):
- """ Sets the pose bone's scale to the same scale as the given matrix.
- Matrix should be given in local space.
- """
- pb.scale = mat.to_scale()
-
-
-def set_pose_translation(pb, mat):
+def set_pose_translation(pose_bone, mat):
""" Sets the pose bone's translation to the same translation as the given matrix.
- Matrix should be given in local space.
+ Matrix should be given in bone's local space.
"""
- if pb.bone.use_local_location == True:
- pb.location = mat.to_translation()
+ if pose_bone.bone.use_local_location == True:
+ pose_bone.location = mat.to_translation()
else:
loc = mat.to_translation()
- rest = pb.bone.matrix_local.copy()
- if pb.bone.parent:
- par_rest = pb.bone.parent.matrix_local.copy()
+ rest = pose_bone.bone.matrix_local.copy()
+ if pose_bone.bone.parent:
+ par_rest = pose_bone.bone.parent.matrix_local.copy()
else:
par_rest = Matrix()
q = (par_rest.inverted() * rest).to_quaternion()
- pb.location = loc * q
+ pose_bone.location = loc * q
-def fk2ik_arm(obj, fk, ik):
- """ Matches the fk bones in an arm rig to the ik bones.
+def set_pose_rotation(pose_bone, mat):
+ """ Sets the pose bone's rotation to the same rotation as the given matrix.
+ Matrix should be given in bone's local space.
"""
- pb = obj.pose.bones
+ q = mat.to_quaternion()
- uarm = pb[fk[0]]
- farm = pb[fk[1]]
- hand = pb[fk[2]]
+ if pose_bone.rotation_mode == 'QUATERNION':
+ pose_bone.rotation_quaternion = q
+ elif pose_bone.rotation_mode == 'AXIS_ANGLE':
+ pose_bone.rotation_axis_angle[0] = q.angle
+ pose_bone.rotation_axis_angle[1] = q.axis[0]
+ pose_bone.rotation_axis_angle[2] = q.axis[1]
+ pose_bone.rotation_axis_angle[3] = q.axis[2]
+ else:
+ pose_bone.rotation_euler = q.to_euler(pose_bone.rotation_mode)
- uarmi = pb[ik[0]]
- farmi = pb[ik[1]]
- handi = pb[ik[2]]
- uarmmat = get_pose_matrix_in_other_space(uarmi.matrix, uarm)
- set_pose_rotation(uarm, uarmmat)
- set_pose_scale(uarm, uarmmat)
- bpy.ops.object.mode_set(mode='OBJECT')
- bpy.ops.object.mode_set(mode='POSE')
+def set_pose_scale(pose_bone, mat):
+ """ Sets the pose bone's scale to the same scale as the given matrix.
+ Matrix should be given in bone's local space.
+ """
+ pose_bone.scale = mat.to_scale()
- farmmat = get_pose_matrix_in_other_space(farmi.matrix, farm)
- set_pose_rotation(farm, farmmat)
- set_pose_scale(farm, farmmat)
+
+def match_pose_translation(pose_bone, target_bone):
+ """ Matches pose_bone's visual translation to target_bone's visual
+ translation.
+ This function assumes you are in pose mode on the relevant armature.
+ """
+ mat = get_pose_matrix_in_other_space(target_bone.matrix, pose_bone)
+ set_pose_translation(pose_bone, mat)
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode='POSE')
- handmat = get_pose_matrix_in_other_space(handi.matrix, hand)
- set_pose_rotation(hand, handmat)
- set_pose_scale(hand, handmat)
+
+def match_pose_rotation(pose_bone, target_bone):
+ """ Matches pose_bone's visual rotation to target_bone's visual
+ rotation.
+ This function assumes you are in pose mode on the relevant armature.
+ """
+ mat = get_pose_matrix_in_other_space(target_bone.matrix, pose_bone)
+ set_pose_rotation(pose_bone, mat)
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode='POSE')
-def ik2fk_arm(obj, fk, ik):
- """ Matches the ik bones in an arm rig to the fk bones.
+def match_pose_scale(pose_bone, target_bone):
+ """ Matches pose_bone's visual scale to target_bone's visual
+ scale.
+ This function assumes you are in pose mode on the relevant armature.
"""
- pb = obj.pose.bones
+ mat = get_pose_matrix_in_other_space(target_bone.matrix, pose_bone)
+ set_pose_scale(pose_bone, mat)
+ bpy.ops.object.mode_set(mode='OBJECT')
+ bpy.ops.object.mode_set(mode='POSE')
- uarm = pb[fk[0]]
- farm = pb[fk[1]]
- hand = pb[fk[2]]
- uarmi = pb[ik[0]]
- farmi = pb[ik[1]]
- handi = pb[ik[2]]
- pole = pb[ik[3]]
+##############################
+## IK/FK snapping functions ##
+##############################
- # Hand position
- handmat = get_pose_matrix_in_other_space(hand.matrix, handi)
- set_pose_translation(handi, handmat)
- set_pose_rotation(handi, handmat)
- set_pose_scale(handi, handmat)
- bpy.ops.object.mode_set(mode='OBJECT')
- bpy.ops.object.mode_set(mode='POSE')
+def match_pole_target(ik_first, ik_last, pole, match_bone, length):
+ """ Places an IK chain's pole target to match ik_first's
+ transforms to match_bone. All bones should be given as pose bones.
+ You need to be in pose mode on the relevant armature object.
+ ik_first: first bone in the IK chain
+ ik_last: last bone in the IK chain
+ pole: pole target bone for the IK chain
+ match_bone: bone to match ik_first to (probably first bone in a matching FK chain)
+ length: distance pole target should be placed from the chain center
+ """
+ a = ik_first.matrix.to_translation()
+ b = ik_last.matrix.to_translation() + ik_last.vector
- # Pole target position
- a = uarm.matrix.to_translation()
- b = farm.matrix.to_translation() + farm.vector
+ # Vector from the head of ik_first to the
+ # tip of ik_last
+ ikv = b - a
- # Vector from the head of the upper arm to the
- # tip of the forearm
- armv = b - a
-
- # Create a vector that is not aligned with armv.
+ # Create a vector that is not aligned with ikv.
# It doesn't matter what vector. Just any vector
# that's guaranteed to not be pointing in the same
- # direction.
- if abs(armv[0]) < abs(armv[1]) and abs(armv[0]) < abs(armv[2]):
+ # direction. In this case, we create a unit vector
+ # on the axis of the smallest component of ikv.
+ if abs(ikv[0]) < abs(ikv[1]) and abs(ikv[0]) < abs(ikv[2]):
v = Vector((1,0,0))
- elif abs(armv[1]) < abs(armv[2]):
+ elif abs(ikv[1]) < abs(ikv[2]):
v = Vector((0,1,0))
else:
v = Vector((0,0,1))
- # cross v with armv to get a vector perpendicular to armv
- pv = v.cross(armv).normalized() * (uarm.length + farm.length)
+ # Get a vector perpendicular to ikv
+ pv = v.cross(ikv).normalized() * length
def set_pole(pvi):
+ """ Set pole target's position based on a vector
+ from the arm center line.
+ """
# Translate pvi into armature space
- ploc = a + (armv/2) + pvi
+ ploc = a + (ikv/2) + pvi
# Set pole target to location
mat = get_pose_matrix_in_other_space(Matrix().Translation(ploc), pole)
@@ -182,50 +181,99 @@
set_pole(pv)
- # Get the rotation difference between the ik and fk upper arms
- q1 = uarm.matrix.to_quaternion()
- q2 = uarmi.matrix.to_quaternion()
+ # Get the rotation difference between ik_first and match_bone
+ q1 = ik_first.matrix.to_quaternion()
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list