【问题标题】:OpenGL Blend Modes vs Shader BlendingOpenGL 混合模式与着色器混合
【发布时间】:2012-07-24 15:14:47
【问题描述】:

我目前正在对 OpenGL 和着色器进行一些研究,但我似乎无法弄清楚使用 glBlendMode 进行混合或在着色器中编写自己的混合模式之间是否存在任何根本区别。

选择前者还是后者的原因是什么?通过选择一个而不是另一个是否存在任何性能瓶颈?还是这只是个人喜好问题?

【问题讨论】:

    标签: opengl shader fragment-shader


    【解决方案1】:

    使用 glBlendFunc 的传统混合无法在着色器中复制。混合需要在修改目标帧缓冲区之前对其进行采样,这在当前硬件上是无法做到的。

    目前您只能传递一种颜色,并选择有限的混合模式之一(glBlendFunc/glBlendEquation),GPU 的光栅化器将在写入帧缓冲区之前应用这些混合模式。

    【讨论】:

    • 这是否意味着着色器不能混合两个纹理并对其应用混合模式并输出 1 个新纹理?如果人们在网络上发布 Photoshop 混合模式着色器,我会觉得有些奇怪。你能详细说明一下吗?谢谢!
    • 不,您仍然可以在着色器中混合两个纹理,但这不是混合的作用。混合将当前像素与帧缓冲区混合。您仍然可以通过其他方式(绘制纹理和混合)实现相同的效果。 @bartcla
    • 好的,如果我理解正确的话:通过glBlendFunc 混合与在着色器中混合纹理完全不同?假设我想用“乘法”混合模式混合两张照片。这应该在着色器中完成,而不是使用 glBlendFunc?你能举一个使用glBlendFunc的例子吗?
    • 对于你的前两个问题,是的,这是正确的。只需对两个纹理进行采样,然后在着色器中将它们相乘。混合通常更多地用于透明度,例如,如果您想绘制有色窗口。当你想在已经绘制的场景的其余部分之上绘制透明的东西时。 @bartcla
    【解决方案2】:

    当着色器从纹理读取同时渲染到同一纹理时,结果是不确定的。这就是为什么将“传统”或固定功能与 glBlendFunc 和 glBlendEquation 混合很有用的原因。

    要使用传统混合来混合两张图像,您需要渲染第一张图像,设置混合模式、函数和方程式,然后渲染第二张图像。这样可以保证给出正确的结果,并且通常是实现透明度等效果的最快方法。

    要使用着色器实现相同的效果,您需要将第一张图像渲染到辅助纹理,更改着色器,然后将第二张图像渲染到实际的帧缓冲区,在片段着色器中将混合作为最后一步。由于纹理读取的额外开销,这通常会比较慢,并且肯定会为辅助纹理使用更多的 GPU 内存。

    在现代硬件上,这两种技术之间的差异往往很小。

    【讨论】:

      【解决方案3】:

      在我知道的三种情况下,可以在着色器中模拟 OpenGL 混合:

      1. 您有 Direct3D11 或 OpenGL 等效项,并且您将渲染目标绑定为像素着色器中的读写纹理。这可以实现任意复杂的混合操作,但在进行简单混合时不会有高性能,因为您正在绕过 GPU 的特殊硬件进行简单混合。

      2. 您有一个奇特的“基于图块”的 GPU,即使是简单的混合也是由“alpha 着色器”完成的。在这种情况下,OpenGL 中的简单混合与等效着色器代码之间没有性能差异。但是你不太可能有这样的 GPU,而且 OpenGL 也不会公开这个功能。

      3. 您可以避开整个固定功能硬件光栅化管道,将自己的“计算着色器”编写为复合体。如果你能做到这一点,“alpha 着色器”之类的东西将成为你基于图块的管道的一部分,但要做到这一点需要做很多工作,所以 alpha 混合将是你最不关心的问题。

        李>

      【讨论】:

      • 1:更不用说,如果多个着色器调用访问同一个像素,您必须处理显式同步访问。
      • 平铺光栅化的一个很好的方面是,通常情况下,像素之间不存在竞争条件。但是,如果您说的是 1. 那么是的,您是对的:在这种情况下,将违反三角形光栅化连续完成的保证。
      【解决方案4】:

      这实际上可以通过使用纹理屏障功能的 gl 3.0 扩展来完成:

      http://www.opengl.org/registry/specs/NV/texture_barrier.txt

      基本上,在你写完背景之后,你可以使用 TextureBarrierNV() 函数来确保 texel 被刷新,然后你可以在单个着色器阶段执行读/写操作(一定要避免多重采样缓冲区,因为只有一次写入操作实际上是允许的)..

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-10-23
        • 2014-04-09
        • 1970-01-01
        • 1970-01-01
        • 2017-01-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多