Masses of animated units kill performance

Started by
7 comments, last by Hannibal2400 9 years ago

Hey guys,

I'm stuck with a problem that I can't solve on my own. I'm writing a game with a ton of units (aiming at several thousands) and I'm making progress. However I now encountered a problem caused by the mass of units. As soon as animations desynchronize the performance breaks down from 100 to 30 fps. The way I understand it it's due to the high amount of draw calls.

I tried to find a solution and read that usually this is solved through geometry instancing. However I'm not very experienced in graphics programming and the Irrlicht engine which I use doesn't seem to have an out of the box solution. Does anyone know if and how it would be possible with this engine? And if it's not possible is there any other engine that can do it or do I have to go down to programming with DirectX?

Advertisement

Offhand, I'd say animate one (or a handful) and copy their position elsewhere and render them again there. Animating hundreds of objects individually is (as a general rule) going to be costly. I'm not familiar enough with irrlicht to suggest how to go about this within the engine, but I would assume it's doable. Perhaps someone has a better approach with irrlicht, but it would be the way I'd go about it.

As a related question, are you loading a separate mesh and everything for each object, or just one and copy the mesh over to each instance of the object? The approach would be similar to the latter method, but with the animation as well.

Beginner here <- please take any opinions with grain of salt

One solution which might be applicable without dealing with engine guts is: ensure the animations are started on a discrete basis.

Example: have all animations spawned in a frame begin at the end of the frame so there will be only 30/60 possibilities for a given animation. This is still a lot of work but still a world better to use the true "instantiation time", which would give you possibly thousands of different positions to compute!

Previously "Krohm"

See March of the Froblins

done that mistake myself some time ago... yes, having many non-static non-batched meshes kills performance. The draw calls will add up.

Now I don't know much about the Irrlicht engine, but I might still make some general suggestions:

1) find a way to batch or instance animations and these non-static meshes... I haven't had to do that myself until now, but there are many online resources on what to do with crowd aniamtions. One of the oldest and most famous one must be this GPU Gem from Nvidia:

http://http.developer.nvidia.com/GPUGems3/gpugems3_ch02.html

No idea if this is still up to date, and of course it means you need to mess around with shader programming. Also it seems to use DX10 functionality so if you want to target DX9, that might not work for you.

Maybe have a look if Ubisoft published any article or postmortem on how they handle the crowd animations in Assassins Creed games.

2) Look up what DX12 brings in batching capabilities. I know, this might not help you today or even next year, but at some point, the Drawcall chokepoint we have today will hopefully go the way of the dodo, with the ability to batch even non-static non-instanced meshes into a single drawcall. How that will work, if it will help you in your scenario IDK, others might be able to help you more who had more exposure to DX12 yet.

And of course, just because 1000 animated characters do not need 1000x<amount of drawcalls per character> drawcalls doesn't mean it is a good idea to have that many characters running around without any kind of optimization. After the drawcall bottleneck is gone, it might be either the CPU or the GPU is choking on skinning 1000 characters individually...

3) Cheat more. If you have 1000 characters running around, do you really need them to be skinned characters... could you get away with unskinned ones? Can you create more aggressive LODs which include cutting out bones and simplifying animations if the camera is far away? Maybe even omitting animations for characters that are only the size of some pixels?

If you can do that, at least for the unanimated character instanciating and batching becomes much easier.

according to their website, Irrlicht supports dx8.1 and dx9.

http://irrlicht.sourceforge.net/features/#drivers

true instancing doesn't arrive until dx10.

there is a dx9 workaround which they might implement.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

Imposters might be a good solution for this kind of problem, but as you say you are inexperienced with graphics programming they may also be prohibitively complicated to implement.

Might be worth at least searching the irrlicht to see if they have support for imposters.

i just ran across this Irrlicht multi animation demo while googling "d3dx animation controller"

http://irrlicht.sourceforge.net/forum/viewtopic.php?t=18987

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

Thank you very much guys for your answers so far.

Offhand, I'd say animate one (or a handful) and copy their position elsewhere and render them again there. Animating hundreds of objects individually is (as a general rule) going to be costly. I'm not familiar enough with irrlicht to suggest how to go about this within the engine, but I would assume it's doable. Perhaps someone has a better approach with irrlicht, but it would be the way I'd go about it.

