3
votes

I'm trying to make bilinear color interpolation on a quad, i succeeded with the help of my previous question on here, but it has bad performance because its requires me to repeat glBegin() and glEnd() and 4 times glUniform() before glBegin().

The question is: is it anyhow possible to apply bilinear color interpolation on a quad like this:

glBegin(GL_QUADS);
    glColor4f(...); glVertexAttrib2f(uv, 0, 0); glTexCoord2f(...); glVertex3f(...);
    glColor4f(...); glVertexAttrib2f(uv, 1, 0); glTexCoord2f(...); glVertex3f(...);
    glColor4f(...); glVertexAttrib2f(uv, 1, 1); glTexCoord2f(...); glVertex3f(...);
    glColor4f(...); glVertexAttrib2f(uv, 0, 1); glTexCoord2f(...); glVertex3f(...);
... // here can be any amount of quads without repeating glBegin()/glEnd()
glEnd();

To do this, i think i should somehow access the nearby vertex colors, but how? Or is there any other solutions for this?

I need this to work this way so i can easily switch between different interpolation shaders.

Any other solution that works with one glBegin() command is good too, but sending all corner colors per vertex isnt acceptable, unless thats the only solution here?

Edit: The example code uses immediate mode for clarity only. Even with vertex arrays/buffers the problem would be the same: i would have to split the rendering calls into 4 vertices chunks, which causes the whole speed drop here!

4
Why don't you use vertex arrays/vertex buffer objects? I think the function call overhead causes your performance issues.datenwolf
Practically everything you are doing here is deprecated OpenGL. You should look into Vertex Buffers, as the person above has saidAdam Casey
becase even with vertex arrays or buffers, the performance will drop because i would have to split the rendering into 4 vertice pieces and then again call glUniform(). also i am using display lists so it doesnt really matter here, it will be converted to VBO anyways. You are missing the point here, its not slow because im using immediate mode, because i already tested with the same rendering code, except by using glUniform() and repeating glBegin() billion times, so the only thing that changes is those two, and thats what im trying to optimize off here, thats the only thing i need to optimize.Rookie

4 Answers

3
votes

Long story short: You cannot do this with a vertex shader.

The interpolator (or rasterizer) is one of the components of the graphics pipeline that is not programmable. Given how the graphics pipe works, neither a vertex shader nor a fragment shader are allowed access to anything but their vertex (or fragment, respectively), for reasons of speed, simplicity, and parallelism.

The workaround is to use a texture lookup, which has already been noted in previous answers.

In newer versions of OpenGL (3.0 and up I believe?) there is now the concept of a geometry shader. Geometry shaders are more complicated to implement than the relatively simple vertex and fragment shaders, but geometry shaders are given topological information. That is, they execute on a primitive (triangle, line, quad, etc) rather than a single point. With that information, they could create additional geometry in order to resolve your alternate color interpolation method.

However, that's far more complicated than necessary. I'd stick with a 4 texel texture map and implement your logic in your fragment lookup.

2
votes

Under the hood, OpenGL (and all the hardware that it drives) will do everything as triangles, so if you choose to blend colors via vertex interpolation, it will be triangular interpolation because the hardware doesn't work any other way.

If you want "quad" interpolation, you should put your colors into a texture, because in hardware a texture is always "quad" shaped.

0
votes

If you really think it's the number of draws that cause your performance drop, you can try to use Instancing (Using glDrawArrayInstanced+glVertexAttribDivisor), available in GL 3.1 core.

An alternative might be point sprites, depending on your usage model (mostly, maximum size of your quads, and are they always perpendicular to the view). That's available since GL 2.0 core.

0
votes

Linear interpolation with colours specified per vertex can be set up efficiently using glColorPointer. Similarly you should use glTexCoordPointer/glVertexAttribPointer/glVertexPointer to replace all those individual per-vertex calls with a single call referencing the data in an array. Then render all your quads with a single (or at most a handful of) glDrawArrays or glDrawElements call. You'll see a huge improvement from this even without VBOs (which just change where the arrays are stored).

You mention you want to change shaders (between ShaderA and ShaderB say) on a quad by quad basis. You should either:

  • Arrange things so you can batch all of the ShaderA quads together and all the ShaderB quads together and render all of each together with a single call. Changing shader is generally quite expensive so you want to minimise the number of changes.

or

  • Implement all the different shader logic you want in a single "unified" shader, but selected by another vertex attribute which selects between the different codepaths. Whether this is anywhere near as efficient as the batching approach (which is preferable) depends on whether or not each "tile" of SIMD shaders tends to have to run a mixture of paths or just one.