At first I thought Ultimate Epic Battle Simulator was just a joke (an army of chickens defeats Roman legions in the trailer), but gameplay videos seem to show unusually large numbers of troops (with relatively good framerates), such as this one:
So how did they get so many animated figures in play at the same time?
Obviously, there are some physics quirks. A battle between 10,000 Chuck Norris clones against 10,000 armored knights results in the Chuck Norris clones only slowly making headway, whereas in real life we all know even one Chuck Norris could easily win against 10,000 armored knights using nothing but his left pinky; so the realism is a bit wonky.
Focus on the soldiers that are close up and then focus on the soldiers that are far away. Up close the units are receiving a good deal of animation but the farther away they are the less animated they become.
Well, rather than process the animations based on bones, they are just cycling through what appears to be a handful of pre-animated models. Only the few in the front line are actually animated. Thus, much less processing power, all it’s really doing is writing stuff to the vertex buffer and then the graphics card takes care of the rest. Still interesting.
I saw an asset that this brings to mind, where the distant units were billboarded as animated sprites, and it was pretty convincing, made up close units have detailed LOD and the far ones were simple quads with an animated sprite angled to represent the units… it even did the sprite generation automatically and everything. I think the demos of that asset showed something like 10k units? If I remember correctly? But… that is a lot, and tricks could be used to simulate a larger crowd which are little more than pixels at the distances they are at…
Right, they’re essentially baking the animations into the meshes. Which makes sense because as far as I’m aware Unity’s GPU instancing doesn’t support skinned meshes. Someone who wanted skinned meshes would have to add support for it themselves. Speaking of handling large numbers of meshes I found this thread from four months ago with more details.
They write to one big vertex array that have all the character and use offset to access single character, ie no transform, no animation, one mesh, everything is made by “hand” using their own process.
If you want to have a huge number of units, assume you will not use a game object for each unit. Create a custom struct that will hold information about one unit, and then make an array of that struct. Then use GPU instancing API methods to draw units with very few draw calls. Check out Graphics.DrawMeshInstanced at
And instead of using normal animations, you need to bake the animations into static meshes. Then you can select which mesh to draw using the GPU instancing. Part of the custom struct will be an index of which animation is currently playing for each unit. Your code will combine units at the same animation index into the same GPU instancing groups.
You code will need to manually decide what the units will be doing in the scene, including moving and attacking other units, and update unit details within your array of your custom struct.
There’s an asset on the asset store called “Mesh Animator” or something like that, it helps you do this as well. In the video you can see that the fps is pretty bad, he’s getting about 10-15 fps. But that number of characters on screen is impressive I bet you could have a 60+ fps game with about 3k troops on each side. Which is still really good. I love games with large numbers of units in them lol.
Sure, but in the Total War series the AI is done entirely at the regiment / cohort (etc) level, whereas in UEBS individual soldiers are clearly doing their own thing, as you can see by watching how they gradually curl around the enemy flanks one by one. In a Total War game, an entire group might maneuver around the flank, but individual soldiers are just offset from that group.
I believe In total war individual soldiers were particles and not part of the regiment. I think I recall them breaking formation during fights, etc. You won’t get this kind of behavior by making them a “part of regiment”.
Similar system was used in black and white 2, by the way. Meaning that while individual units weren’t running an AI, they would stil avoid obstacles, etc. Basically, you need to reduce a “soldier” from a full blown object to a set of a few floats. (for example… position, movement vector, maybe animation frame). Doing that will turn it into a “particle” which can be then fed into a shader.
The developer of that, or something very similar, has talked a fair bit about it on the forums.
People saying it’s impossible to do this kind of thing in Unity are almost always referring to using the built-in, general purpose tools. Those tools simply aren’t built for this kind of use case.
I’ve done something similar myself, albeit less graphically focused. In my project rendering wasn’t really a concern, but we still had to handle all of the “physics” side of things. We did it by making a custom system built specifically around the types of interactions we needed.
In our tests, for our needs Unity’s built-in systems topped out at around 6,000 units on our target hardware. A simple test with a mockup of our custom system had several tens of thousands on the same hardware. Rendering wasn’t the bottleneck in either case. We did have a bunch of ideas to push the limit up further, but since we’d already exceeded our spec’d requirements we didn’t get to try any of those out.
Basically, Unity’s built in stuff is great, but it’s built to meet broad and generic requirements. There’s plenty of savings to be had if you figure out specifically what your unique case needs and build something custom that only does that, in the most efficient way possible.
That makes sad, because the more I document myself on that, the more I see I need custom physics, and nobody will do it for me lol, I’m not a programmer damn it!
Unfortunately for nonprogrammers, that is just the way it is when you need to push the limits in a game. Pushing the limits nearly always involves writing custom code.