Repository navigation
Fix repeated armature bind-pose round trips - #3007
toaster0123 wants to merge 1 commit into
Conversation
Fixes jMonkeyEngine#2383. Restore separate parent transforms componentwise, preserve the complete matrix bind pose, and reset reused affine matrix storage. Add regression coverage for both joint transform strategies. Forum: https://hub.jmonkeyengine.org/t/issue-calling-armature-savebindpose/48046
| inverseModelBindMatrix.loadIdentity(); | ||
| jointModelTransform.getOffsetTransform(inverseModelBindMatrix, Matrix4f.IDENTITY); |
There was a problem hiding this comment.
Nice, focused fix — going through getOffsetTransform() instead of decomposing into T/R/S is the right call, and keeping the full matrix for shear is a solid catch.
Two things I'd like you to double-check here:
-
Freshness of the cached local transform.
getOffsetTransform()reads the transform cached inside theJointModelTransform, which is only refreshed byupdateModelTransform(). The previous code handedinitialTransformstraight toJointModelTransform.saveBindPose(...). If the local transform changed since the last model-transform update, the new path could save a slightly stale pose. Your round-trip test never changes the pose, so it can't distinguish the two — worth either confirming thatArmature.saveBindPose()/applyBindPose()refresh the model transforms, or adding a case that moves a joint before saving. -
Custom
JointModelTransformimplementations. This call no longer goes through the interface'ssaveBindPose(Transform, Matrix4f, Joint). If a third-party implementation overrides only that method, this path now skips it. Worth a javadoc note or keeping the delegation if the method is meant to stay as an extension point.
jaime-jmebot
left a comment
There was a problem hiding this comment.
Really solid diagnosis and a tidy, minimal fix — I like that the shear case is handled by keeping the whole model matrix rather than trying to recover it.
- Routing the bind pose through
getOffsetTransform()instead of a T/R/S decomposition is the right call, and theloadIdentity()reset for reused matrices is a good catch. - The separate-transform fix looks correct: reversing the parent's T/R/S components directly is exactly what the inverse composition needs for a TRS chain.
- The regression tests cover both strategies and both scale flavours, and the fact that 7 of 8 fail on master is convincing evidence they actually pin the bug.
- Only open point is in the inline comment: whether the model transform cached inside the
JointModelTransformis guaranteed fresh atsaveBindPose()time, plus the small API note about custom implementations.
Good luck with the full Gradle run when you can.
Fixes #2383.
Repeatedly restoring and saving the same bind pose can stretch or distort a rotated joint hierarchy, even when the original scale is 1. The added test reproduces this with an eight-joint chain: save its bind pose, then call
applyBindPose()andsaveBindPose()1,000 times without changing the pose.Three details caused the saved pose to drift:
The regression tests cover both transform strategies, unit and nonuniform scales, identity skinning at the saved pose, and reused bind-matrix storage.
Validation:
--release 8and the repository's strict unchecked-warning options.These checks used cached JUnit 5.13.4. The full Gradle build with the project's configured Java 25/JUnit 6 toolchain and renderer/GPU tests have not been run. Coverage uses positive scales; reflection and zero-scale limitations remain. Small floating-point round-off is still expected.
Original discussion: https://hub.jmonkeyengine.org/t/issue-calling-armature-savebindpose/48046