I think there’s a bug in getAbsolutePosition
, but it’s a bit over my head.
After rotating a bone, getAbsolutePosition
on the child bone gives the same position as prior to the rotation.
I think there’s a bug in getAbsolutePosition
, but it’s a bit over my head.
After rotating a bone, getAbsolutePosition
on the child bone gives the same position as prior to the rotation.
You have to call computeAbsoluteTransforms() on the bones.
Same thing happens with a mesh if you forget to call computeWorldMatrix() afterwards.
A quick way of testing for these cases is calling scene.render() after you scale, rotate, translate etc. but before you need the updated values.
The position of a bone is at the head not the tail. Rotation only “moves” the tail. I needed to also get the position of the tail for IK. The control mesh & pole mesh needed to initially be placed at the wrist & elbow.
I found code in the repo, but it was in the debug area, in Skeleton Viewer. In order to draw lines which end at the tail, you have to know where that is. I just grabbed it, since it was in the wrong place for me, as well as being private. Here is a minorly changed version:
/**
* lifted from SkeletonViewer
*/
private _getBonePosition(position : BABYLON.Vector3, bone : Bone, meshMat : BABYLON.Matrix, x = 0, y = 0, z = 0): void {
const parentBone = bone.getParent();
const tmat = bone.getLocalMatrix().clone();
if (x !== 0 || y !== 0 || z !== 0) {
const tmat2 = BABYLON.Matrix.Identity();
tmat2.setTranslationFromFloats(x, y, z);
tmat2.multiplyToRef(tmat, tmat);
}
if (parentBone) {
tmat.multiplyToRef(parentBone.getAbsoluteTransform(), tmat);
}
tmat.multiplyToRef(meshMat, tmat);
position.x = tmat.m[12];
position.y = tmat.m[13];
position.z = tmat.m[14];
}
You will have to do the same. For those not familiar with IK, here is a PG, where you can drag either mesh to pose a bone. In this, I am just eye balling the initial locations. https://www.babylonjs-playground.com/#VSURBJ#2
@Deltakosh & @Pryme8, I think this method should be refactored into the bone class, please. There other uses where knowing the position of the tail is important.
If you have bone length you can just do bone position plus direction scaled to length.
This method was from before me so I’m not sure why it got places in the viewer and not as a bone method, could see the perks of it being a public bone method.
Could also do something like this:
let dir = bone.childofSomekind.getAbsolutePosition.subtract(bone.getAbsolutePosition())
let dist = dir.length()
dir = dir.normalize()
bone.position = bone.getAbsolutePosition().add(dir.scale(dist))
Thanks Raggar!
Is there any reason why getAbsolutePosition
is not calling computeAbsoluteTransforms
on the relevant bones?
It is doing the call:
public getPositionToRef(space = Space.LOCAL, mesh: Nullable<AbstractMesh>, result: Vector3): void {
if (space == Space.LOCAL) {
var lm = this.getLocalMatrix();
result.x = lm.m[12];
result.y = lm.m[13];
result.z = lm.m[14];
} else {
var wm: Nullable<Matrix> = null;
//mesh.getWorldMatrix() needs to be called before skeleton.computeAbsoluteTransforms()
if (mesh) {
wm = mesh.getWorldMatrix();
}
this._skeleton.computeAbsoluteTransforms();
var tmat = Bone._tmpMats[0];
if (mesh && wm) {
tmat.copyFrom(this.getAbsoluteTransform());
tmat.multiplyToRef(wm, tmat);
} else {
tmat = this.getAbsoluteTransform();
}
result.x = tmat.m[12];
result.y = tmat.m[13];
result.z = tmat.m[14];
}
}
and Skeleton.computeAbsoluteTransforms
:
public computeAbsoluteTransforms(forceUpdate = false): void {
var renderId = this._scene.getRenderId();
if (this._lastAbsoluteTransformsUpdateId != renderId || forceUpdate) {
this.bones[0].computeAbsoluteTransforms();
this._lastAbsoluteTransformsUpdateId = renderId;
}
}
However, it is doing it only a single time per frame, it may be your problem if you are modifying several bones and getting their absolute position.