3
votes

I'm attempting to render a large number of textured quads on the iPhone. To improve render speeds I've created a VBO that I leverage to render my objects in a single draw call. This seems to work well, but I'm new to OpenGL and have run into issues when it comes to providing a unique transform for each of my quads (ultimately I'm looking for each quad to have a custom scale, position and rotation).

After a decent amount of Googling, it appears that the standard means of handling this situation is to pass a uniform matrix to the vertex shader and to have each quad take care of rendering itself. But this approach seems to negate the purpose of the VBO, by ultimately requiring a draw call per object.

In my mind, it makes sense that each object should keep it's own model view matrix, using it to transform, scale and rotate the object as necessary. But applying separate matrices to objects in a VBO has me lost. I've considered two approaches:

  • Send the model view matrix to the vertex shader as a non-uniform attribute and apply it within the shader.
  • Or transform the vertex data before it's stored in the VBO and sent to the GPU

But the fact that I'm finding it difficult to find information on how best to handle this leads me to believe I'm confusing the issue. What's the best way of handling this?

1
I don't think there's a simple solution you're missing. Both of the approaches you're considering are viable. How frequently do the per-quad transformations change in your use case? Do you typically draw with the same transformations many times, and only modify the transformations infrequently? Or do the transformations change each frame for all/part of the quads?Reto Koradi
Transformations will be updated fairly frequently. I'd considered keeping a VBO with static vertex data, and passing attributes (such as rotation in radians) to the vertex shader - where I could then generate a transform matrix. But I have a feeling that's likely to be more expensive than simply doing it on the CPU.ndg
If you want to be sure that you find the best performing solution for your use case, you may have to try a few approaches, and benchmark them. I don't think it's clear cut based on the information we have. As inelegant as it seems, updating the vertex coordinates on the CPU might be better than the alternatives. Unfortunately glMapBufferRange, which could help you avoid one copy for this approach, is not in ES 2.0. Going the opposite direction and moving more of the computation to the GPU is obviously appealing, but you'll have to find out if it's practical for your usage.Reto Koradi

1 Answers

1
votes

This is the "evergreen" question (a good one) on how to optimize the rendering of many simple geometries (a quad is in fact 2 triangles, 6 vertices most of the time unless we use a strip).

Anyway, the use of VBO vs VAO in this case should not mean a significant advantage since the size of the data to be transferred on the memory buffer is rather low (32 bytes per vertex, 96 bytes per triangle, 192 per quad) which is not a big effort for nowadays memory bandwidth (yet it depends on How many quads you mean. If you have 20.000 quads per frame then it would be a problem anyway).

A possible approach could be to batch the drawing of the quads by building a new VAO at each frame with the different quads positioned in your own coordinate system. Something like shifting the quads vertices to the correct position in a "virtual" mesh origin. Then you just perform a single draw of the newly creates mesh in your VAO.

In this way, you could batch the drawing of multiple objects in fewer calls.

The problem would be if your quads need to "scale" and "rotate" and not just translate, you can compute it with CPU the actual vertices position but it would be way to costly in terms of computing power.

A simple suggestion on top of the way you transfer the meshes is to use a texture atlas for all the textures of your quads, in this way you will need a much lower (if not needed at all) texture bind operation which might be costly in rendering operations.