Forgive me if this question comes across as vauge, but I was trying to figure out the typical number of "objects" that a decent game engine can handle. What I mean by "objects" is logically independent instances, which (in my experience) meet the following requirements:
- They are not part of a larger mesh or generated through a texture (ie POM, relief mapping or whatever else)
- Require their own draw calls (instancing can be taken into consideration)
- Are capable of using physics (but do not have to be using them)
- Have their own components for an independent world matrix (position, rotation, scale)
From what I have seen, it seems like in some engines most objects that appear to be just laying around are actually embedded into the terrain or building mesh (ie Fallout 3) and some engines have several hundered "real" objects just lying around (ie Half Life 2).
I am just getting a bit concerned about how my engine can support rather large polycounts, but begins severley lagging when more than about 280 simple objects are rendered. If there are 400 objects in the scene at once, I don't even have to draw them and it still drags the framerate down (which is probably a culling efficiency issue).
Thanks for any help
Max number of "independent" objects in a scene
Started by starstutter, Oct 05 2009 04:29 AM
5 replies to this topic
#1
Posted 05 October 2009 - 04:29 AM
(\__/)
(='.'=) This is Bunny. Copy and paste bunny into
(")_(") your signature to help him gain world domination.
bunny also wants to fight spam: Click Here Bots!
(='.'=) This is Bunny. Copy and paste bunny into
(")_(") your signature to help him gain world domination.
bunny also wants to fight spam: Click Here Bots!
#2
Posted 05 October 2009 - 06:48 AM
Culling and batching are essential to achieve decent performance.
When it comes to batching, it is really necessary to do what you can to keep the number of calls to DrawPrimitive/DrawIndexedPrimitive down. I would say to keep it between 500-1000 per frame, maybe a little higher for a game which targets high-end hardware only. Considering that many objects may use several draw calls (when using different materials), this can severely limit the number of objects you can draw. If you can bake objects into larger environment chunks, and use a texture atlas so you can render it in one drawcall, that's a good thing. If you have small objects (hundreds of polys rather than thousands), it is often a win to transform them on the CPU, and fill a dynamic vertex buffer with them, so you can draw them in one drawcall (again, assuming texture atlas to make this possible). But as always, you need to measure what works for your specific game. We used the technique to great effect in this game where people in the far distance (lowest lod) were extremely simple stick figures with only a handfull of vertices, all transformed on the CPU and rendered in one draw call.
But of course, the best thing is not to draw the thing at all, after determining that it is not in view. Having small objects disappear altogether at a certain distance from the camera is not a bad idea. Using things like quadtrees or octrees is a great way to cull large sets of objects in few operations, and essential when you have many objects. Generally speaking, you want your culling to reject as much as possible in as few operations as possible.
It is also important to consider LOD for the logic of some objects. A lot of things can be simulated much simpler when an object is out of view or in the distance - even for things like AI, decisions can be made less frequently when an entity is off-screen or far away. In this game, we simulated tens of thousands of people, by keeping the simulation simple when entities weren't visible. Also, when you have large number of objects which you update every frame, cache coherency becomes a major issue, and can often make as much or greater difference than choice of algorithm or implementation. Make sure to keep such objects as small as you can, and allocate them in contiguous memory blocks (you could use things like memory pools or free lists).
Achieving high performance with large number of game objects is not trivial, and it does take a lot of time - and you need to constantly measure and re-measure CPU-time, memory use and GPU-characteristics every step of the way - constantly run your profiler and PIX and/or the nvidia profiler as well as add your own stats on-screen, to make sure you're moving in the right direction. Whatever you do, don't assume that your framerate counter will be enough to judge if you've achieved a performance gain (it's not even a linear measurement!).
When it comes to batching, it is really necessary to do what you can to keep the number of calls to DrawPrimitive/DrawIndexedPrimitive down. I would say to keep it between 500-1000 per frame, maybe a little higher for a game which targets high-end hardware only. Considering that many objects may use several draw calls (when using different materials), this can severely limit the number of objects you can draw. If you can bake objects into larger environment chunks, and use a texture atlas so you can render it in one drawcall, that's a good thing. If you have small objects (hundreds of polys rather than thousands), it is often a win to transform them on the CPU, and fill a dynamic vertex buffer with them, so you can draw them in one drawcall (again, assuming texture atlas to make this possible). But as always, you need to measure what works for your specific game. We used the technique to great effect in this game where people in the far distance (lowest lod) were extremely simple stick figures with only a handfull of vertices, all transformed on the CPU and rendered in one draw call.
But of course, the best thing is not to draw the thing at all, after determining that it is not in view. Having small objects disappear altogether at a certain distance from the camera is not a bad idea. Using things like quadtrees or octrees is a great way to cull large sets of objects in few operations, and essential when you have many objects. Generally speaking, you want your culling to reject as much as possible in as few operations as possible.
It is also important to consider LOD for the logic of some objects. A lot of things can be simulated much simpler when an object is out of view or in the distance - even for things like AI, decisions can be made less frequently when an entity is off-screen or far away. In this game, we simulated tens of thousands of people, by keeping the simulation simple when entities weren't visible. Also, when you have large number of objects which you update every frame, cache coherency becomes a major issue, and can often make as much or greater difference than choice of algorithm or implementation. Make sure to keep such objects as small as you can, and allocate them in contiguous memory blocks (you could use things like memory pools or free lists).
Achieving high performance with large number of game objects is not trivial, and it does take a lot of time - and you need to constantly measure and re-measure CPU-time, memory use and GPU-characteristics every step of the way - constantly run your profiler and PIX and/or the nvidia profiler as well as add your own stats on-screen, to make sure you're moving in the right direction. Whatever you do, don't assume that your framerate counter will be enough to judge if you've achieved a performance gain (it's not even a linear measurement!).
- www.mattiasgustavsson.com - My blog and current projects
- www.rivtind.com - My Fantasy world and isometric RPG engine
- www.pixieuniversity.com - My Software 2D Game Engine
#3
Posted 05 October 2009 - 10:11 AM
280 individual objects isnt bad... is it so important to have legions of objects in your game?!? why not design your game around a smaller group of objects and not even worry about batching.
The problem with writing generic engines is youd like to take every single game type you can think of into account, but sometimes thats not possible.
rts games need the highest object counts of all games, but they usually render those objects with minimal effects so they dont bog the game down.
Im in favour of custom engines for custom game types... just look at a 1on1 fighter for example, at most your render 2 objects at once so they can be very pretty looking and hi poly, thats the extreme end of not having to draw much so you can make it look real good and the computer can still take it.
The problem with writing generic engines is youd like to take every single game type you can think of into account, but sometimes thats not possible.
rts games need the highest object counts of all games, but they usually render those objects with minimal effects so they dont bog the game down.
Im in favour of custom engines for custom game types... just look at a 1on1 fighter for example, at most your render 2 objects at once so they can be very pretty looking and hi poly, thats the extreme end of not having to draw much so you can make it look real good and the computer can still take it.
you used to be able to fit a game on a disk, then you used to be able to fit a game on a cd, then you used to be able to fit a game on a dvd, now you can barely fit one on your harddrive.
#4
Posted 05 October 2009 - 02:55 PM
280 objects seems a little low for me...
Try to find out where the bottleneck is, if it is while rendering (try to use VBOs as much as possible and render what just needs to be rendered) ... although 280 objects with lets say 1000 triangles per each is just 280 000 triangles (and thats nothing today ... for VBOs) ... well don't know how much draw calls per object are used, so there might be bottleneck.
For me it though seems like that bottleneck is on CPU - maybe slow transfomation math (matrix math), or maybe slow vector math ... try to use some profiler on your app - to get what is causing the slowdown.
Try to find out where the bottleneck is, if it is while rendering (try to use VBOs as much as possible and render what just needs to be rendered) ... although 280 objects with lets say 1000 triangles per each is just 280 000 triangles (and thats nothing today ... for VBOs) ... well don't know how much draw calls per object are used, so there might be bottleneck.
For me it though seems like that bottleneck is on CPU - maybe slow transfomation math (matrix math), or maybe slow vector math ... try to use some profiler on your app - to get what is causing the slowdown.
My blog about game development (and not just game development) - http://gameprogramme...y.blogspot.com/
If you don't know how to speed up application, go "roarrrrrr!", hit the compiler with the club and use -O3 :D
If you don't know how to speed up application, go "roarrrrrr!", hit the compiler with the club and use -O3 :D
#5
Posted 05 October 2009 - 05:04 PM
Thanks for the help so far.
Well, understand that in this scenerio 280 objects =/= 280 draw calls. I am using cascaded shadow maps for directional lighting, so on average it levels out to around 400 draw calls. Also, polycount seems to have little to do with it, as it can render over about 1.3 million of them at a reasonable framerate (using a few very high poly models)
I think my biggest issue may be the efficiency of my culling technique. I am using sort of a hackish method, but it seems to work better than a rigid "proper" one. For closer objects I do standard 6-plane frustum culling with bounding spheres, and for further away objects I do a simple dot product test that uses the cameras direction and FoV (havent noticed any graphic glitches, and yes, it does work, I put a draw-call counter on my mesh renderer).
Still though, 280 cull tests for the camera and then perhaps twice as many for shadows is a whole lot of culling. I think Im going to try disabling the rendering of the majority of objects and see how much power the culling technique eats up alone.
Vilem Otte said:
280 objects seems a little low for me...
Try to find out where the bottleneck is, if it is while rendering (try to use VBOs as much as possible and render what just needs to be rendered) ... although 280 objects with lets say 1000 triangles per each is just 280 000 triangles (and thats nothing today ... for VBOs) ... well don't know how much draw calls per object are used, so there might be bottleneck.
Try to find out where the bottleneck is, if it is while rendering (try to use VBOs as much as possible and render what just needs to be rendered) ... although 280 objects with lets say 1000 triangles per each is just 280 000 triangles (and thats nothing today ... for VBOs) ... well don't know how much draw calls per object are used, so there might be bottleneck.
Well, understand that in this scenerio 280 objects =/= 280 draw calls. I am using cascaded shadow maps for directional lighting, so on average it levels out to around 400 draw calls. Also, polycount seems to have little to do with it, as it can render over about 1.3 million of them at a reasonable framerate (using a few very high poly models)
I think my biggest issue may be the efficiency of my culling technique. I am using sort of a hackish method, but it seems to work better than a rigid "proper" one. For closer objects I do standard 6-plane frustum culling with bounding spheres, and for further away objects I do a simple dot product test that uses the cameras direction and FoV (havent noticed any graphic glitches, and yes, it does work, I put a draw-call counter on my mesh renderer).
Still though, 280 cull tests for the camera and then perhaps twice as many for shadows is a whole lot of culling. I think Im going to try disabling the rendering of the majority of objects and see how much power the culling technique eats up alone.
(\__/)
(='.'=) This is Bunny. Copy and paste bunny into
(")_(") your signature to help him gain world domination.
bunny also wants to fight spam: Click Here Bots!
(='.'=) This is Bunny. Copy and paste bunny into
(")_(") your signature to help him gain world domination.
bunny also wants to fight spam: Click Here Bots!
#6
Posted 05 October 2009 - 07:28 PM
HOT DAMN! :)
1000 objects being drawn at once using %15 CPU at 28 fps (on a laptop ^^)
I would have tested above that, but 1000 is the current cap for the object manager (though I can raise it easily).
Also, since this engine uses deferred-everything, the framerate actually starts out at 40 fps rendering practically nothing. I favored a moderate and steady framerate over a lightning fast one that drops quickly with scene complexity.
The draw counter is reading 1800 (with shadows enabled of course) and not even a hiccup.
Well, once again you guys were right. It was a major bottleneck in my code. I disabled all rendering (except for the terrain for the sake of seeing where I was going), kept the culling algorithems and everything else. Turns out the culling bit actually had nothing to do with it. The problem spawned from a feature I wasn't even using anymore. Thankfully it didn't take me too long to track it down.
I know 1000 isn't a glorious number (compared to professional engines), but im excited anyway :D
Thanks much for the tips!
1000 objects being drawn at once using %15 CPU at 28 fps (on a laptop ^^)
I would have tested above that, but 1000 is the current cap for the object manager (though I can raise it easily).
Also, since this engine uses deferred-everything, the framerate actually starts out at 40 fps rendering practically nothing. I favored a moderate and steady framerate over a lightning fast one that drops quickly with scene complexity.
The draw counter is reading 1800 (with shadows enabled of course) and not even a hiccup.
Well, once again you guys were right. It was a major bottleneck in my code. I disabled all rendering (except for the terrain for the sake of seeing where I was going), kept the culling algorithems and everything else. Turns out the culling bit actually had nothing to do with it. The problem spawned from a feature I wasn't even using anymore. Thankfully it didn't take me too long to track it down.
I know 1000 isn't a glorious number (compared to professional engines), but im excited anyway :D
Thanks much for the tips!
(\__/)
(='.'=) This is Bunny. Copy and paste bunny into
(")_(") your signature to help him gain world domination.
bunny also wants to fight spam: Click Here Bots!
(='.'=) This is Bunny. Copy and paste bunny into
(")_(") your signature to help him gain world domination.
bunny also wants to fight spam: Click Here Bots!
1 user(s) are reading this topic
0 members, 1 guests, 0 anonymous users












