Animation Layers/Instances - Shared computational work

Hello,

We’re trying to optimize our animation blueprints, and we moved all blueprint logic to c++, which greatly helped, however we have our animation instances and layers inheriting from the same c++ animation instances which compute the required values for all the anim graphs.

However, we have up to 5 layers/instances/postprocessing layers on a single character and because they share the same parent they all compute the same values, when we except virtually no difference between the computed values across the layers. Many layers require access to the same variables, but not all layers always use all variables, and this makes it somewhat impossible to split up variables into multiple classes in c++ as there’s no clear separation between the variables we compute. We did our best, but even after splitting some of it up, there’s still a lot of redundant repeat-work.

To further optimize this we decided to pre-compute a lot of variables into various struct types before we tick the animations, and then copy the struct types into the animation layer/instance, so they can access it without needing to compute.

But this only partially reduced the cost, and because of the sheer amount of data we need access to in the anim graphs, and still needing to copy the data once per layer/instance it still adds up with up to 100 characters on screen.

My suggestion/idea:

To improve this I had the idea that we can store the shared animation we compute into a thread-safe storage that is accessible to all layers, and then each layer can access this storage without the worry of needing to compute it more than once, nor the worry of having to copy the data once per layer/instance.

However, this is where I hit a wall in how to go about and access this data from the anim graph. I tried to look into UAnimGraphNodeBinding to expose more variables through a custom binding, but this seems to fully private and not extendable. I then looked at UAnimBlueprintExtension, which seems to also allow us to provide a way to do this, but I struggle to see any hook for us to add these anim blueprint extensions to the anim graph, they all seem hardcoded in c++. Following the idea of UK2Node_PropertyAccess was also something we considered, but this node introduces a lot of game-thread overhead during PropertyAccess_PreUpdate_GT.

----

My question here is, does the engine provide a way for us to access some sort of shared thread-safe storage from the anim graph, and if not, is there any further recommendations you can give that would allow us to get rid of the redundant repeat-work between the layers and instances? Since they’re all belonging to the same mesh, I feel like there must be a way to support shared data across the layers, but perhaps I am not seeing it.

Any help or suggestions you can provide here would be greatly appreciated.

Thank you for your time,

With kind regards,

Céleste Neukirchen

[Attachment Removed]

Steps to Reproduce
Not a bug - nothing to reproduce.

[Attachment Removed]

Hi, is it possible to move the repeated work/data into the ‘main’ anim instance in this case? Or are we talking about repeated work that is meant to be independent of the context in which it is running (such as instances that are implememented in a plugin)?

[Attachment Removed]

Property access will run in a thread-safe manner if the functions it calls are all thread-safe, so will run inline on a worker thread rather than beforehand on the game thread. You can see if this is occuring on the property access widget, where it will indicate ‘thread-safe’ rather than ‘pre-event graph’ (etc.).

Recently introduced (available in 5.7) is a native BlueprintThreadSafe call: Blueprint_GetMainAnimInstance (listed as “Get Main Anim Instance” in BP). If you wrap this with a BP function (marked thread safe) that casts to your type then you can use that function to access your main instance’s data via property access on the worker thread.

[Attachment Removed]

That is not possible - the task and the instances themselves are owned by the skeletal mesh component

[Attachment Removed]

A lot of the variables can be computed once in the main anim graph yes, but to my understanding, to access those variables you need to use the property access node, and get the main anim instance, in which case we introduce GT Property access overhead? Unless there’s a different way of doing it that we’re not aware of.

[Attachment Removed]

Ah I see, that may be a solution. Though, looking at Blueprint_GetMainAnimInstance, the function seems to access the skeletal mesh and then gets the anim instance from that skeletal mesh. From a first glance this doesn’t sound too thread safe if the skeletal mesh is destroyed while the worker thread is busy, are there any safeguards in place outside this function that makes this less unsafe?

[Attachment Removed]

Okay thanks, in that case this sounds like it might be a good solution.

[Attachment Removed]