Moving 2D Quads - Update vertices or matrix

Started by
4 comments, last by Halsafar 12 years, 5 months ago
The preferred method is clearly to adjust the matrix. Draw your objects in local space and use a matrix to transform that object. This is definitely true for 3D.

In my specific scenario I am rendering only quads (sprites) using batching (sorted by texture for example).

The option for adjusting the position of the quads has come up. I can either:
- adjust the vertices and send the new 4 vertices to the GPU, use the same matrix for all
- send the vertices once and adjust the world matrix each frame.

The latter again seems most logical. The concern I have is for just quads is updating an entire matrix for each quad each frame a bit overkill? In reality the vertices come out to be 12 floats and the matrix is 16 floats. Will any of this even make a major difference? I am curious what XNA does with its spritebatch.

I am working with OpenGL ES 2.0 in C/C++.
Advertisement
Store each quad's matrix as vertex-attributes in each of their 4 vertices. Read these attributes in a vertex shader and multiply appropriately so you can restore each quad's exclusive transformations even when batching quad soups.

Store each quad's matrix as vertex-attributes in each of their 4 vertices. Read these attributes in a vertex shader and multiply appropriately so you can restore each quad's exclusive transformations even when batching quad soups.


Maybe I misunderstand but that sounds like the worst of both worlds. Now I am sending both vertices and matrix data for each quad each frame?
Opposite to having a draw call per quad as you originally had planned, uploading matrices individually? You need to batch all that.

Store each quad's matrix with a Vertex Attribute Array so you can interpret this data appropriately in a vertex program when rendering them all with a single draw call.
Given a choice between the two, I'd update the vertexes. Adding a matrix for each vertex will bloat the vertex size (which may not actually be a problem depending on where your primary bottleneck is) and changing the matrix for each quad will break batching (which may not be a problem either, as you may not be drawing that many quads).

An alternative that's suitable for certain use cases exists. If each quad is drawn at the same depth, then the only things differentiating them are position (x and y) and size (height and width). That's 4 floats, which fits nicely into a constants register, so you could have a batch of quads stored in a static vertex buffer, with the "positions" being a size multiplier (either 0 or 1) in each dimension, and just load new x/y/w/h values into the constants for each quad. Each vertex would also need an index into the constants, these being in groups of 4: 0,0,0,0/1,1,1,1/etc. That would then give you output.position.x = quads[quadindex].x + quads[quadindex].z * input.position.x and output.position.y = quads[quadindex].y + quads[quadindex].w * input.position.y

So that gives you 1 float per vertex that needs changing, and 2 less shader instructions per-vertex, but at a cost of needing to index into the constants. It may or may not be more efficient and that would be hardware-dependent.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

I've decided to go the simple route. Keeping my vertex data as small as possible. I store vertex arrays for the sprites in a hashmap (unordered_map) which is keyed by a texture id. Each vertex stores simply x,y,z,u,v. When the vertices are pushed onto their array I calculate their position in world space right there (including rotations). They all share the same world matrix. When rendering comes I can render each vertex array as one batch.

This topic is closed to new replies.

Advertisement