Implementing batching
H'Ok, so here's the earth... no wait, this is not the end of the world...
So. I got the FPS issues fixed for now at least. I implemented something I call the "Pipeline". I like fancy names for simple things! Makes them sound... more complicated.
It's basically a bunch of dynamically created VertexBuffers and sorting algorithms.
To begin with, I changed my quad rendering code to use TriangeLists instead of TriangleFans to deal with the texture problem. I also added an IndexBuffer. That didn't affect the FPS (yet) as I was still doing waaay too many DrawIndexedPrimitives calls.
Well, okay. As I had mentioned earlier, I had succesfully batched vertices in the tile map and got a big FPS boost. Now as I had some code to generate a VertexBuffer and IndexBuffer with TriangleList-style rendering, I could batch them and the textures would appear correctly too.
So the batching worked wonderfully. There's a few things to mention though:
If I wanted to use lights for a quad, it would have to be separated from the batch (I use lights to dim tiles to highlight the area a unit can move to)
If I wanted to use a different texture, it would again have to be separated from the batch (except if using a texturemap and changing vertex U and V values)
So to cope with those, I create the Pipeline-class.
The basic principle of the Pipeline goes something like this:
-Create new quad(s)
-Add quads to the pipeline
-Have the pipeline process the quads
-Now you can render them using the pipeline
Now the magic of the pipeline is done in the processing part.
When adding quads to the pipeline, they first go into a list.
The Pipeline has a method which processes the quads added:
-Loop though "free" quads
-Check if there's a PipelineBuffer with similar features as the quad
-If we found a buffer, add the object to it
-If not, create a new buffer with the quads properties
-Clear free quad list as they should be assigned to a buffer now
Free quads are ones which aren't yet assigned to any PipelineBuffer
A PipelineBuffer is an object which holds quads. It can generate a VertexBuffer based on the quads and an IndexBuffer. It also contains details of the lights used, the material used and the texture used, so quads which can be batched together can be sorted from the free list and added to the buffer.
It also has flags determining the type of the vertexbuffer (dynamic or static) and if it's "dirty".
If a PipelineBuffer has the dirty flag, it means the data inside it has changed (like a quad has got a new light and can't be batched with the others anymore) and has to be re-initialized.
Quads in a dirty buffer are dumped back into the free quad list and re-assigned.
The dirty mechanism is done in a simple manner: a quad contains an event which is triggered whenever a value which makes batching different is changed (light, material, texture or dynamic/static flag). When adding a quad to the PipelineBuffer, the buffer adds it's handler for the event.
Comparing to the earlier batching, without indexbuffers and without batching the 15 or so units which were also rendered:
1. No batching, 20x20 map, about 15 units - 45 FPS
2. Batched 20x20 map, non-batched 15 units - 100-150 FPS
3. Batched 20x20 map and 15 units, with IndexBuffers - 650-750 FPS!
1. used 20 * 20 + 15 = 415 DrawPrimitive calls
2. used 16 DrawPrimitive calls
3. used 2 DrawIndexedPrimitive calls (units in a dynamic buffer, if not, one call)
All this good.. and something bad too: lightning broke up. For some reason, tiles using Diffuse lights show up in black now, no matter what I try. Any input welcome.
Using Emissive lightning for now, which works just fine.
Edit 10. Jun: About matrix translations:
Matrix translations are replaced with "vertex translations". I still use a location Vector3 structure, but I don't apply a World translation. Instead, I offset the vertices in model space when defining them. Works just as fine. Using a matrix translation would yet again need me to separate things from bathing.
And here's some links related...
Bitwise Flags with Enums (samples in C#,VB.NET and TSQL)
GameDev.net forum post on efficient rendering
A C++ article on drawing 2D in D3D using quads.. has some quad-batching examples
A very deep look into C# delegates and events
Labels: C#
0 Comments:
Post a Comment
<< Home