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

时间:2014-10-08 16:06:57

标签: opengl opengl-es rendering framebuffer alphablending

方案

我正在创建一个帧缓冲区对象并将纹理绑定到颜色附件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);

渲染到纹理(迭代开启)

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

将纹理渲染到主帧缓冲区

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

我看到的一个例子

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

Bad Blending

更新

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

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

Good Blending

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

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

1 个答案:

答案 0 :(得分:6)

渲染到纹理时,请尝试

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);

而不是:

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

案例在于,当渲染到纹理时,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

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

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

有关详细信息,请参阅thisthis

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

glBlendEquation(GL_FUNC_ADD);

有关详细信息,请参阅this