- संपादित
Skeleton Late/Update in Pararalel ? [Pharaoh - A New Era]
Hi all,
I was wondering if Skeleton Component could be manually updated through some Job system instead of the classic MonoBehaviour Update/LateUpdate.
To put some context, I'm the lead developper on Pharaoh - A New Era (remake of the old city builder), and we are using Spine to create the various walkers in the game. The whole game is based on those Walkers moving around the city, distributing resources between various buildings and houses, so as you'd expect, there can be quite a few.
Also, we are using Spine 4 and Unity 2019.
I recently made some profiling, and with around 300 walkers, the Update/LateUpdate are taking quite a few ms to execute, and I players could potentially put way more guys on their city, so I'm a bit worried it won't scale well.
Here are some screenshots attached:
The pink block on the left are our own mess, don't worry about that
I know using Job require the data to be blittable (no class, only struct), so this may not be strictly compatible with internal Spine data structures, but I feel that having most of the Skeleton computation may gain from being parallelized.
On a side note, maybe there is other things that could be used to reduce the time used ?
We currently have very few Spine skeletons using Events, so this could be a hint to some possible optimization too.
I'm open to every suggestions, and though I have searched through documentation and forum, I may have missed something, feel free to redirect me in case!
Thanks !
Can you show us the metrics of your skeletons? See Metrics view - Spine User Guide
The update time is proportional to your skeleton's complexity, where complexity is composed of many factors: number of bones, constraints, whether you use mesh deforms, how many vertices there are in the meshes, whether you use clipping and so on. The less of each of those, the faster the update will be.
Making the runtime compatible with the Unity jobs system is something we have on our todo list, but as you pointed out, it's not exactly trivial, especially since the runtime was designed before that system was in place. It's unlikely we'll get to do it before your game ships.
Hehe, I first posted about this four years ago now.
I was under the impression that this major refactor was currently bubbling to the surface though? Every month or so I check the Github Issue and it does look like it's on Harald's radar as something he hopes to tackle soon. Unless that's wishful thinking on my part and he's just adding it to each 4.x milestone list as a cruel joke, which I doubt. I hope that soon the Spine team can schedule in a month or so where the only thing on Harald's plate is to get the Unity runtime future-proofed for DOTS. It'll have to happen at some point!
DOTS is absolutely fantastic, by the way. Anything CPU heavy that happens frequently will function many times faster running in a Burst routine than it will in a Monobehaviour. The hype is mostly justified, in my experience, and especially so now that the API has settled down.
Thanks for the quick answer !
Mario लिखाCan you show us the metrics of your skeletons? See http://en.esotericsoftware.com/spine-metrics
Sure, I just asked our artists to give some of the walker metrics we have, here are a sample of 4 of them:
(they're using the software in french, hope you won't mind the localization )
Mario लिखाThe update time is proportional to your skeleton's complexity, where complexity is composed of many factors: number of bones, constraints, whether you use mesh deforms, how many vertices there are in the meshes, whether you use clipping and so on. The less of each of those, the faster the update will be.
Making the runtime compatible with the Unity jobs system is something we have on our todo list, but as you pointed out, it's not exactly trivial, especially since the runtime was designed before that system was in place. It's unlikely we'll get to do it before your game ships.
To be honest, this is a bit what I expected, Job/DOTS are moving quite fast but their usage isn't that widespread yet, so no worries on your side
Most of our Walkers have only one looping "walk" animation, but I was wondering if Spine had a Cache system of some sort ?
Let's say I spawn 600 of the same walker using the same Spine skeleton (but each its own component), do they all recompute the bones individually ?
On one AAA game I've worked on, they used a technique where they computed/baked animations once at runtime, and they kind of "lerped" on the animation to assign bones & vertices attributes from the baked one.
One things I add in mind as last resort was to generate a spritesheet of our animation instead of computing it when there are many of them on screen.
Cranktrain लिखाDOTS is absolutely fantastic, by the way. Anything CPU heavy that happens frequently will function many times faster running in a Burst routine than it will in a Monobehaviour. The hype is mostly justified, in my experience, and especially so now that the API has settled down.
Indeed, data-oriented design is way simpler to parallelize (now that modern CPU mostly all have at least 2 or 4 cores). But we're not using DOTS here, that's why I just refered to the Job system :grinteeth:
Unless that's wishful thinking on my part and he's just adding it to each 4.x milestone list as a cruel joke, which I doubt.
I'm afraid it's not a cruel joke, but simply due to that work being quite a bit more than 1 month of one devs time. It's also non-trivial, as the data layout needed for DOTS is so far away from what we actually have (and need), that it constitutes a complete rewrite of the Spine Unity Runtime. All of that, while the "old" system needs to keep working and gets bug fixed and updated for new Spine features. I understand that's frustrating, but it's a function of our team size paired with what most of our users need. Displaying hundreds of complex skeletons on screen at the same time is not generally a use case many of our users have.
walker metrics
Those appear to be rather heavy to be honest. Here are Spineboy's metrics a rather complex sample character that comes with Spine.
Note that Spineboy is a character that takes up a lot of the screen, e.g. in a platformer, so he has tons of detail to pop out of the display. All your walkers have more vertices and triangles than him, which is what will dictate your computational requirements.
Now, you say you are displaying hundreds of walkers on screen at once. That would mean, you have a very zoomed out view, in which case your walkers will not take up a lot of screen space. Chances are, all that detail your artists are baking in will get lost in the zoom. Like here:
Even in 4k, there's simply no way to see all that detail your skeletons have.
Here are a few proposals:
- Cut down on the number of vertices in your meshes, and if possible, use regions (rectangles) instead of meshes where possible. At this detail level, you can get pretty much the exact same look if you use shear in addition to translation, scale, rotation. I know that going back in and modifying those skeletons can be quite a bit of work, but it will definitely pay off. If you share one of the skeletons with us, we can possibly give you tips on how to best approach this (either here or via contact@esotericsoftware.com).
- I assume you do cull walkers outside the viewport? If so, simply disable their animation updates while they aren't in view. The underlying AnimationState is stateless, so it suffices to keep track of the animation delta time until the character is in view again, and only then do a full update of the animation state and skeleton.
- If too many skeletons are displayed at once at a time, you can opt to update their animation state only ever other frame. E.g. half the skeletons get updated on odd frames, the other half gets updated on even frames. That will effectively cut down the processing time in half, and is what you usually do for things like path finding as well. Again, the scale plays to your advantage, as the effective halfing of the animation framerate is unlikely to get noticed. You may also only opt to do this if too many skeletons are on screen.
The remake is targeting desktop machines, so you may actually get away with not doing any of the above, especially modifying the skeletons and animations themselves. However, a few items are quick wins and likely quite easy to implement without a degradation of your game's quality.
The Spine Unity Runtimes support baking, but it has limits requiring you to rework your animations/skeletons and may actually not give you a huge performance boost in return: spine-unity Runtime Documentation: Skeleton Baking
The remake looks dope btw!
To add to Mario's great advice, you might try using prune to reduce your vertex transforms, if you haven't done that yet. Try not to have more than 3 bones with weights for a single vertex. Use only 2 bones or even 1 bone with weights for a vertex where you can.
There are a number of clever tricks to get nearly the same look, but they are generally dependent on the look you need. The more you can simplify, the less work the runtimes have to do each frame. When you are displaying many skeletons, a small savings gets multiplied. That combined with using a single skeleton for multiple on screen instances (say 5 skeletons for 25 or 30 units), updating every other frame, and other techniques can cut the work required down to a fraction. There are tradeoffs, so you'll need to experiment and see what works best for you without sacrificing quality.
Oh I LOVED this game as a child, this fills my heart with pure joy. :heart:
If I may chime in, when showing the metrics please make sure to show them in animate mode, possibly with the animation that you're playing at runtime so that we can also see what the metrics for those are. (for example if there are deform keys, if maybe there are too many timelines or keys, etc.)
In case, I'd also love to take a look and help figuring it out if you send the files in question to our email: contact@esotericsoftware.com
First of all: your game looks great! :nerd:
Mario लिखा2. I assume you do cull walkers outside the viewport? If so, simply disable their animation updates while they aren't in view. The underlying AnimationState is stateless, so it suffices to keep track of the animation delta time until the character is in view again, and only then do a full update of the animation state and skeleton.
I assume you're already using it, but mentioning just in case:
Please note that the spine-unity runtime skeleton components provide anAdvanced - Update When Invisible
parameter which can be set to automatically disable and enable animation updates.