The problem of mixing Alpha with multiple iterations of rendering into the same texture (OpenGL)

Scenario

I create a frame buffer object and bind the texture to a color nesting. I do not use depth buffer. Having created it, I untie it.

At some point in time, the frame buffer is tied, a triangle strip is transferred to it (some parts are partially transparent), and then not tied again. This is repeated several times with different triangular stripes.

Ultimately, what is drawn in the main frame buffer is a textured square with a texture attached to the frame buffer object I created.

Problem

I found that the partially transparent parts of the triangular stripes inscribed in the texture that overlap with the other triangular stripes do not mix properly. They seem to mix with white, not with a color that already has a texture. Even if I fill the texture with solid green (for example), the color will be raised during blending, still white.

Here are some snippets of code that I use to do all 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 (iteration)

 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); 

Map 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); 

Example of what i see

The parts where you see the white lines are overlapping triangular stripes. They should be partially transparent and blend with the black that was previously painted.

Poor mix

Update

I have made several discoveries since I posted this:

  • The β€œwhite” part is actually completely transparent, so it just shows the color of everything that is displayed behind the texture.
  • I replaced the more complex triangular meshes with randomly placed squares that consist of vertices that go from completely transparent on one side of the square to completely opaque on the other, and I don't see the same mixing problem. Here is an image of the squares:

Good mix

So this is the problem with the triangle meshes I use, not the blending.

Actually, looking very closely at the image of "Good Mixing", I see that the completely opaque parts of the square are actually illuminated when another square is drawn on top of it. So the problem is that it’s not so extreme.

+5
source share
1 answer

When rendering texture try

 glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); 

instead:

 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 

The fact is that when rendering texture, the alpha channel is also mixed.

To make everything clear, consider the rendering of a translucent edge above an opaque strip of a triangle that was made earlier. Let the alpha value of the edge be 0.5 (source alpha) and the alpha in the render buffer is 1.0 (target value). Thus, the resulting value will be:

 r = SrcAlpha * SrcAlpha + DstAlpha * (1.0 - SrcAlpha) = 0.5 * 0.5 + 0.5 * 0.5 = 0.5 

As you can see, the alpha value in the render buffer is not 1.0, as expected. As a result, the original color will mix with the destination color in the main frame buffer.

This way you do not need to mix the alpha channel. For example, you can simply add the source alpha value to the destination alpha value, this can be achieved by specifying another blending function for the alpha channel using glBlendFuncSeparate.

See this and ./p> for details.

Also make sure you set the correct mixing equation:

 glBlendEquation(GL_FUNC_ADD); 

See details

+6
source

Source: https://habr.com/ru/post/1204268/


All Articles