1
votes

I'm looking for a way to render many meshes at once, so that I don't have to issue a draw call for each mesh. I'm dealing with a 2D rendering here, and a typical object such as a square may have only two triangles in it. However, an object may also be quite complex and have thousands of triangles.

Now each object can move around by itself. Conceptually it's perfectly reasonable to have a VBO (or VBO/IBO pair) for each "object": As long as the object does not change, all I have to upload to the GPU each frame is the transformation information: a position vector and an orientation value. Or, equivalently, a transformation matrix.

But the problem with that approach is with a scene of 1000 square objects I'd have 1000 VBO's and 1000 IBO's to initialize, and 1000 draw calls setting 1000 sets of uniforms each frame in order to render 2000 triangles.

Okay. If all of those objects are identical, I can have one VBO/IBO to describe them, set up a Uniform Buffer Object (or perhaps a uniform array is more appropriate -- I still need to learn how to use these) with transformation data for each of them, and issue one instancing draw call, to have the vertex shader pull from the UBO the transformation data by using the instance number it receives. Great.

I just want to go one step further. I want to do what amounts to instancing on non-identical meshes: I have 1000 different objects, which I am happy to describe in either 1000 separate vertex/index buffer pairs, or one single gigantic pair of vertex/index buffers. I want to send their tranformation data to the GPU in one call. It's simply a matter of letting the driver/GPU bind or select the proper vertices.

Can this be done? Can it be done without using SM4 geometry shaders?

Update: I just thought of a potential method to accomplish this. I use a vertex attribute as my "instancing" value with which to index into a UBO that contains transformations. Is this the way to do it?

1
This smells of a premature optimization. What makes you think that you need to do this, that you can't just render these "1000 objects" the normal way? - Nicol Bolas
I likely don't need it. But I am interested in learning how to use the technology in the best way for my purposes. I want to be able to have a very large number of objects and if I can draw them all with one call I get more than just the benefit of avoiding function call overhead, I also get viewport culling, and i'm sure some other things, for free. - Steven Lu
How does that give you viewport culling? Instancing doesn't cull anything; it can't. Indeed, the whole point of instancing is to cut down on CPU overhead, so you try to do as little processing per-instance as possible. Even a quick frustum culling should generall be avoided. - Nicol Bolas
You are right about that. I think i meant that the naive method would allow me to cull manually, which is actually a pro rather than a con. No idea why I mentioned it there. Okay -- There is definitely a big benefit to having a vertex buffer (pair) for each object. This way, if I delete an object, I can delete its buffers, no more housekeeping necessary. So, what I'm looking for now is a way to issue buffer bind commands without an explicit call. Not possible? - Steven Lu
That doesn't explain why you feel that drawing "1000 objects" the normal way will be a substantial performance issue. Have you tried it? Is it a bottleneck? How big are these objects anyway? What ways have you tried to render things? - Nicol Bolas

1 Answers

0
votes

You don't need one VBO per object. Just concatenate all the objects into one single VBO or just a small set of VBOs. You can address into that VBO either adding a offset to the data parameter of the gl*Pointer functions, or use glDrawElementsBaseVertex to add the offset upon drawing time. Instead of just 4 indecies in the index array concatenate the index-arrays of all the small objects. If you're using some strip or fan primitive, you can set a special index with glPrimitiveRestartIndex that when encountered will start a new primitive.

That way you need to split down your rendering calls only by used material settings and the overall transformations and shader parameters (i.e. textures, shaders, shader uniforms).