Hi!
I'm working on a game (targeting PC, Mac, Linux) that probably uses a number of Spine characters at once that perhaps would be far higher than expected or supported. Here's my current benchmark, when running 81 animating skeletons of the nature discussed further below:
Loading Image
I would love to bring that 41% down as low as possible. My goal would be to have there be up to 100 zoo visitors at 60fps, but 80 drags it down to 30fps. I understand that SkeletonRenderer.LateUpdate and SkeletonAnimator.Update do a fair bit of work, so what I'm probably looking for are some hacky-approaches that save me some CPU time, but more on that in a bit. First, I've got to do my due-diligence based on what has already been said on these forums on the subject of performance. Sixth months ago Pharan wrote a helpful pointed list to go through to improve performance:
1) Minimize the number of keyed properties in spine. For example: If a bone doesn't need to rotate, don't give it a key to rotate. Anywhere. That item shouldn't have a row in the dopesheet. Each row in the dopesheet is extra overhead. So even if you only have 1 key on it, it'll eat up resources. (Each dopesheet row is one Timeline runtime object that the runtime has to iterate over every Update an animation makes.)
Done! As a result my animations are a bit more mechanical than they used to, but I'm approaching all my timelines with an ascetic approach.
2) Have as few bones and attachments as possible.
Ah, now, I think I'm pretty good on the Bone front. Here's the skeleton in question, the one I had 81 of in the benchmark:
Loading Image
I think the Bones count is inoffensive. I probably could go down to two spinal bones, but would have to go through all my animations to correct for it, so I'm leaving that until I absolutely have to.
The Attachments count, however, are quite high. There are 178 attachments because I have half a dozen skins that share the skeleton. For the skin displayed above, there are just 26 attachments. I imagine the answer is 'of course not' but attachments in skins that aren't displayed in Unity don't drag down the performance, do they?
3) If you can help it, don't use meshes and FFD. And if you really need meshes for these skeletons, minimize their vertex count.
The skin screenshot'd above is entirely made of meshes. But the other 80 skeletons are displaying one of the two Visitor skins, which don't have any meshes.
4) If your skeletons are for looping environment stuff, and you want want it to play one animation over and over, Baking may be a good option, especially if you just want it to do a Weighted/Skinned animation. Baking will take advantage of the GPU to animate the meshes and free up your CPU to do the more controlled things. For maximum compatibility with Unity GPU skinning settings, make sure each VERTEX is bound to a maxmimum of two bones.
I'm really not too keen on baking stuff, because I want to ragdoll these skeletons later on, if I possibly can. I suppose I could swap out a baked version with a non-baked version. The player can't be baked because I'm mixing animations too much, but that's just one skeleton. I've not actually baked anything with Spine/Unity yet, so I don't know how baking to 60fps and displaying that would perform? Can anyone with some experience in this area make any educated guesses as to how that would turn out?
My Ideas
I've had a few thoughts, that essentially come down to what I described earlier as hacky approaches to this problem. For full context, here's a screenshot of the game, showing the one player Skeleton, and some of the eighty Visitor Skeletons:
Loading Image
My first idea is the obvious one, which is just not animate anything that's not on camera. Easy gains there, I'm sure.
The second idea is for skeletons that are far enough away from the camera, to just update their animations at 30fps, even less. The lack of smoothness is very noticeable up close, but I'm guessing less so further away. Slipping a:
if (Time.frameCount % 2 == 0) return;
into the slow LateUpdate and Update methods does really help, but of course I'll have to spread the updates-by-frame across the two frames, otherwise, spikes!
These are the ideas I've got, hopefully I've given enough context in this post to help you with your own suggestions, which are very appreciated. Feel free to ask questions, if I've missed anything.