In OpenGL, what's the best way to achieve a combined blend of primitives that don't all use the same shader? - c++

Let's say I have a bunch of semi-transparent triangles that I want to render as part of the same scene, correctly blended in order of depth. If they all use the same shader (and same uniforms, OpenGL state etc), then all I have to do is sort them by depth before submitting to OpenGL and I can render them all with a single draw call.
But what do I do if I want to render some of the triangles using a different shader? I can't do a single draw call anymore because there's two shaders. Do I sort the two sets of triangles separately and render them one after the other? But that only works if the depth values of one of the sets happen to be all less than the depth values of the other set. What if the depth values of the two sets interleave? In the worst case, what if the two sets of triangles are perfectly interleaved, so that between every two consecutive triangles of one set there's a triangle from the other set? What do I do then? Do I have to do as many draw calls as there are triangles in order to get the right result? I would like to limit the number of draw calls since I've heard having many draw calls is bad for performance. Is there a better way to do this?

In the worst case, what if the two sets of triangles are perfectly interleaved, so that between every two consecutive triangles of one set there's a triangle from the other set? What do I do then? Do I have to do as many draw calls as there are triangles in order to get the right result?
Yes, exactly so.
I would like to limit the number of draw calls since I've heard having many draw calls is bad for performance.
Each draw call has a comparatively large overhead, sure. The less draw calls you can render your scene in, the faster it will be.
Is there a better way to do this?
Sure, stop using different shaders. The whole "different shader" thing is just an assumption on your end, I haven't yet seen proof that it's actually needed. Between bindless textures, instanced drawing, SSBOs and plain ol atlases, you'd have to be rendering some pretty crazy triangles that you can't write just one shader for all of them.

Related

Is there a defined draw order for OpenGL instanced drawing? [duplicate]

Here's what I'm trying to do: I want to render a 2D scene, consisting of a number of objects (quads), using instancing. Objects with a lower y value (towards the bottom of the screen) need to be rendered in front of the ones with higher y values. And alpha blending also needs to work.
So my first idea was to use the Z value for depth, but I soon realized alpha blending will not work unless the objects are drawn in the right order. But I'm not issuing one call for each quad, but use a single instanced call to render the whole scene. Putting the instance data in the correct sorted order seems to work for me, but I doubt this is something I can rely on, since the GPU is supposed to run those computations in parallel as much as possible.
So the question is, is there a way to make this work? The best thing I can think of right now is to issue an instanced call for each separate y value (and issue those in order, back to front). Is there a better way to do this?
Instancing is best used for cases where each instance is medium-sized: hundreds or maybe thousands of triangles. Quads are not a good candidate for instancing.
Just build and render a sequence of triangles. There are even ways to efficiently get around the lack of a GL_QUADS primitive type in modern OpenGL.
Putting the instance data in the correct sorted order seems to work for me, but I doubt this is something I can rely on, since the GPU is supposed to run those computations in parallel as much as possible.
That's not how GPUs work.
When you issue a rendering command, what you (eventually) get is a sequence of primitives. Because the vertices that were given to that command are ordered (first to last), and the instances in that command are ordered, and even the draws within a single draw command are ordered, an order can be assigned to every primitive in the draw call with respect to every other primitive based on the order of vertices, instances, and draws.
This defines the primitive order for a drawing command. GPUs guarantee that blending (and logical operations and other visible post-fragment shader operations) will respect the primitive order of a rendering command and between rendering commands. That is, if you draw 2 triangles in a single call, and the first is behind the second (with depth testing turned off), then blending for the second triangle will respect the data written by the first.
Basically, if you give primitives to the GPU in an order, the GPU will respect that order with regard to blending and such.
So again, just build a ordered stream of triangles to represent your quads and render them.

Using OpenGL instancing for rendering 2D scene with object depths and alpha blending

Here's what I'm trying to do: I want to render a 2D scene, consisting of a number of objects (quads), using instancing. Objects with a lower y value (towards the bottom of the screen) need to be rendered in front of the ones with higher y values. And alpha blending also needs to work.
So my first idea was to use the Z value for depth, but I soon realized alpha blending will not work unless the objects are drawn in the right order. But I'm not issuing one call for each quad, but use a single instanced call to render the whole scene. Putting the instance data in the correct sorted order seems to work for me, but I doubt this is something I can rely on, since the GPU is supposed to run those computations in parallel as much as possible.
So the question is, is there a way to make this work? The best thing I can think of right now is to issue an instanced call for each separate y value (and issue those in order, back to front). Is there a better way to do this?
Instancing is best used for cases where each instance is medium-sized: hundreds or maybe thousands of triangles. Quads are not a good candidate for instancing.
Just build and render a sequence of triangles. There are even ways to efficiently get around the lack of a GL_QUADS primitive type in modern OpenGL.
Putting the instance data in the correct sorted order seems to work for me, but I doubt this is something I can rely on, since the GPU is supposed to run those computations in parallel as much as possible.
That's not how GPUs work.
When you issue a rendering command, what you (eventually) get is a sequence of primitives. Because the vertices that were given to that command are ordered (first to last), and the instances in that command are ordered, and even the draws within a single draw command are ordered, an order can be assigned to every primitive in the draw call with respect to every other primitive based on the order of vertices, instances, and draws.
This defines the primitive order for a drawing command. GPUs guarantee that blending (and logical operations and other visible post-fragment shader operations) will respect the primitive order of a rendering command and between rendering commands. That is, if you draw 2 triangles in a single call, and the first is behind the second (with depth testing turned off), then blending for the second triangle will respect the data written by the first.
Basically, if you give primitives to the GPU in an order, the GPU will respect that order with regard to blending and such.
So again, just build a ordered stream of triangles to represent your quads and render them.

