具有多个渲染迭代的Alpha混合问题到同一纹理(OpenGL)

cod*_*ely 6 opengl rendering alphablending opengl-es framebuffer

场景

我正在创建一个帧缓冲区对象并将纹理绑定到颜色附件0.我没有使用深度缓冲区.创建它之后,我解开它.

在某个时间点之后,帧缓冲区被绑定,向其呈现三角形条带(某些部分部分透明),然后再次解除绑定.使用不同的三角形条重复多次.

最终,绘制到主帧缓冲区的是纹理四边形,其纹理附加到我创建的帧缓冲区对象上.

问题

我发现绘制到纹理中的三角形条带的部分透明部分与其他三角形条带重叠没有正确混合.它们似乎与白色混合,而不是纹理中已经存在的颜色.即使我用纯绿色填充纹理(例如),在混合时拾取的颜色仍然是白色.

这里是我用来完成所有这些的代码的几个片段:

初始化

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);
Run Code Online (Sandbox Code Playgroud)

渲染到纹理(迭代)

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);
Run Code Online (Sandbox Code Playgroud)

渲染纹理到主帧缓冲区

// 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);
Run Code Online (Sandbox Code Playgroud)

我所看到的一个例子

您看到白线的部分是三角形条带重叠的位置.它们应该是部分透明的,并与之前绘制的黑色混合.

糟糕的混合

更新

自从我发布以来,我发现了一些发现:

  • "白色"部分实际上是完全透明的,因此它只显示纹理背后呈现的颜色
  • 我用随机放置的正方形替换了更复杂的三角形网格,这些正方形由顶点组成,这些顶点从正方形一侧的完全透明到另一侧的完全不透明,我看不到相同的混合问题.这是正方形的图片:

良好的混合

因此,我正在使用的三角形网格似乎是一个问题,而不是混合.

实际上,仔细观察"Good Blending"图像,我可以看到,当另一个正方形呈现在其上方时,正方形的完全不透明部分实际上正在被照亮.所以问题在那里,它不是那么极端.

Pod*_*kiy 6

渲染到纹理时,请尝试

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
Run Code Online (Sandbox Code Playgroud)

代替:

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Run Code Online (Sandbox Code Playgroud)

情况是,当你渲染到纹理时,alpha通道也会被混合.

为了清楚起见,让我们考虑在之前渲染的不透明三角形条带上渲染半透明边缘.设edge的alpha值为0.5(源alpha),渲染缓冲区中的alpha为1.0(目标值).因此得到的值将是:

r = SrcAlpha * SrcAlpha  + DstAlpha * (1.0 - SrcAlpha) = 0.5 * 0.5 + 0.5 * 0.5 = 0.5
Run Code Online (Sandbox Code Playgroud)

如您所见,渲染缓冲区中alpha的值不等于1.0,正如您所期望的那样.结果,源颜色将与主帧缓冲区中的目标颜色混合.

所以你不需要混合alpha通道.例如,您可以简单地将源alpha值添加到目标alpha值,这可以通过使用glBlendFuncSeparate为alpha通道指定不同的混合函数来实现.

这个这个的更多细节.

还要确保您已设置了正确的混合等式:

glBlendEquation(GL_FUNC_ADD);
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