What is the correct math to mirror bones

Hi everybody,
I’m trying to write a method for bones transformations reflection along the X-axis.
What I currently have looks approximately like that:

		// X-mirror matrix
		const reflPlane = new Plane(1, 0, 0, 0);
		const mirrorMatrix = Matrix.Reflection(reflPlane);

		const fromGlobalMat = fromBone.getWorldMatrix();
		const fromAbsInv = fromBone.getInvertedAbsoluteTransform();
		const fromGlobalDiff = fromGlobalMat.multiply(fromAbsInv);

		// TO NODE
		const toAbs = toBone.getAbsoluteTransform();
		const toGlobalDiffMat = mirrorMatrix.multiply(fromGlobalDiff);
		const toParent = toTnode.parent;
		const parentMat = toParent instanceof TransformNode ? toParent.getWorldMatrix() : Matrix.Identity();
		const toParentInv = parentMat.invert();

		const newGlobalMat = toGlobalDiffMat.multiply(toAbs);
		const newLocalMat = newGlobalMat.multiply(toParentInv);

The resulting matrix will be right-handed which needs to be fixed, but the position should be ok.
Unfortunately, that’s not the case. The position is messed up as well. I’d appreciate if someone could give me an idea of where I might be wrong.

1 Like

I would decompose the matrix to TRS, then I woudl mirror position and orientation quaternion.
mirrored position is simple : (-x,y,z)
mirrored quaternion is (-x, y, z, -w) IIRC
Then recompose the matrix. This will be fine for a world matrix. For parented matrix, compute in world space then multiply by parent world inverse matrix.


I see what you mean. That’s a bit different from what I’m trying to achieve I think.
The way you propose to do it, the mirrored bone will get the exact mirrored transform in skeleton space.
I need it to be in parent bone space.
A bit hard to describe it but the mirrored bone should get the same mirrored transformation as the original bone relative to its parent.

I’ll actually try to combine your mirroring approach with what I do.


Hi @Eugene_R did you get the mirroring to work? Would you like any more help? :relaxed:

Hi @carolhmj,
I tried a bit and pushed it off for a while but I’d greatly appreciate it if you can share your ideas on this one as we still need mirroring in the app :smiley:

For someone who is interested. The initial math I had was very simple and it appeared to be the correct one (like what Blender does). It only required conversion to euler angles.

		const LR = from.getLocalRotation().toEulerAngles();
		const LP = from.getLocalPosition();
		const newR = new Vector3(LR.x, -LR.y, -LR.z);
		const newP = new Vector3(-LP.x, LP.y, LP.z);

It is just it doesn’t work for all sorts of bones’ orientations. And I believe it is not possible to have reliable mirroring like that for all potential bind matrices.
Closing this one.