__author__ = 'thoth'
# http://blender.stackexchange.com/questions/63878/how-to-map-a-pose-to-the-restpose-of-another-rig-with-same-topology
import bpy
from mathutils import *
def explore_matrices(arm):
for bone in arm.data.bones:
#print ( [ bone.name, bone.head_local, bone.matrix_local*Vector([0,0,0])])
print ( [ bone.name, bone.tail_local, bone.matrix_local*Vector([0,bone.length,0])])
def scene_link(obj, scn):
try:
scn.objects.link(obj)
except:
pass
def check1(arm):
bone = arm.pose.bones[2]
e1 = bpy.data.objects.get("head")
if e1 is None:
e1 = bpy.data.objects.new("head", None)
scn = bpy.context.scene
scene_link(e1, scn)
e2 = bpy.data.objects.get("tail")
if e2 is None:
e2 = bpy.data.objects.new("tail", None)
scene_link(e2, scn)
e1.location = arm.matrix_world * bone.matrix * Vector([0,0,0])
e2.location = arm.matrix_world * bone.matrix * Vector([0,arm.data.bones[bone.name].length,0])
def matrix_scale(scale_vec):
return Matrix([[scale_vec[0],0,0,0],
[0,scale_vec[1],0,0],
[0,0,scale_vec[2],0],
[0,0,0,1]
])
def matrix_for_bone_from_parent(bone, ao):
eb1 = ao.data.bones[bone.name]
E = eb1.matrix_local # * Matrix.Scale(eb1.length,4)
ebp = ao.data.bones[bone.name].parent
E_p = ebp.matrix_local # * Matrix.Scale(ebp.length,4)
return E_p.inverted() * E
def matrix_the_hard_way(pose_bone, ao):
if pose_bone.rotation_mode == 'QUATERNION':
mr = pose_bone.rotation_quaternion.to_matrix().to_4x4()
else:
mr = pose_bone.rotation_euler.to_matrix().to_4x4()
m1 = Matrix.Translation(pose_bone.location) * mr * matrix_scale(pose_bone.scale)
E = ao.data.bones[pose_bone.name].matrix_local
if pose_bone.parent is None:
return E * m1
else:
m2 = matrix_the_hard_way(pose_bone.parent, ao)
E_p = ao.data.bones[pose_bone.parent.name].matrix_local
return m2 * E_p.inverted() * E * m1
def pose_to_match(arm, goal):
"""
pose arm so that its bones line up with the REST pose of goal
"""
matrix_os= {}
for to_match in goal.data.bones:
matrix_os[to_match.name] = to_match.matrix_local
#print([ "matrix", to_match.name, matrix_os[to_match.name] ] )
#xyz' = s * m * m(parent) * xyz
for to_pose in arm.pose.bones:
if to_pose.parent is None:
len2 = arm.data.bones[to_pose.name].length
len1 = goal.data.bones[to_pose.name].length
to_pose.matrix = matrix_os[to_pose.name] * Matrix.Scale(len1/len2, 4)
else:
# we can not set .matrix, because a lot of stuff behind the scenes has not yet
# caught up with our alterations, and it ends up doing math on outdated numbers
mp = matrix_the_hard_way(to_pose.parent, arm) * matrix_for_bone_from_parent(to_pose, arm)
m2 = mp.inverted()* matrix_os[to_pose.name] * Matrix.Scale(goal.data.bones[to_pose.name].length, 4)
loc,rot,scale = m2.decompose()
to_pose.location = loc
if 'QUATERNION' == to_pose.rotation_mode:
to_pose.rotation_quaternion = rot
else:
to_pose.rotation_euler = rot.to_euler(to_pose.rotation_mode)
to_pose.scale = scale / arm.data.bones[to_pose.name].length
#
#
#
#explore_matrices(bpy.data.objects['beta'])
#pose_to_match(bpy.data.objects['Armature.001'], bpy.data.objects['Armature'])
pose_to_match(bpy.data.objects['gamma'], bpy.data.objects['beta'])
#check1(bpy.data.objects['gamma'])
|
Blender python API quick-start
Syntax highlighting by Pygments.