【问题标题】:Painting in buffer. Issue with alpha chanel在缓冲区中绘画。 Alpha 通道问题
【发布时间】:2017-05-08 21:05:55
【问题描述】:

我尝试实现像绘画工具这样的东西,但遇到了问题 alpha chanel 的画笔。我的画笔是具有透明背景的 .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 通道将累积在缓冲区中以替换颜色。

我不熟悉 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);
}

更新2

好的。我尝试了您的建议,但结果相似,无法解释我的问题。看:

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

2) glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 和直阿尔法纹理。

【问题讨论】:

  • 深度测试是否被禁用?
  • 是的。如果我启用它,一切都不会改变。
  • 你发布的图片——它是什么的图片?什么是“绘制 FBO”代码、“绘制画笔”代码,您是如何设置 FBO 的?
  • 好的,我更新它。图像我尝试在 opengl 窗口中绘制时得到的结果。当我停止画笔时,它开始慢慢“燃烧”我之前画的东西,如果你理解我的话。
  • @OpenGLNoob:不,我不知道。你不清除缓冲区吗?很难从您的代码中分辨出来,因为它只是不连贯的部分。以后请发Minimal, Complete, and Verifiable example。至于现在,我怀疑问题在于您渲染到不是预乘 alpha 的透明纹理。

标签: opengl buffer blending fbo


【解决方案1】:

当混合到具有直 Alpha 通道的纹理中时,正确的混合方程涉及除以 Alpha 值,并且此类方程不能在 OpenGL(和 GPU)提供的线性公式中表达,glBlendFunc 和 @ 987654323@.

相反,您应该使用预乘 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(第一个)。

【讨论】:

  • 感谢您的回答!我会记住它对未来渲染结果的影响。我尝试了您的解决方案和其他组合,并且没有预乘(查看更新),但在我看来,问题出在其他地方。我的帧缓冲区不仅会在游戏循环中累积颜色,而且会累积 alpha 值,它会影响 FBO。当我停止刷子时,它开始像纸上的墨水一样流血。现在我试图弄清楚如何解决它,但我不能。((
  • @OpenGLNoob:您是否意识到您没有发布与鼠标相关的代码,因此我们无法提供帮助?请学会发Minimal, Complete and Verifiable Example
  • 是的,你是对的。我的错误是我没有通过鼠标移动控制更新我的 FBO,而是直接将绘画管道放入游戏循环中。 FBO 每帧都在累积 alpha,这就是我的问题的原因。谢谢!
猜你喜欢
  • 2020-09-03
  • 1970-01-01
  • 2012-08-15
  • 1970-01-01
  • 2012-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多