OpenGL Abnormal mixing result

Mesh (vertexBuffer and indexBuffer):

Several 2-D triangles overlap each other. The vertex color of each vertex R:1, G:0, B:0, A:0.005

(transparent red). The triangles are combined into one mesh.

Rendering code : (C # code, but it should be the same for other languages)

GL.Enable(GL.GL_BLEND);
GL.BlendEquation(GL.GL_FUNC_ADD_EXT);
GL.BlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
GL.Disable(GL.GL_CULL_FACE);
GL.Disable(GL.GL_DEPTH_TEST);
GL.Disable(GL.GL_ALPHA_TEST);
GL.DepthFunc(GL.GL_NEVER);
GL.Enable(GL.GL_SCISSOR_TEST);

GL.ClearColor(1, 1, 1, 1);
GL.Clear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
GL.Viewport(0, 0, width, height);
GLM.mat4 ortho_projection = GLM.glm.ortho(0.0f, width, height, 0.0f, -5.0f, 5.0f);

material.program.Bind();
material.program.SetUniformMatrix4("ProjMtx", ortho_projection.to_array());

GL.BindVertexArray(material.vaoHandle);
GL.BindBuffer(GL.GL_ARRAY_BUFFER, material.VboHandle);
GL.BufferData(GL.GL_ARRAY_BUFFER, vertexBuffer.Count*sizeof_Vertex, vertexBuffer.Pointer, GL.GL_STREAM_DRAW);
GL.BindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, material.elementsHandle);
GL.BufferData(GL.GL_ELEMENT_ARRAY_BUFFER, indexBuffer.Count *sizeof_Index, indexBuffer.Pointer, GL.GL_STREAM_DRAW);

GL.DrawElements(GL.GL_TRIANGLES, elemCount, GL.GL_UNSIGNED_INT, IntPtr.Zero);

      

vertex shader

#version 330
uniform mat4 ProjMtx;
in vec2 Position;
in vec2 UV;
in vec4 Color;
out vec2 Frag_UV;
out vec4 Frag_Color;
void main()
{
    Frag_UV = UV;
    Frag_Color = Color;
    gl_Position = ProjMtx * vec4(Position.xy,0,1);
}

      

fragment shader

#version 330
in vec2 Frag_UV;
in vec4 Frag_Color;
out vec4 Out_Color;
void main()
{
    Out_Color = Frag_Color;
}

      

I thought the overlapping triangles would display like this:

overlapped overlapped (wireframe)

But the actual rendering result is:

result

After each draw and call, the SwapBuffer

red value of the render polygon gets stronger.

Why? Shouldn't those transparent triangles just blend once? What I mean is that over time, the result should be static and not animated.

Note that I want the overlapping pixels to appear in a stronger red color. But I don't want the whole grid (overlapping triangles) to appear in more red color frame by frame . Since the current buffer of the linked frame is cleared, blending works correctly, the render result shouldn't be bigger or redder IMO.

+3


source to share


1 answer


You have disabled GL_DEPTH_TEST

, you have no stencil test, and you have no other operation that prevents the fragment from being drawn.

The blend function is a function of target color and source color. Each time the slice draws, the color changes to the target buffer.

If you set glBlendFunc with parameters (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

, then the destination color is calculated as follows:

C_dest = C_src * A_src + C_dest * (1-A_src)

      

If you mix C_dest = 0

with C_src = 1.0

and A_src = 0.05

, then:

C_dest = 0.05 = 1.0 * 0.05 + 0.0 * 0.95 

      

If you repeat mixing the same color C_src = 1.0

and A_src = 0.05

then the destination color is highlighted:

C_dest = 0.0975 = 1.0 * 0.05 + 0.05 * 0.95

      

Repetition of this makes the target color brighter and brighter.

To prevent this, you can use a depth test. For example, using a depth function GL_LESS

that prevents a fragment from being drawn if its depth is equal to or even higher than the depth stored in the depth buffer:



GL.Enable(GL.GL_DEPTH_TEST);
GL.DepthFunc(GL.GL_LESS);

      

Or you can customize stencil buffer and stencil test. For example, a stencil test can be set to transmit only when the stencil buffer is 0. Each time a chunk needs to be written, the stencil buffer is incremented. If the same fragment is to be written a second time, then the test fails:

GL.Clear( GL.GL_STENCIL_BUFFER_BIT );
GL.Enable( GL.GL_STENCIL_TEST );
GL.StencilOp( GL.GL_KEEP, GL.GL_KEEP, GL.GL_INCR );
GL.StencilFunc( GL.GL_EQUAL, 0, 255 );

      

Expanding the answer

Note. GL.Clear(GL.GL_COLOR_BUFFER_BIT);

clears the paint buffer color scale immediately, of course you have to do this before every scene update and it really only affects the currently associated framebuffer.

In addition, the color mask for framebuffer write operations must be set correctly.

GL.ColorMask(GL.GL_TRUE, GL.GL_TRUE, GL.GL_TRUE, GL.GL_TRUE);

      

If you are using a double buffer, make sure the buffers are swapped only once per update, not twice.

Please note, you must be careful that the geometry does not overlap and is drawn only once!

+2


source







All Articles