Reputation: 508
I'm trying to build a component which can display the position and orientation of the bones of a SkinMesh and has run into a bit of a snag. somehow I cannot determine the global position of a bone.
I have tried:
this.updateMatrixWorld(true);
this.traverse(function (bone) {
var twinGlobalPos = new THREE.Vector3().getPositionFromMatrix(bone.matrixWorld);
console.log(typeof (bone), "GlobalPos", twinGlobalPos.x, twinGlobalPos.y, twinGlobalPos.z);
});
and obvious variations on that, unfortunately this doesn't seem to work, all bones, except for the root report a position of 0,0,0. The root bone reports a global position identical to the SkinMesh
What am I doing wrong? is there some alternative way?
Upvotes: 5
Views: 2996
Reputation: 18212
The chosen answer might be outdated because in current version multiple animations are now supported. Don't edit the original answer because people use different versions of three.js
this line (from Anton's code):
var twinGlobalPos = new THREE.Vector3().setFromMatrixPosition(bone.skinMatrix).add(meshGlobal);
should be now looking like that:
var twinGlobalPos = new THREE.Vector3().setFromMatrixPosition(bone.animationCache.animations[animation.data.name].originalMatrix).add(meshGlobal);
or just
var twinGlobalPos = new THREE.Vector3().setFromMatrixPosition(bone.position).add(meshGlobal);
Upvotes: 0
Reputation: 508
Ok, I found the answer on my own.
SkinMesh overloads the implementation of updateMatrixWorld, which does not perform updates on any instances of THREE.Bone. Instead it delegates to the bones' update method, which maintains a matrix 'skinmatrix'.
Skinmatrix works similar to the worldMatrix but uses the SkinnedMesh as the global reference rather than the scene. Combining the worldMatrix of the SkinnedMesh and the SkinMatrix of the bone seems to do the trick.
this.updateMatrixWorld(true);
// assuming this is a SkinnedMesh
var meshGlobal = new THREE.Vector3().setFromMatrixPosition(this.matrixWorld);
this.traverse(function (bone) {
if(bone instanceof THREE.Bone) {
var twinGlobalPos = new THREE.Vector3().setFromMatrixPosition(bone.skinMatrix).add(meshGlobal);
console.log(typeof (bone), "GlobalPos", twinGlobalPos.x, twinGlobalPos.y, twinGlobalPos.z);
}
});
The above code seems to do the trick. I can see why this design has been chosen, but it does present a gotcha, perhaps overriding the localToWorld
and worldToLocal
methods on THREE.Bone would be a semi solution?
Upvotes: 5