Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is best practice for batch drawing objects with different transformations?

I'm conceptualising a good approach to rendering as many disjointed pieces of geometry with a single draw call in OpenGL, and the wall I'm up against is the best way to do so when each piece has a different translation and maybe rotation, since you don't have the luxury of updating the model view uniform between single object draws. I've read a few other questions here and elsewhere and it seems the directions people are pointed in are quite varied. It would be nice to list the main methods of doing this and attempt to isolate what is most common or recommended. Here are the ideas I've considered:

[edit: removed mention of Instancing as it doesn't really apply here]

  1. Creating matrix transformations in the shader. Here I'd send a translation vector or maybe a rotation angle or quaternion as part of the attributes. The advantage is it would work cross-platform including mobile. But it seems a bit wasteful to send the exact same transformation data for every single vertex in an object, as an attribute. Without instancing, I'd have to repeat these identical vectors or scalars for a single object many many times in a VBO as part of the interleave array, right? The other drawback is I'm relying on the shader to do the math; I don't know if this is wise or not.

  2. Similar to 1), but instead of relying on the shader to do the matrix calculations, I instead do these on the client side but still send through the final model view matrix as a stream of 16 floats in the VBO. But as far as I can tell, without instancing, I'd have to repeat this identical stream for every single vertex in the VBO, right? Just seems wasteful. The tradeoff with 2) above is that I am sending more data in the VBO per vertex (16 floats rather than a 3-float vector for translation and maybe a 4 float quaternion), but requiring the shader to do less work.

  3. Skip all the above limitations and instead compromise with a separate draw call for each object. This is what is typically "taught" in the books I'm reading, no doubt for simplicity's sake.

Are there other common methods than these?

As an academic question, I'm curious if all the above are feasible and "acceptable" or if one of them is clearly a winner over the others? If I was to exclusively use desktop GL, is instancing the primary way for achieving this?

like image 248
johnbakers Avatar asked Apr 21 '13 07:04

johnbakers


2 Answers

Two considerations:

Generally speaking, if you have multiple objects, with each object using independent transforms, you use multiple draw calls. That's what they're there for. The old NVIDIA "Batch Batch Batch" presentation cited between 10,000 and 40,000 draw calls per-frame (in D3D. More in GL) for a 1GHz GPU. Nowadays, you're looking at rather more than that. So unless you're dealing with tens of thousands of individual objects, all of them being different (so no instancing), odds are good that you'll be fine.

Another idea:

Take the modelview matrix calculations out of the shader entirely and just pass the vertices after multiplication. This allows a single draw call for many objects in different orientations and translations. The cost just comes at all the CPU calculations, but I suppose if that bottleneck is not as big as the bottleneck of multiple draw calls, it would be worth it.

(Taken from here.)

like image 182
johnbakers Avatar answered Nov 19 '22 00:11

johnbakers


Here's an alternate idea:

Give each vertex an object ID that is passed in via an attribute. Then in the vertex shader, use this ID to do a lookup in a texture where you store your transformation matrices.

like image 34
Taylor Avatar answered Nov 19 '22 00:11

Taylor