使用glBlitFramebuffer进行多重采样

时间:2015-10-01 09:45:06

标签: opengl antialiasing fbo multisampling

这是我第一次尝试使用opengl进行多重采样(用于抗锯齿)。基本上,我在屏幕上绘制背景(不应该消除锯齿),然后我绘制应该消除锯齿的顶点。 到目前为止我做了什么:

{{1}}

问题是:当我调用glBlitFramebuffer(...)时,整个背景变黑,我只看到消除锯齿的顶点。

有什么建议吗?

1 个答案:

答案 0 :(得分:9)

通常情况下,如果要在图像中考虑透明度的同时在现有渲染上渲染新图像/纹理,则混合是最明显的选项。将渲染到多重采样帧缓冲区视为具有透明度的图像,这正是您所拥有的情况。

在这种情况下,有一些挑战使混合的使用比平常更困难。首先,glBlitFramebuffer()不应用混合。来自规范:

  

Blit操作绕过片段管道。影响blit的唯一片段操作是像素所有权测试和剪刀测试。

如果没有多重采样,这很容易克服。您可以通过绘制屏幕大小的纹理四边形来执行blit,而不是使用glBlitFramebuffer()。由于现在所有片段操作都在使用,您可以使用混合。

Howerver,"绘制纹理四边形"由于您的内容是多重采样的,因此部分变得更加棘手。我想到了一些选择。

将背景渲染到FBO

您可以将背景渲染到多重采样FBO而不是主帧缓冲区。然后,您可以像现在一样使用glBlitFramebuffer()

您可能会想:"但我不希望我的背景被消除锯齿!" 这不是一个真正的问题。您只需在绘制背景时禁用多重采样:

glDisable(GL_MULTISAMPLE);

我认为应该给你你想要的东西。如果确实如此,它是迄今为止最简单的选择。

多重采样纹理

OpenGL 3.2及更高版本支持多重采样纹理。为此,您将使用纹理而不是渲染缓冲区作为FBO的颜色缓冲区。纹理分配:

glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8,
                         xsize, ysize, GL_FALSE);

还有其他方面我不能在这里介绍。如果您想探索此选项,可以阅读规范或其他来源中的所有详细信息。例如,着色器代码中纹理的采样工作方式不同,使用不同的采样器类型,以及只允许您一次读取一个采样的采样函数。

两阶段Blitting

您可以使用glBlitFramebuffer()的混合来解析多重采样内容,以及"手册"用于将内容混合到默认帧缓冲区中的blit:

  1. 创建第二个FBO,其中颜色附件是常规纹理,而不是多重采样纹理。
  2. 使用glBlitFramebuffer()从第一个FBO中的多重采样渲染缓冲区复制到第二个FBO中的纹理。
  3. 设置并启用混合。
  4. 使用作为第二个FBO附件的纹理绘制一个屏幕大小的四边形。
  5. 虽然这看起来有点尴尬,并且需要额外的副本,这对性能不利,但它相当简单。

    最后渲染背景

    为此,您完全按照自己现在所做的操作,将多重采样的FBO内容复制到glBlitFramebuffer()的默认帧缓冲区。但是你首先这样做,然后渲染背景

    您可能认为这不会起作用,因为它会将背景放在其他内容的前面,这使得......背景不是很多。

    但这里是混合再次发挥作用的地方。虽然在其他内容之上混合内容是使用混合的最常用方式,但您也可以使用它来渲染隐藏现有内容。要做到这一点,你需要做一些事情:

    • 具有alpha平面的帧缓冲区。您的请求取决于您用于OpenGL设置的窗口系统/工具包。它通常位于您请求深度缓冲区,模板缓冲区(如果需要)等的同一区域中。它通常被指定为多个alpha平面,通常设置为8。
    • 正确的混合功能。对于前后混合,通常使用:

      glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE);
      

      这增加了以前没有渲染任何内容的新渲染(即目标中的alpha为0),并且在已经渲染的地方(即目标alpha为1)保持前一渲染不变。

      如果渲染涉及部分透明度,混合设置会变得有点棘手。

    这可能看起来有点复杂,但是一旦你了解混合功能的工作方式,它就非常直观。我认为它总体上是一个优雅而有效的解决方案,可以解决您的整体问题。