4
\$\begingroup\$

I was thinking about how to program a user interface in a 3D game. The problem is, immediate mode (glBegin and glEnd) is deprecated for a long time but I don't think vertex buffer objects (or arrays) are needed just for the (2D) quads I want to draw (and I don't think they are even efficient for plenty of small quads).

Are there any approaches on how to avoid vertex-buffer-objects/arrays and the deprecated functions?

\$\endgroup\$
6
\$\begingroup\$

Not really. Use vertex buffer objects. There can be perfectly efficient for large numbers of small triangles.

The thing is that you don't want to make one VBO per quad, but rather few VBOs into which you stuff multiple quads.

\$\endgroup\$
  • 1
    \$\begingroup\$ Since I'm not sure if the OP realizes you can do this: you want to batch together all your quads into a small number of vertex buffers and draw many quads all at the same time. You need a pass over your GUI that batches together anything that can be and then schedules the minimal number of state changes, VBO updates, and draw calls needed to draw the UI. \$\endgroup\$ – Sean Middleditch Dec 15 '14 at 0:32
  • 1
    \$\begingroup\$ Yup, was just editing to clarify that :D \$\endgroup\$ – Josh Dec 15 '14 at 0:34
  • 1
    \$\begingroup\$ Josh, this is something I'm currently struggling with in my own game engine. Any relevant links on the subject of batching many VBOs together efficiently? I'm worried about overhead when many quads get created or destroyed (such as in a particle system) should I? \$\endgroup\$ – mklingen Dec 16 '14 at 0:09
1
\$\begingroup\$

You can use instancing and a texture atlas to combine all the draw calls into a single one.

You only have a single 4 vertex VBO with the 4 corners 0,0 0,1 1,1 1,0 and an index buffer to draw them using GL_TRIANGLES.

Then in a separate VBO you have the position and size of the quad (in a single vec4) and the position and size of the texture to use in the atlas (again as a vec4).

in vec2 coords;

in vec4 location;//x and y is the relative offset and z and w is the scaling factor
in vec4 textureLoc;

out vec2 texCoord;//0-1 as you would without the atlas

main(){
   gl_Position = coords.xy*location.zw + location.xy;
   texCoord = coords.xy*textureLoc.zw + textureLoc.xy;
}

Then during the rendering you fill the second VBO with position, size, texturePosition, textureSize, set the attribute pointer as if they where one for each vertex and set the attribute Divisor to 1; draw with

void glDrawElementsInstanced​(GL_TRIANGLES​, 6, GL_Int, 0​, numberQuads);
\$\endgroup\$
  • 2
    \$\begingroup\$ You don't need instancing to combine all the draws into one. Instancing is a good tool to have in your belt, but the OP asked for alternatives to VBOs, not more advanced ways to use VBOs. IMO it's also overkill for all but the most complex UIs, and it needlessly introduces dependencies (glVertexAttribDivisor is pretty ubiquitous since it's core in 3.2, but glDraw*Instanced*BaseInstance, which allows using the same VAO/buffer bindings for multiple instanced draws, requires GL 4.3 or ARB_base_instance). \$\endgroup\$ – bcrist Dec 15 '14 at 9:52
  • 1
    \$\begingroup\$ @bcrist he actually asked for something that doesn't quite exist; so I gave him a way to pass more information using VBOs in less draw calls \$\endgroup\$ – ratchet freak Dec 15 '14 at 10:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.