OpenGL - Alternate between drawing with or without texture

In my game engine, I often change between drawing textured and non-textured shapes. I'm wondering, what is the most efficient way to make this distinction? For example, suppose we have two methods, DrawRectangle(Color color) and DrawRectangleTextured(int textureId) and we have no control of the order in which they are called.
I have thought of three possible ways of dealing with this:
1) Have two different shader programs, one that takes a texture and one that doesn't. Then select the appropriate shader before drawing. This seems like a good solution in terms of efficiency, but I'm not sure about the overhead of swapping programs all the time. Furthermore, it's troublesome to have to always keep track of two programs, making it difficult to maintain and extend.
2) Make a completely white texture and treat non-textured drawing as textured drawing with that white texture. This means whenever we draw with color, we have to upload redundant texture coordinates and the fragment shader has to do a little bit of extra work.
3) Use a uniform value specifying whether to draw with a texture or not. Not sure if this has any advantages over option 2).
Is there a common and efficient way to deal with this problem?

OpenGL- drawarrays or drawelements?

I'm making a small 2D game demo and from what I've read, it's better to use drawElements() to draw an indexed triangle list than using drawArrays() to draw an unindexed triangle list.
But it doesn't seem possible as far as I know to draw multiple elements that are not connected in a single draw call with drawElements().
So for my 2D game demo where I'm only ever going to draw squares made of two triangles, what would be the best approach so I don't end having one draw call per object?
Yes, it's better to use indices in many cases since you don't have to store or transfer duplicate vertices and you don't have to process duplicate vertices (vertex shader only needs to be run once per vertex). In the case of quads, you reduce 6 vertices to 4, plus a small amount of index data. Two thirds is quite a good improvement really, especially if your vertex data is more than just position.
In summary, glDrawElements results in
Less data (mostly), which means more GPU memory for other things
Faster updating if the data changes
Faster transfer to the GPU
Faster vertex processing (no duplicates)
Indexing can affect cache performance, if the reference vertices that aren't near each other in memory. Modellers commonly produce meshes which are optimized with this in mind.
For multiple elements, if you're referring to GL_TRIANGLE_STRIP you could use glPrimitiveRestartIndex to draw multiple strips of triangles with the one glDrawElements call. In your case it's easy enough to use GL_TRIANGLES and reference 4 vertices with 6 indices for each quad. Your vertex array then needs to store all the vertices for all your quads. If they're moving you still need to send that data to the GPU every frame. You could position all the moving quads at the front of the array and only update the active ones. You could also store static vertex data in a separate array.
The typical approach to drawing a 3D model is to provide a list of fixed vertices for the geometry and move the whole thing with the model matrix (as part of the model-view). The confusing part here is that the mesh data is so small that, as you say, the overhead of the draw calls may become quite prominent. I think you'll have to draw a LOT of quads before you get to the stage where it'll be a problem. However, if you do, instancing or some similar idea such as particle systems is where you should look.
Perhaps only go down the following track if the draw calls or data transfer becomes a problem as there's a lot involved. A good way of implementing particle systems entirely on the GPU is to store instance attributes such as position/colour in a texture. Each frame you use an FBO/render-to-texture to "ping-pong" this data between another texture and update the attributes in a fragment shader. To draw the particles, you can set up a static VBO which stores quads with the attribute-data texture coordinates for use in the vertex shader where the particle position can be read and applied. I'm sure there's a bunch of good tutorials/implementations to follow out there (please comment if you know of a good one).

Comparing textures in OpenGL ES 2.0

I am working on a painting app using the LibGDX framework, though this should be primarily OpenGL related.
Basically, I am looking for a way to prevent the sprites I use to draw from overlapping each other when they aren't fully opaque, as this creates a lot of unpleasant effects. Drawing the sprites at 1.0 alpha onto a texture and then drawing that texture back at the desired alpha gives the effect I want, but that method would involve constantly recreating the texture as the user is drawing, which is far too intensive to be viable.
From what I can see, the best option for me, in basic terms, is to sort of subtract one of these sprites from the other in the fragment shader. I am quite certain this route would work, but I cannot figure out how to get to the point where I can actually compare them in the fragment shader. Both will always use the same single texture, but they will be positioned in different spots. Is it at all possible to actually compare them like that, or is there a suitable alternative?
It's not actually possible to compare 2 textures that are applied to different geometry (sprites) in the fragment or vertex shader that way, because they will be rendered on different iterations of the shaders, at different points in time.
You could have two or more texture units to sample and subtract multiple textures, but they would have to be applied to the same vertices (sprites), which I think is not what you want.
A better approach would be to compute the proximity of the sprites before they are rendered. You could then either change their positions, or pass the proxmity as a uniform value into the shaders, which could then be used to change the alpha of the fragment pixels for the sprites.