• 3D
  • How to rotate a bone globally

I'm trying to rotate a bone by an angle and an axis I have already calculated. I've tested this angle and axis by rotating a Mesh Instance, and it works perfectly. I checked the calculations and they look right (the axis is found by taking the cross product of the two vectors making up the angle). However, when I try to rotate the bone by the same values, it rotates by the correct angle, but the axis is suddenly different (it should be rotating up, but it rotates to the left). I'm pretty sure the bone is rotating locally relative to something, because when I change the bones orientation it rotates in a different direction every time. I've tried using .get_bone_global_pose(), but for some reason the bone gets stretched out in a weird direction instead of just rotating.

This is my code in gdscript: (the vector is the Mesh Instance, and the rotation and axis is correct) vector.rotate(axis, angle)

( the bone is rotated by the same values, but the axis is wrong) bonePose = skel.get_bone_pose(id) bonePose = bonePose.rotated(axis, angle) skel.set_bone_pose(id, bonePose)

Make sure the axis vector is normalized. Other than that, if axis is not calculated in bone's local space, you'll need to transform it to that space before performing the rotation.

The axis vector is already normalized. How would I transform it to the bone local space? (it was calculated in global space, so I think that's the problem)

Writing this off the top of my head so watch out:

# get transformation from bone space to global space
var bone_to_global = skeleton.global_transform * skeleton.get_bone_global_pose(bone_id)

# invert it so we get transformation from global to bone space
var global_to_bone = bone_to_global.inverse()

# eliminate translation and non proportional scalling 
# since we're transforming a direction vector
var global_to_bone_basis = bone_to_global.basis.inverse().transposed())

# transform the axis
var axis_local = global_to_bone_basis * axis_global

If the above works it can be optimized to:

var bone_to_global = skeleton.global_transform * skeleton.get_bone_global_pose(bone_id)
var axis_local = bone_to_global.basis.transposed() * axis_global

@xyz said: If the above works it can be optimized to:

var bone_to_global = skeleton.global_transform * skeleton.get_bone_global_pose(bone_id)
var axis_local = bone_to_global.basis.transposed() * axis_global

This worked, except the bone rotated in exactly the opposite direction it was supposed to lol. But this actually works really well, I changed the bones orientation and it stayed the same each time. Do you know how I would get the axis to be in the opposite direction? Thanks for all the help by the way.

@Joe said: Do you know how I would get the axis to be in the opposite direction?

Swap the order of vectors when taking the cross product or simply put the minus sign in front of the axis vector. a.cross(b) -> b.cross(a) axis -> -axis

Thank you so much this worked perfectly!