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\$
1

2 Answers 2

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\$
3
  • 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\$ Commented Dec 15, 2014 at 0:32
  • 1
    \$\begingroup\$ Yup, was just editing to clarify that :D \$\endgroup\$
    – user1430
    Commented Dec 15, 2014 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
    Commented Dec 16, 2014 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
  • 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
    Commented Dec 15, 2014 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\$ Commented Dec 15, 2014 at 10:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .