9
\$\begingroup\$

Preconcepts

Ok, so what I've gathered so far is this:

  • don't use fixed pipeline (deprecated or going to be deprecated)
  • vbos store "object models" (n vertex data, mostly)
  • vaos describe how data is laid down so that draw calls know what part of each vbo is for what kind of vertex information (one vao can refer to multiple vbos, the opposite is kinda difficult)
  • each draw call also sends vertex data to shaders

How I see 3D (optional)

Given these informations, I can see how drawing 3D complicated objects is very nice with modern OpenGL. You basically load a bunch of object models (probably from Blender or other similar software) into VBOs with local coordinates, and then you simply provide for each instance of an object a different shader parameter (offset) to draw to world space.

Problem/question

In 2D problems and priorities are completely different, though. You don't draw much complex objects, you don't need complicated projection matrixes and whatnot and shaders are much simpler.

What would be the best way to draw frequently (really frequently, basically every frame) changing geometry with modern OpenGL?

In the following paragraph you can see some ideas of problems (the circle and rectangle problem), that better identify the kind of changes I'm interested in.

My attempts (optional)

So, I began to think how I would deal with drawing basic 2D geometry on the screen:

  • a square: load a [(1, 0), (1, 1), (0, 1), (0, 0)] VBO for the geometry of a square in local space, then provide the shader with the actual width of the square and world coordinates and color informations

cools, looks easy. Let's move to a circle:

  • a circle: triangle fan with... eh. how much precision (number of vertexes)? for small circles precision must be small and for bug circles precision must be high. Clearly loading 1 VBO cannot possibly fit all cases. What if I need to add precision because a circle is resized to be bigger?

Less cool. Let's move to something slightly easier, a rectangle:

  • a rectangle: eh. there's no "general rectangle geometry". You just have a width/height proportion and that's it, but each rectangle is probably different if the size changes.

As you can see, things go downhill from there. Especially with complex polygons and whatnot.

No code policy :P

I just need an overview of the idea, no code is necessary, especially C or C++ code. Just say stuff like: "make a VBO with this vertex data, and then bind it, ...".

