OpenGL Blending - 用不同的颜色填充交叉点
OpenGL Blending - fill intersections with a different color
我在屏幕上渲染了一堆形状(多边形),我没有使用深度测试。
我只是希望这些形状在绘制到空的 space 上时使用它们自己的颜色,并且在绘制到任何非空的东西上时使用它们自己的颜色,即在我的情况下绘制在另一个多边形上。
这里的问题实际上在于我可以使用的颜色和我可以分配的因素。
所以假设我的颜色是任意的,比如 RGBA(0.5, 0.7, 0.3, 1.0)。
这意味着当我绘制第一个对象时,它将最终出现在帧缓冲区中。
然后我用相同的颜色绘制第二个重叠的对象。但我希望重叠区域为红色 (1,0,0,1)。
但在这里我 运行 遇到了问题,因为无论我为混合函数分配什么 sFactor 和 dFactor - 我永远无法增加值。
我显然需要在 Framebuffer 中没有任何东西时使用 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);
效果很好!我还包含了擦除一些渲染图像的部分,以防万一有人需要类似的任务。
几个不直观的点:
- glClear(GL_STENCIL_BUFFER_BIT) 实际上使用了 glStencilMask(),因此必须将其设置为 0xFF 才能完全清除。我错误地将清除调用置于掩码分配之上,因此本质上它保留了前一个渲染周期 0x00 的掩码并且没有清除模板缓冲区。如果您想用画笔演奏莱昂纳多,那正是您想要的。 ^_^
- glStencilFunc(func , ref, mast) 实际上是从直观的角度倒退的。公式是:(ref & mask) func (stencil & mask)。即 glStencilFunc(GL_LESS,1,0xFF);将丢弃任何大于 1 的片段,因为公式为 (1 & FF) < (stencil & FF),即当 stencil 为 1 和 0 - 公式为 FALSE,片段将被丢弃。如果stencil为2及以上,则1<2 = true,片段保留
您的问题最好借助 stencil buffer.
解决
您使用 glStencilOp(GL_INCR,GL_INCR,GL_INCR)
将图元渲染到屏幕外模板缓冲区中。这有效地计算了每个像素有多少图元重叠。完成后,使用着色器绘制全屏四边形,该着色器根据模板缓冲区中的值计算颜色(零表示背景颜色)。
我在屏幕上渲染了一堆形状(多边形),我没有使用深度测试。 我只是希望这些形状在绘制到空的 space 上时使用它们自己的颜色,并且在绘制到任何非空的东西上时使用它们自己的颜色,即在我的情况下绘制在另一个多边形上。
这里的问题实际上在于我可以使用的颜色和我可以分配的因素。 所以假设我的颜色是任意的,比如 RGBA(0.5, 0.7, 0.3, 1.0)。 这意味着当我绘制第一个对象时,它将最终出现在帧缓冲区中。
然后我用相同的颜色绘制第二个重叠的对象。但我希望重叠区域为红色 (1,0,0,1)。
但在这里我 运行 遇到了问题,因为无论我为混合函数分配什么 sFactor 和 dFactor - 我永远无法增加值。
我显然需要在 Framebuffer 中没有任何东西时使用 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);
效果很好!我还包含了擦除一些渲染图像的部分,以防万一有人需要类似的任务。
几个不直观的点:
- glClear(GL_STENCIL_BUFFER_BIT) 实际上使用了 glStencilMask(),因此必须将其设置为 0xFF 才能完全清除。我错误地将清除调用置于掩码分配之上,因此本质上它保留了前一个渲染周期 0x00 的掩码并且没有清除模板缓冲区。如果您想用画笔演奏莱昂纳多,那正是您想要的。 ^_^
- glStencilFunc(func , ref, mast) 实际上是从直观的角度倒退的。公式是:(ref & mask) func (stencil & mask)。即 glStencilFunc(GL_LESS,1,0xFF);将丢弃任何大于 1 的片段,因为公式为 (1 & FF) < (stencil & FF),即当 stencil 为 1 和 0 - 公式为 FALSE,片段将被丢弃。如果stencil为2及以上,则1<2 = true,片段保留
您的问题最好借助 stencil buffer.
解决您使用 glStencilOp(GL_INCR,GL_INCR,GL_INCR)
将图元渲染到屏幕外模板缓冲区中。这有效地计算了每个像素有多少图元重叠。完成后,使用着色器绘制全屏四边形,该着色器根据模板缓冲区中的值计算颜色(零表示背景颜色)。