在缓冲区绘画。 alpha chanel的问题

时间:2017-05-08 21:05:56

标签: opengl buffer blending fbo

我尝试实现类似绘画工具的东西,并坚持使用问题alpha chanel of brush。我的画笔是具有透明背景的.PNG纹理。我在RGBA缓冲区中绘图。我的代码:

initFBO(...)
...

glEnable(GL_BLEND);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);

glBindFramebuffer(GL_FRAMEBUFFER, FBO);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

drawBrush(...)

glBindFramebuffer(GL_FRAMEBUFFER, 0); 

drawFBO(...)

它有效但如果我停止刷子,刷子的alpha通道将积聚在缓冲区中以替换颜色。

enter image description here

我不太熟悉Opengl中的混合距离太近而且混合参数有问题。我的问题在于混合还是其他什么?

更新

initFBO(GLuint &framebuff, GLuint &text)
{
    glGenFramebuffers(1, &framebuff);
    glBindFramebuffer(GL_FRAMEBUFFER, framebuff);
    glGenTextures(1, &text);

    glBindTexture(GL_TEXTURE_2D, text);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screenWidth, screenHeight, 0, GL_RGB, GL_FLOAT, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, text, 0);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

drawBrush(glm::vec2 mousePosition, GLuint texture, Shader shader)
{
    glm::mat4 model;
    model = glm::translate(model, glm::vec3(mousePosition, 1.0));

    GLfloat brushVertices[] =
    {
        -0.1f, 0.1f, 0.0f, 0.0f, 1.0f,
        -0.1f,-0.1f, 0.0f, 0.0f, 0.0f,
         0.1f, 0.1f, 0.0f, 1.0f, 1.0f,
         0.1f,-0.1f, 0.0f, 1.0f, 0.0f
    };

    glGenVertexArrays(1, &brushVAO);
    glGenBuffers(1, &brushVBO);
    glBindVertexArray(brushVAO);
    glBindBuffer(GL_ARRAY_BUFFER, brushVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(brushVertices), &brushVertices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glBindVertexArray(0);

    shader.set();
    glUniform1i(glGetUniformLocation(shader.Program, "texture"), 0);
    glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);

    glBindVertexArray(brushVAO);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    glBindVertexArray(0);
}

drawFBO(GLuint texture, Shader shader)
{
    GLfloat screenquadVertices[] =
    {
    -1.0f, 1.0f, 0.0f,  0.0f, 1.0f,
    -1.0f, -1.0f,0.0f,  0.0f, 0.0f,
    1.0f, 1.0f, 0.0f,  1.0f, 1.0f,
    1.0f, -1.0f,  0.0f,  1.0f, 0.0f
    };

    glGenVertexArrays(1, &screenquadVAO);
    glGenBuffers(1, &screenquadVBO);
    glBindVertexArray(screenquadVAO);
    glBindBuffer(GL_ARRAY_BUFFER, screenquadVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(screenquadVertices), &screenquadVertices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glBindVertexArray(0);

    shader.set();
    glUniform1i(glGetUniformLocation(shader.Program, "texture"), 0);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);

    glBindVertexArray(screenquadVAO);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    glBindVertexArray(0);
}

UPDATE2

确定。我试过你的推荐,但结果是相似的,不解释我的问题。看看:

1)glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);和两个预乘的.PNG纹理 - 黑色和白色。

enter image description here

2)glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);和直的alpha纹理。

enter image description here

1 个答案:

答案 0 :(得分:1)

当混合到具有直alpha通道的纹理时,正确的混合方程涉及除以alpha值,并且这些方程不能在OpenGL(和GPU)提供的线性公式中表达glBlendFuncglBlendFuncSeparate

相反,您应该使用预乘alpha。原则上你可以通过调用

来做到这一点
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

一次,并确保所有输入和输出都是预乘alpha。

然而,标准的PNG是直接的alpha(虽然存在预乘alpha的非标准PNG ......可能不是你的情况)。要处理它,你可以在加载时预乘PNG,或者在drawBrush中使用以下内容:

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

这将得到一个直的alpha着色器输出并将其混合到一个预乘的alpha帧缓冲区中。因此,在将帧缓冲区渲染到屏幕时,请记住使用glBlendFunc进行预乘alpha(第一个)。