1
$\begingroup$

I have an array of head positions of bones only, and I am trying to pose a skeleton based on that only. In pose mode you are unable to change the location of bones that are not the main bone, so I resort to calculating the rotations between connected bones. I do it like so and store the rotations in a list of the same length as the amount of bones:

#frame holds the xyz position of the bone heads.
def CalculateRotations(frame):
for i in range(0, len(joints)):
    children = arm.bones[joints[i]].children.values()
    if children:
        #Current orientation of the bone.
        vector1 = bpy.data.objects['Armature'].pose.bones[joints[i]].y_axis
        if (len(children) == 1):
            childIndex = joints.index(children[0].name)
            #A vector pointing from the head to the tail.
            vector2 = Vector(frame[childIndex]) - Vector(frame[i])
        else:
            for bone in children:
                if bone.use_connect:
                    vector2 = Vector(frame[joints.index(bone.name)]) - Vector(frame[i])
                    
        angleInRadians = vector1.angle(vector2)
        axis = vector1.normalized().cross(vector2.normalized())
        rotations[i] = Quaternion(axis, angleInRadians)

Then I turn the rotation into a matrix and multiply it to the bones matrix:

def RotateBones():
arm = bpy.data.objects['Armature']
for joint in joints:
    rot_mat = rotations[joints.index(joint)].to_matrix().to_4x4()
    orig_loc, orig_rot, orig_scale = arm.pose.bones[joint].matrix.decompose()
    orig_loc_mat = Matrix.Translation(orig_loc)
    orig_rot_mat = orig_rot.to_matrix().to_4x4()
    orig_scale_mat = Matrix.Scale(orig_scale[0],4,(1,0,0)) * Matrix.Scale(orig_scale[1],4,(0,1,0)) * Matrix.Scale(orig_scale[2],4,(0,0,1))
    arm.pose.bones[joint].matrix = orig_loc_mat @ orig_rot_mat @ rot_mat @ orig_scale_mat

I have created spheres on each point of the head positions, and I've also added nurbs path corresponding to the 4 of the arm bones with constraints copying the local rotation of the resulting bones from the above script. The rotations on the nurbs path seem correct, as they connect the spheres, however, the bones are not rotated correctly. In the below attached picture is the resulting pose on the right, on the left are the spheres and nurbs paths, arms only, plus a bone which has the copy rotation constraint local space -> world space as well.

enter image description here

How would I make the bones align such that they connect the spheres? I'm not sure what I'm doing wrong here. Edit: Added the input file. With numpy.load() you'll have a 310x17x3 ndarray, 310 frames, 17 joints, and xyz positions relative to the pelvis. The joints are:

joints = ['Pelvis', 'Hip_R', 'Knee_R', 'Ankle_R',
          'Hip_L', 'Knee_L', 'Ankle_L', 'Spine1',
          'Neck', 'Head', 'Site', 'Shoulder_L',
          'Elbow_L', 'Wrist_L', 'Shoulder_R', 'Elbow_R', 'Wrist_R']
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.