【问题标题】:OpenGL Blending - fill intersections with a different colorOpenGL混合 - 用不同的颜色填充交叉点
【发布时间】:2021-07-13 08:32:02
【问题描述】:

我正在屏幕上渲染一堆形状(多边形),但我没有使用深度测试。 我只是希望这些形状在被绘制在空白区域时使用自己的颜色,并且在它们被绘制在任何非空的东西上时成为红色像素,即在我的情况下,在另一个多边形上。

这里的问题实际上在于我可以使用的颜色和我可以分配的因素。 所以假设我的颜色是任意的,比如 RGBA(0.5, 0.7, 0.3, 1.0)。 这意味着当我绘制第一个对象时,这就是最终在帧缓冲区中的内容。

然后我用相同的颜色绘制第二个重叠的对象。但我希望重叠区域为红色 (1,0,0,1)。

但在这里我遇到了问题,因为无论我为混合函数分配什么 sFactor 和 dFactor - 我都无法增加值。

显然,当帧缓冲区中没有任何内容时,我需要使用因子 1 绘制我的原始颜色,而当有某些内容时,我需要使用因子 0。所以第一个因素是简单的选择:GL_ONE_MINUS_DST_ALPHA。

但是对于第二个因素,假设我想将原始颜色 RGBA(0.5, 0.7, 0.3, 1.0) 变成红色 RGBA(1, 0, 0, 1),我显然做不到。因为我的因子被限制在 [0,1],所以我最多可以将结果的红色通道设置为 0.5,而不是更大。我可以通过提供 GL_CONSTANT_COLOR 作为一个因素轻松否定其他 2 个通道,但我不能使任何通道大于原始通道。

或者我可以吗? 还有其他方法可以实现我想要的吗?

编辑/回答:

按照建议,我使用了模板缓冲区,这正是我所需要的。我没有选择为它创建一个单独的帧缓冲区,但只是在相同的情况下工作,因为它对我来说效果更好并且承诺更少的开销。 无论如何,这是伪代码:

        glEnable(GL_STENCIL_TEST);
        glStencilOp(GL_INCR,GL_INCR,GL_INCR);
        glStencilFunc(GL_ALWAYS,1,0xFF);
        glStencilMask(0xFF);
        glClear(GL_STENCIL_BUFFER_BIT);

        glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE);
        renderer.render(stuff);

        // Parts of above stuff are erased / cleared
        glStencilOp(GL_ZERO,GL_ZERO,GL_ZERO);
        glBlendFunc(GL_ZERO,GL_ZERO);
        renderer.render(eraser);

        glStencilOp(GL_INCR,GL_INCR,GL_INCR);
        glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE);
        renderer.render(moreStuff)

        glStencilMask(0x00);                  //Disable writing to stencil buffer
        glBlendFunc(GL_ONE, GL_ZERO);         // render above everything
        glStencilFunc(GL_LESS,1,0xFF);        //only parts that are above 1 stencil value, i.e. intersections
                                              //this is a bit unintuitive
        renderer.render(overlay);             //quad that is filled with solid color, and takes the entire screen
        glDisable(GL_STENCIL_TEST);

效果很好!我还包括了我擦除一些渲染图像的部分,以防万一有人需要类似的任务。

一些不直观的点:

  1. glClear(GL_STENCIL_BUFFER_BIT) 实际上使用了 glStencilMask(),因此必须将其设置为 0xFF 才能完全清除。我犯了一个错误,将 clear 调用放在掩码分配之上,所以本质上它保留了上一个渲染周期 0x00 的掩码,并且没有清除模板缓冲区。如果您想用画笔演奏莱昂纳多,这正是您想要的。 ^_^
  2. glStencilFunc(func , ref, mast) 实际上从直观的角度向后工作。公式是:(ref & mask) func (stencil & mask)。即 glStencilFunc(GL_LESS,1,0xFF);将丢弃任何大于 1 的片段,因为公式为 (1 & FF)

【问题讨论】:

  • 关于“不使用单独的缓冲区”的说明——我假设您想根据模板缓冲区中的值对像素进行不同的着色。如果您只需要一个二进制掩码操作,那么,当然,主模板缓冲区就可以了。不过,单独的一个会给你更多的灵活性。
  • 是的,我知道!我只是解释说我觉得我不需要这样做。以防让人们感到困惑,为什么我不使用单独的缓冲区。

标签: opengl intersection blending glblendfunc


【解决方案1】:

您的问题最好通过stencil buffer 来解决。

您可以使用glStencilOp(GL_INCR,GL_INCR,GL_INCR) 将图元渲染到屏幕外模板缓冲区中。这有效地计算了每个像素重叠的图元数量。完成后,使用着色器绘制一个全屏四边形,该着色器根据模板缓冲区中的值计算颜色(零表示背景颜色)。

【讨论】:

    猜你喜欢
    • 2015-04-28
    • 2016-08-23
    • 2020-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多