The scenario
I'm creating a frame buffer object and binding a texture to colour attachment 0. I'm not using a depth buffer. After creating it, I unbind it.
At some point in time later, the frame buffer is bound, a triangle strip is rendered to it (some parts partially transparent), and then it's unbound again. This is repeated a number of times with different triangle strips.
Ultimately, what's drawn to the main frame buffer is a textured quad with the texture that's attached to the frame buffer object I created.
The problem
I'm finding that the partially transparent parts of the triangle strips drawn into the texture which overlap with other triangle strips aren't being blended properly. They appear to be blended with white rather than the colour that's already in the texture. Even if I fill the texture with solid green (for example), the colour being picked up while blending is still white.
Here's a few snippets of the code I'm using to do all of this:
Initialization
glGenTextures(1, &texture_id);
glBindTexture(GL_TEXTURE_2D, texture_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glGenFramebuffers(1, &framebuffer_id);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_id, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
Render To Texture (iterated on)
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id);
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// On the first render iteration, do_clear is true
if (do_clear)
{
glClearColor(r, g, b, a);
glClear(GL_COLOR_BUFFER_BIT);
}
// ... render the current triangle strip ...
glBindFramebuffer(GL_FRAMEBUFFER, 0);
Render Texture To Main Framebuffer
// Set up the texture (making no assumptions about current state)
glEnable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture_id);
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Set up the vertex buffer (quad made up of triangle strip)
glBindBuffer(GL_ARRAY_BUFFER, vertices_id);
glVertexAttribPointer(VERTEX_ATTRIB_POSITION_TAG, 3, GL_FLOAT, GL_FALSE, sizeof(MyRenderVertex), BUFFER_OFFSET(0));
glEnableVertexAttribArray(VERTEX_ATTRIB_POSITION_TAG);
glVertexAttribPointer(VERTEX_ATTRIB_TEXCOORD_TAG, 2, GL_FLOAT, GL_FALSE, sizeof(MyRenderVertex), BUFFER_OFFSET(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(VERTEX_ATTRIB_TEXCOORD_TAG);
glVertexAttribPointer(VERTEX_ATTRIB_COLOR_TAG, 4, GL_FLOAT, GL_FALSE, sizeof(MyRenderVertex), BUFFER_OFFSET(5 * sizeof(GLfloat)));
glEnableVertexAttribArray(VERTEX_ATTRIB_COLOR_TAG);
glVertexAttribPointer(VERTEX_ATTRIB_NORMAL_TAG, 3, GL_FLOAT, GL_FALSE, sizeof(MyRenderVertex), BUFFER_OFFSET(9 * sizeof(GLfloat)));
glEnableVertexAttribArray(VERTEX_ATTRIB_NORMAL_TAG);
// Draw the textured geometry
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// Reset everything
glDisableVertexAttribArray(VERTEX_ATTRIB_POSITION_TAG);
glDisableVertexAttribArray(VERTEX_ATTRIB_TEXCOORD_TAG);
glDisableVertexAttribArray(VERTEX_ATTRIB_COLOR_TAG);
glDisableVertexAttribArray(VERTEX_ATTRIB_NORMAL_TAG);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindTexture(target, 0);
glActiveTexture(0);
An Example of What I'm Seeing
The parts where you see the white lines are where the triangle strips overlap. They should be partially transparent and blended with the black that was previously drawn.
Bad Blending
Update
I've made a few discoveries since I posted this:
Good Blending
So it appears to be a problem with the triangle meshes I'm using and not the blending.
Actually, looking very closely at the "Good Blending" image, I can see that the fully opaque parts of a square are actually being lightened when another square is rendered over top of it. So the problem is there, it's just not quite as extreme.
When you render to texture, try
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
instead of:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
The case is in that, when you render to texture the alpha channel is also blended.
To make things clear, let's consider rendering a half transparent edge over an opaque triangle strip that was rendered before. Let's the alpha value of edge be 0.5 (source alpha) and the alpha in render buffer be 1.0 (destination value). So the resulting value would be:
r = SrcAlpha * SrcAlpha + DstAlpha * (1.0 - SrcAlpha) = 0.5 * 0.5 + 0.5 * 0.5 = 0.5
As you see, the value of alpha in render buffer is not equal to 1.0, as you were expecting. As a result, the source color would be blended with the destination color in main frame buffer.
So you do not need to blend alpha channel. For example, you can simply add source alpha value to destination alpha value, this can be achieved by specifying different blending function for alpha channel using glBlendFuncSeparate.
See this and this for more details.
Also make sure, that you have set a proper blending equation:
glBlendEquation(GL_FUNC_ADD);
See this for more details
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With