| Efficiently Rendering Dynamic Vertices |
|
|
| Written by Markus Ewald | |||
| Monday, July 27 2009 19:59 | |||
|
Sometimes, games have to render highly dynamic geometry such as sparks, bullet trails, muzzle flashes and lightning arcs. Sometimes it's possible to off-load the work of simulating these things to the GPU, but there are effects than can't be done by the GPU alone. These cases usually occur when effects require heavy interaction with level geometry or when they require lots of conditionals to mutate a persistent effect state. And sometimes, the effort of simulating an effect on the GPU is just not worth the results. If you have maybe a hundred instances of a bullet trail at once, letting the GPU orient the constrained billboards for the trails instead of generating the vertices on the CPU might just not yield any tangible benefits.
However, there are still a lot of traps you can run into. A typical mistake of the
unknowing developer is to render the primitives one-by-one either using one
This is not a good idea because modern GPUs are optimized for rendering large numbers
of polygons at once. When you call By sending single primitives to the GPU, this per-call overhead is multiplied and can become a real bottleneck. To demonstrate the effects of making lots of small drawing calls, I wrote a small benchmark and measured the results on my GeForce 8800 GTS 512 and on whatever the XBox 360 uses as its GPU.
To render such dynamic geometry efficiently, you need to collect the primitives into
larger batches. For example, by appending them to an array until it is full and then
doing a single
This introduces several new problems, however. If your effects are rendered using
different textures or even different effects, you can not use a single
This essentially is what XNA's
In my latest game, however, I needed to render 3D primitives and the
It took me several evenings of pedantic, brain-melting coding and refactoring to support all the different primitive types without any off-by-one errors which might lead to a primitive not drawing at all or, even worse, all further primitives to be off by one vertex causing triangles to connect the wrong vertices. In that regard, unit testing really helped a lot.
First I needed to design the
PrimitiveBatch might encounter. That uncovered quite a few
problems hiding in the code and waiting to be tripped in my game at unexpected times.
Luckily, after fixing them all and integrating the PrimitiveBatch into my game,
not a single issue has surfaces and everything draws just as it did before with the
individual DrawIndexedUserPrimitive() calls, just way faster :D
|


Comments
RSS feed for comments to this post