• Runtimes
  • Is there a good way to extrapolate a skeleton's pose using the C runtime?

My problem is thus: In our game we're using Spine via the C runtime. We run the game's physics and gameplay logic on a fixed timestep so that the behavior is consistent regardless of framerate. Then when we render, we use objects' velocities to extrapolate their transforms forward by the leftover fraction of the timestep, so we get smooth motion without jitter, regardless of the discrepancy between tick rate and refresh rate. The classic method from https://www.gafferongames.com/post/fix_your_timestep/, basically.

What we'd like to do is use Spine animations to drive certain gameplay logic - for example, attaching a collider to a bone on a skeleton, or triggering a script to run based on an animation event. However, that implies we need to update animations and transforms once per tick instead of once per frame in order to get consistent behavior, which means the animations may not be smooth unless the tick rate is extremely high, or unless we can interpolate or extrapolate between ticks.

What I'm wondering then is, is there any good built-in or otherwise reasonably easy way to extrapolate the animations for the purpose of rendering? Or, alternatively, is there a way to clone an existing skeleton and animation state? That way each frame we could clone the rig, simulate the clone forward a fraction of a tick, then render the clone and throw it away, which would effectively be an even more accurate/robust kind of extrapolation.

Related Discussions
...

Spinebot is so comically useless, I really do not understand why you even allow it on the forum at all. It seems actively counterproductive.

Sounds like you have never worked in customer service. 😉 Spinebot solves simple user problems, giving users a solution immediately. That saves the user from having to wait for an answer and it saves us significant time from having to answer the same simple questions, day after day -- giving us more time to answer the more advanced questions. If a Spinebot answer is poor, we delete it.

If you were using a single animation, it would be a lot easier, but when using AnimationState the results can be complex. Eg, there could be multiple tracks, some could be in the middle of transitions to other animations, etc. The only 100% accurate solution is to step the AnimationState forward and pose the skeleton with it.

The AnimationState has state (surprise!) that would not be easy to revert (eg track entries that have ended) so you would need a copy, as you mentioned. We don't currently have copy constructors, though that wouldn't be super hard to add.

When AnimationState is applied normally, it doesn't leave the skeleton in an unknown state. If a property will no longer be animated, it gets set back to the setup pose (unless you use clearTrack, clearTracks, or trackEnd). If you were to pose the skeleton with an AnimationState, discard the AnimationState, then go back to using an older AnimationState, it could leave the skeleton with state from the discarded AnimationState. For example, an attachment might remain visible.

Cloning the skeleton could be a way around this (and we have copy constructors), but that's pretty heavy. You could reset the skeleton to the setup pose, or I think you could call setEmptyAnimations(0) and apply the AnimationState again before discarding it. Either of those should cover everything except physics.

First you'd want to revert the skeleton time. Then if you called updateWorldTransform with Physics.update, it advances the physics state (which is actually stored on the constraint, not the skeleton). You would need to do that to be 100% accurate if you are using physics, in which case you'd need to restore these values for each PhysicsConstraint to revert advancing physics:

float ux, uy, cx, cy, tx, ty;
float xOffset, xVelocity;
float yOffset, yVelocity;
float rotateOffset, rotateVelocity;
float scaleOffset, scaleVelocity;
float remaining, lastTime;

If you use Physics.pose instead, physics won't advance. That's a little easier, if its acceptable to not have exactly the right pose.