Hello everyone,
I have a skinned mesh (nested hierarchy of bones) and want to transform the bones directly. For the bones, I also have a json file of position, rotation and scale as Vector3 that represent absolute transforms of each bone in world coordinate space. I have these bone transforms as a list of frames and now want to: Receive a frame, transform my bones in world coordinate space, render() etc. to achieve animation that way.
I read in the docs that to transform an Object3D (i.e. a Bone) three.js expects local transforms relative to the parent of the object.
So I need to convert my absolute transforms of the bones to local ones (while respecting the hierarchy of my model). Is there a good approach for this? I saw there is .localToWorld(), but it only works for position. Otherwise I need to use matrices right? I think I would have to multiply my position, rotation, scale by the inverse of the world matrix of the parent, but I am not so sure on the details. Could anyone give me some pointers?
1 Like
If you have a JSON file with transforms in world coordinate space, you might as well detach the bones from their parents and put them at the root, or under an un-transformed parent node. Not much reason to have a nested scene graph if it isn’t going to be used.
So that every bone’s immediate parent is the scene itself? I am not sure if this will work as the json file isn’t complete in the sense that some transforms (e.g. of the lower body of the skeleton) aren’t part of the file, so I need to keep them attached to their parents right?
In terms of rendering, all that matters is the world matrix of each bone. Whatever the world matrix of a bone was under its parent, you can apply the same transform to bone.matrix
after un-nesting the object if you want.
I guess the question would be, if this “lower body of the skeleton” isn’t in the JSON file, what do you want to happen if one of its parent bones were changed? Should it remain in the same absolute position, or in the same position relative to its parents?
Ok I got it to work . I detached each bone from its parent, by attaching it to the scene. Then I apply the transforms to the bone by using bone.position /rotation/scale and finally I re-attach the bone to the parent. This gives me the expected result. Thanks!
Weirdly enough I only got the correct result after doing the thing I described above, as well as specifying the order “ZYX” for my rotation like so:
let euler = new THREE.Euler(eulerX, eulerY, eulerZ, "ZYX");
let q = new THREE.Quaternion().setFromEuler(euler);
bone.rotation.setFromQuaternion(q);
which is a bit surprising as the transforms are also from a RHS /Y-up coordinate system.
Awesome! The rotation order not tied to the coordinate system. In three.js XYZ is the default, but I find ZYX
helpful when working with cameras, for example, as it keeps the camera level when rotating around the X and Y axes.
Ok, so i guess the data I receive uses the ZYX convention for rotations. Thx for the help. I will close this thread now.