The goal is to get the rotational difference of the bones between Armature 1 and Armature 2 in its T-pose(not exactly), then apply the difference to a pose of Armature 2.
The purpose is so the model of Armature 1 follows Armature 2.
Testing for just the Right Upper Arm
Lets say I have two Armatures in normal poses. I want Armature 1 to follow Armature 2. The Armature 1 on the Left is the Source and Armature 2 on the Right is the Target:
But the Bones are not Aligned so the rotation is values are different:
First, Save the rotation variable of Armature 2 Right Arm, then set the Right Arm bone vector of Armature 2 to vector of Armature 1
Code:
import bpy
from mathutils import Matrix
from mathutils import Quaternion
context = bpy.context
scene = context.scene
RobloxRig = bpy.context.scene.objects['__Rig']
UpperRightArm = RobloxRig.pose.bones["RightUpperArm"]
CloudRig = bpy.context.scene.objects['CloudRig']
CloudRig_UpperRightArm = CloudRig.pose.bones["r_uparm"]
def snap_rotation(source, target):
Ms = source.id_data.convert_space(
pose_bone=source,
matrix=source.matrix,
from_space='POSE',
)
Mt = target.id_data.convert_space(
pose_bone=target,
matrix=target.matrix,
from_space='POSE',
)
_, q, _ = Ms.decompose()
t, _, s = Mt.decompose()
M = (
Matrix.Translation(t) @
q.to_matrix().to_4x4() @
Matrix.Diagonal(s.to_4d())
)
target.matrix = target.id_data.convert_space(
pose_bone=target,
matrix=M,
to_space='POSE',
)
if __name__ == "__main__":
context = bpy.context
scene = context.scene
scene.frame_set(720) #Frame of Normal pose
bpy.context.view_layer.update()
Mt = UpperRightArm.matrix
loc1, rot1, scale1 = Mt.decompose()
NormalRot = Quaternion(rot1)
snap_rotation(
CloudRig_UpperRightArm,
UpperRightArm
)
Output:
Now that Bone Vector of Armature 2 is aligned with Armature 1, Save the new rotation, Set it back to normal and get the rotational difference.
bpy.context.view_layer.update()
Mt = UpperRightArm.matrix
loc2, rot2, scale2 = Mt.decompose()
#New Rotation
NextRot = Quaternion(rot2)
#Setting back to normal using from code above values
M = (
Matrix.Translation(loc1) @
rot1.to_matrix().to_4x4() @
Matrix.Diagonal(scale1.to_4d())
)
UpperRightArm.matrix = M
#Getting Difference
RotationalDifference = NormalRot - NextRot
Output, Just back to normal after taking the value:
Now I Change the Frame which moves Armature 1:
scene.frame_set(730)
bpy.context.view_layer.update()
This Final part which Doesn't work I set the vector of the Armature 1 to Armature 2 like before then added the difference.
snap_rotation(
CloudRig_UpperRightArm,
UpperRightArm
)
bpy.context.view_layer.update()
Mt2 = UpperRightArm.matrix
loc3, rot3, scale3 = Mt2.decompose()
FinalRot = RotationalDifference + Quaternion(rot3)
M2 = (
Matrix.Translation(loc3) @
FinalRot.to_matrix().to_4x4() @
Matrix.Diagonal(scale3.to_4d())
)
UpperRightArm.matrix = M2
Wrong Output:
Here is what's expected:
A small difference is that it applies to all bones. If I get one bone it would be easy to get the rest.
Please help, Thank you.