As a related question, are you loading a separate mesh and everything for each object, or just one and copy the mesh over to each instance of the object? The approach would be similar to the latter method, but with the animation as well.

It doesn't make a difference wether I load the mesh every time or I use a copy because the engine automatically uses the same instance if it sees I'm loading from the same path. I did try using the same animated mesh scene node for every unit by moving it to every position and rendering it. It helps with the performance a bit but not enough.

One solution which might be applicable without dealing with engine guts is: ensure the animations are started on a discrete basis.

Example: have all animations spawned in a frame begin at the end of the frame so there will be only 30/60 possibilities for a given animation. This is still a lot of work but still a world better to use the true "instantiation time", which would give you possibly thousands of different positions to compute!

I'm not quite sure I understand you. Do you mean I should synchronize the animations? I tried something similiar. I noticed that the engine also animated the joint nodes between animation frames. So even though there might only be 10 animation frames the frame number is a float and can take any value resulting in an almost infinite amount of different animation states. I now manually set the frame number so it can only change by steps of 0.5 which limits the animations a lot and gave me quite a boost in performance. And the steps are small enough to not be noticed as unsmooth. However I'm still not satisfied.

done that mistake myself some time ago... yes, having many non-static non-batched meshes kills performance. The draw calls will add up.

Now I don't know much about the Irrlicht engine, but I might still make some general suggestions:

1) find a way to batch or instance animations and these non-static meshes... I haven't had to do that myself until now, but there are many online resources on what to do with crowd aniamtions. One of the oldest and most famous one must be this GPU Gem from Nvidia:

http://http.developer.nvidia.com/GPUGems3/gpugems3_ch02.html

No idea if this is still up to date, and of course it means you need to mess around with shader programming. Also it seems to use DX10 functionality so if you want to target DX9, that might not work for you.

Maybe have a look if Ubisoft published any article or postmortem on how they handle the crowd animations in Assassins Creed games.

2) Look up what DX12 brings in batching capabilities. I know, this might not help you today or even next year, but at some point, the Drawcall chokepoint we have today will hopefully go the way of the dodo, with the ability to batch even non-static non-instanced meshes into a single drawcall. How that will work, if it will help you in your scenario IDK, others might be able to help you more who had more exposure to DX12 yet.

And of course, just because 1000 animated characters do not need 1000x<amount of drawcalls per character> drawcalls doesn't mean it is a good idea to have that many characters running around without any kind of optimization. After the drawcall bottleneck is gone, it might be either the CPU or the GPU is choking on skinning 1000 characters individually...

3) Cheat more. If you have 1000 characters running around, do you really need them to be skinned characters... could you get away with unskinned ones? Can you create more aggressive LODs which include cutting out bones and simplifying animations if the camera is far away? Maybe even omitting animations for characters that are only the size of some pixels?

If you can do that, at least for the unanimated character instanciating and batching becomes much easier.

Actually I do plan to "cheat" but first I want to optimize it as far as I can without it. I might also use 2D sprites for units that are far away which will help a lot. The reason why I don't only want to do LOD is because there will be occasions with very crowded areas where LOD won't help. I will probably have to use some shader programming which I will first have to learn. DX12 will probably be too complicated for an amateur like me, at least in the near future, and it will also not be supported by a lot of computers so older API will remain necessary.

Imposters might be a good solution for this kind of problem, but as you say you are inexperienced with graphics programming they may also be prohibitively complicated to implement.

Might be worth at least searching the irrlicht to see if they have support for imposters.

If by imposters you mean rendering textures instead of meshes for objects far away then I do plan on doing that aditionally to the other optimization.

i just ran across this Irrlicht multi animation demo while googling "d3dx animation controller"

http://irrlicht.sourceforge.net/forum/viewtopic.php?t=18987

That actually looks great and runs pretty well on my computer. I'll look into it. As it seemsI will have to do some raw DirectX if I want to get the results I desire. I actually did try to start with DirectX but Microsoft changed some stuff in the SDK and I can't really get the instructions in books and tutorials to work because they use libraries that don't exist anymore. (Edit: I found an older version of the SDK so I'll start learning DirectX. Though I don't know if it's wise to use an old SDK.)

If I can't get the results I want I will have to lower the scale of the game and get along with less units. However I'm not giving up till I tried everything within my capabilities.

This topic is closed to new replies.

Advertisement