Batching textured quads using BasicEffect and PrimitiveBatch

May 14, 2013 at 5:35 PM
Edited May 14, 2013 at 5:36 PM
I've been struggling a bit to get this working the right way.. figured I'd give this forum a try.

I'd like to batch a textured billboard quad draw using BasicEffect and PrimitiveBatch.. but I'm not sure how to go about doing this.

What I'm trying to do looks something like this:

// Setup during initialization
BasicEffect* be = new BasicEffect(dc);
be->SetTextureEnabled(true);
be->EnableDefaultLighting(true);

// Load shader blob using BasicEffect and Create input layout using
// VertexPositionNormalColorTexture in DirectXTK
// Create PrimitiveBatch<VertexPositionNormalColorTexture> 

// Every Update Call 
be->SetProjection(camera->GetProjection);
be->SetView(camera->GetView);

// Every draw call
be->SetTexture(myTexture);
be->Apply(dc);
dc->IASetInputLayout(myLayout);
primitiveBatch->Begin();

for(auto it = billboards.begin(); it != billboards.end(); it++)
{
    be->SetWorld(it->GetWorld());
    be->Apply(dc);
    primitiveBatch->DrawQuad(/* draw quad vertices untransformed */);
}

primitiveBatch->End();
In case it's not clear from my code, I'm trying to save to the perframe const buffer the final world translation of each billboard in the effect before calling primitiveBatch draw. The only way I can get this to work properly is do a PrimitiveBatch::Begin() and ::End() call per billboard with each having the basic effect's world translation set each time before the call to ::Begin().

Also, even with my non-batch like calls to PrimitiveBatch, my billboards do not draw in the correct order... Although they do show up as transparent, when placed next to each other, they seem to clip each other. Do I have to manually order each one before drawing in the batch based on its z value?

Thanks!

Jared
Coordinator
May 14, 2013 at 7:48 PM
You cannot change state settings in between individual draw calls within a single batch. The whole point of a batch is to 'batch' up many draw calls, then submit them to the GPU all in one go. So by definition, it's impossible to have a different state for each draw, because there is really only one single combined draw taking place.

The simplest solution is to use a separate batch (begin/end block) for each object that you want to draw using a different state. First set the state, then begin the batch, then draw, then end the batch.

A more efficient approach is to draw everything in a single batch, and change your rendering algorithms so that all the objects within the batch can use the same state. This means no longer applying a different world matrix to the effect per draw. One way to do that would be to leave the effect world matrix set to identity, and instead apply that same transform to your source vertex positions on the CPU, before passing them to PrimitiveBatch.

An even more efficient but complex way to draw very large numbers of billboards is to do the billboarding computation inside the vertex shader. I don't know of a good D3D sample showing this technique, but the XNA Particle 3D sample uses this idea.
May 14, 2013 at 8:14 PM
Thanks Shawn, this is very helpful. I'll take your advice and do a XMVector3Transform() to transform my positions on the CPU using the billboard's world matrix before rendering, keeping each billboard using the same state for the batch.

The 2nd concern I had was the ordering of the billboards when they were drawn. Giving each billboard its own separate batch had them clipping each other. Do I have to sort manually via Z order before drawing or is there a way to have PrimitiveBatch do the right thing?

Thanks again for your help!

Jared
Coordinator
May 15, 2013 at 3:22 AM
This article might help with your question about depth sorting:

http://blogs.msdn.com/b/shawnhar/archive/2009/02/18/depth-sorting-alpha-blended-objects.aspx
Marked as answer by walbourn on 1/23/2014 at 11:27 PM
May 15, 2013 at 5:55 AM
That article was perfect! It really helped me understand what was actually going on and how to draw my billboards correctly. My rendering looks great now and is batched together.

Thanks again Shawn! Also, it seems like your blog has a wealth of free information. I'll be studying up on it a lot in the future :)