\$\endgroup\$
  • \$\begingroup\$ I think I understand what you are asking, but you may want to give this question a little bit more direction. It is a bit unclear what is being asked - which is actually a close reason. \$\endgroup\$ – Lysol Dec 21 '14 at 6:31
  • \$\begingroup\$ @AidanMueller I'm not sure what you mean, but feel free to give more direction if you feel the need. \$\endgroup\$ – Shoe Dec 21 '14 at 14:35
  • \$\begingroup\$ The top answer currently starts out by saying "You main question seems to be". That indicates that it is unclear what you are asking. Maybe you should give a summary of what you need no know at the end of your question. This is a Q/A after all, not a discussion. \$\endgroup\$ – Lysol Dec 21 '14 at 19:21
  • \$\begingroup\$ @AidanMueller Not in that context, I believe. It says "Your main question seems to be..." and then he/she quotes the question I've posted. Which actually indicates that it is clear enough to be quoted. Also the phrase indicates not that my question is unclear, rather that there's a main question and another secondary question (which is: what is the solution to the specific cases I've presented). I really don't see the problem with my current question, and apparently not even the answerers did as I've found both answers very useful and to the point. \$\endgroup\$ – Shoe Dec 21 '14 at 19:34
  • \$\begingroup\$ You can draw a precise circle with a fragment shader. \$\endgroup\$ – user253751 Aug 17 '16 at 21:04
5
\$\begingroup\$

Your main question seems to be:

What would be the best way to draw frequently (really frequently, basically every frame) changing geometry with modern OpenGL?

In most ways, there's no big difference between 2d and 3d OpenGL. The graphics pipeline has that one extra coordinate, Z, which won't be used as much in 2d, but that's about it.

There's a few ways to change the geometry on each draw.

  • You can push new CPU-provided vertexes every frame. (See https://stackoverflow.com/questions/14155615/opengl-updating-vertex-buffer-with-glbufferdata for some notes on reusing buffers.)

  • You can draw different portions of an existing buffer, with glDrawArrays(mode, first, count). If the animation loops, maybe you can put the precomputed frames with the different vertex lists in one big buffer, and draw the appropriate portion of the buffer each frame.

  • You can influence the vertex list with some other data, like a uniform array, or a texture. In your vertex shader, read this data and apply it appropriately. These are just other idioms for presenting data to the GPU, and probably won't have much difference in performance.

  • If you have many instances of the same geometry (possibly influenced by attributes), then glDrawElementsInstanced() may be useful

  • You can influence the vertex list algorithmically in the vertex, geometry, or tessellation shaders. If the animation can be described mathematically, you might be able to keep the same vertex list, and change just a few shader uniforms each frame.

And perhaps your animation might be expressed as pure textures, with all animation done pixel by pixel by the cpu, or pre rendered from disk.

On the whole, I'd say, "Computers are fast, make it work the easiest way you can, which is probably by setting fresh CPU-made vertexes every frame. Then, see if that's good enough. Profile the battery/CPU usage first, memory footprint second."

Your other question, paraphrased, "What's a good way to draw circles and rectangles?"

Circles.

  • With tessellation shaders (or geometry shaders) you could make your geometry dynamic.

  • You could draw squares, and in your fragment shader only opaque (alpha = 1.0) within a radius, and transparent (alpha = 0.0) outside the radius. Then it's pixel perfect every time. (Make your square vertexes -1 to +1, and in fragment shader something like, outColor.a = dot(coord.xy, coord.xy) < 1.0 ? 1.0 : 0.0;. Could also smooth the edge a little, would look nice there...)

  • You could just always use, say, a 120-triangle fan. Probably good enough.

Rectangles.

  • I think you answered your own question, on that one. What you suggest will work fine!
\$\endgroup\$
  • \$\begingroup\$ The fragment-shader/radius is pretty neat, thanks. With regards to me answering my own question, I don't think I understand what you mean. \$\endgroup\$ – Shoe Dec 20 '14 at 15:59
  • \$\begingroup\$ Oh, just like with a square, you mention to control the width (with uniform, I assume), and you wrote, "You just have a width/height proportion and that's it, but each rectangle is probably different if the size changes". So, for a rectangle, do the same as a square but you'll need 4 values (x,y,w,h) instead of 3 (x,y,w). Or pass in (xlow,xhigh,ylow,yhigh) as four uniforms. With your (0,0) to (1,1) input, that's enough for the Vertex Shader to do what it needs. \$\endgroup\$ – david van brink Dec 20 '14 at 16:29
  • \$\begingroup\$ Oh, I see, that makes sense. \$\endgroup\$ – Shoe Dec 20 '14 at 16:32
  • \$\begingroup\$ Is there an automatic fan in modern GL like GL_TRIANGLE_FAN from the fixed function pipeline? \$\endgroup\$ – John P Aug 31 '16 at 1:40
5
\$\begingroup\$

I can't say to be expert of this subject, and in my game project(s) I have concentrated more on 3D side, so my 2D side is pretty simple generally using things made for 3D side; and obviously, my perspective is at gaming side, so my 2D graphics is more about blitting sprites than geometry. From that perspective,

1) Squares and rectangles are pretty easy. I have just single 1x1 box in a VBO which I use to blit everything. I pass MVP matrices to shader with this "unit box", and I have combined it with additional scaling to scale the box to right dimensions - as you know, you can have different x and y scale.

For my purposes, I have been thinking to move from using "unit box" to some sort of particle engine to blit 2D sprites, but that's another story.

2) I haven't work much with circles, I just use fixed VBOs with specific number of vertices. But I could imagine that I could make some stride tweaking to affect to the number of vertices drawn for the circle.

When connecting VBO data to shader attributes, I use glVertexAttribPointer. It has stride parameter meant to be used for interleaved data (which I use). But it might be possible to use it like this:

glVertexAttribPointer(..., n * sizeof(VERTEX_DATA), ...);

...to pick every nth vertex from the buffer, thus affecting to the number of vertices drawn for the circle. I could create several VAOs having the same VBO with different stride affecting to number of vertex drawn for circle. I haven't tried that, thought.

In general, yes, working with VBOs and such make CPU-side tweaking bit more complex, why I have been studying different things to make tweaking at GPU side (shaders). Still, according to this article, using VBOs is more efficient on modern hardware even if you need lots of CPU side "intervention":

http://www.quelsolaar.com/opengl_performance.txt

Hope this helps you a bit to design & decide your directions.

\$\endgroup\$
  • 2
    \$\begingroup\$ "stride tweaking to affect to the number of vertices drawn for the circle" Super cool! \$\endgroup\$ – david van brink Dec 20 '14 at 16:57

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.