Skip to content

New animation system: shared stateful static objects cause unexpected threading issues #1806

@pspeed42

Description

@pspeed42

In general, JME operates in a "threading not supported" mode but in a "you are fine to do whatever until you attach it to the scene graph" sort of way. Meaning that you can load and manipulate Spatials from separate threads but once you attach them to the render-thread managed scene, then hands off.

The animation system internally uses several global objects that keep state. By default, these are shared across every loaded animation, no matter where it was loaded.

Examples at the lowest level are AnimInterpolators.NLerp and AnimInterpolators.LinearVec3f:
https://github.com/jMonkeyEngine/jmonkeyengine/blob/master/jme3-core/src/main/java/com/jme3/anim/interpolator/AnimInterpolators.java#L46

...which are then used by one shared FrameInterpolator instance:
https://github.com/jMonkeyEngine/jmonkeyengine/blob/master/jme3-core/src/main/java/com/jme3/anim/interpolator/FrameInterpolator.java#L41
...that is the default for MorphTrack and TransformTrack:
https://github.com/jMonkeyEngine/jmonkeyengine/blob/master/jme3-core/src/main/java/com/jme3/anim/MorphTrack.java#L55
https://github.com/jMonkeyEngine/jmonkeyengine/blob/master/jme3-core/src/main/java/com/jme3/anim/TransformTrack.java#L53

And while you could meticulously set your own:
https://github.com/jMonkeyEngine/jmonkeyengine/blob/master/jme3-core/src/main/java/com/jme3/anim/TransformTrack.java#L302
...it won't be serialized:
https://github.com/jMonkeyEngine/jmonkeyengine/blob/master/jme3-core/src/main/java/com/jme3/anim/TransformTrack.java#L332

At a high level, the right solution would be to share a single FrameInterpolator instance (and its own instances of NLerp, LinearVector3f, etc.) across the AnimComposer/SkinningControl and not across the whole Java virtual machine. I'm still trying to figure out the simplest/least-impactful way to make that happen. (Locally I've modified all of these cases to create their own instances and it solves the problems.)

As it stands, if you load Jaime.j3o into a scene and let him run around while meanwhile loading a totally separate model in another thread... posing or modifying that animation from that other thread will cause Jaime to glitch or crash. Which breaks the mental threading model under which JME normally operates.

Or in my case, when having a game load thread animate physics collision shapes while the rendering thread is trying to play animations:
https://www.youtube.com/watch?v=lWAEevlytPE

animation-error1

Metadata

Metadata

Assignees

No one assigned

    Labels

    defectSomething that is supposed to work, but doesn't. Less severe than a "bug"

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions