Repository navigation
[Feature] Physics pose: a seam for external pose sources - #55
Merged
Merged
Conversation
added 2 commits
September 22, 2026 10:38
A game or a physics plugin can now read an entity's skeleton (joint paths, parents, the model-space bind pose) and this frame's displayed joint transforms, and hand a pose back: one model-space transform and one weight per joint, applied every animation update after foot IK and before the world pose is composed, until cleared. A weighted joint takes the physics rotation, slerped by its weight, in its parent's blended frame; it also takes the physics translation when it heads a physics-driven subtree (no parent, or a parent at weight 0), while joints below keep their animated bone offsets, and joints at weight 0 keep the animated pose under whatever moves their parent. Writing into the local pose keeps the transition history valid, so a clip change out of a ragdoll pose inertializes for free. A paused entity skips the stage like every other. Eleven tests on a three-joint chain; a UsingPhysicsPose guide and the pipeline description updated.
… blend A plugin driving its bodies toward the animation read the displayed pose, which already carried the bodies' result: at full weight the motors aimed at where the bodies were and stopped pulling. getAnimatedJointModelTransforms returns the pose the update composed before the physics blend (equal to the displayed pose while none is active), captured only when a physics pose is set. The blend composed translations without rest scale while the pose a plugin reads includes it, so a rig with a scaled root did not round-trip. The walk now accumulates the rest scale of the ancestors and applies it to translations both ways: exact for uniform scales, per-axis otherwise. Docs note that a clip switch while a physics pose is active inertializes from the blended pose (what a get-up wants) and that a cut is halflife 0.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A public seam so an external pose source (a physics plugin, a game) can read an entity's skeleton and hand a pose back that the animation pipeline blends in per joint. The first consumer is the CoolZombie demo's ragdoll on the Jolt plugin: knockdowns and hit reactions, with the mesh following the simulated parts.
SkeletonJointInfo+getSkeletonJointInfo(entityId:): joint paths (parents before children), parent indices, the model-space bind pose. What a rig builder needs to put physics parts on the joints.getJointModelTransforms(entityId:): this frame's displayed model-space joint transforms (the bind pose before the first update). World = the entity's world transform × model.setPhysicsPose(entityId:jointModelTransforms:jointWeights:)/clearPhysicsPose(entityId:): one model-space transform and one weight per joint, applied every animation update after foot IK and before the world pose is composed, until cleared. A weighted joint takes the physics rotation, slerped by its weight, in its parent's blended frame; it also takes the physics translation when it heads a physics-driven subtree (no parent, or a parent at weight 0), while joints below keep their animated bone offsets; joints at weight 0 keep the animated pose under whatever moves their parent. Wrong array counts are ignored with a logged error.The stage writes into the local pose, so the transition history stays valid and a clip change out of a ragdoll pose inertializes for free. A paused entity skips the stage like every other. Motion matching, reach IK and foot IK are untouched.
Tests
AnimationPhysicsPoseTests(11) on a three-joint chain: full weight on a leaf, half-weight rotation, a weight-0 child under a driven parent, the translation rule at the top of a subtree and below it, clear restores the animated pose, pause defers the pose, wrong counts ignored, weight clamping, joint info and model transforms consistent with each other and with the bind pose, nil readers without a skeleton. The animation suite (114) stays green.Docs
docs/API/UsingPhysicsPose.md(new, in the mkdocs nav after Root Motion) and the pipeline description indocs/Architecture/animationPoseLayer.md.