OpenGL ES 多目标渲染(MRT)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenGL ES 多目标渲染(MRT)相关的知识,希望对你有一定的参考价值。

参考技术A

OpenGL ES 多目标渲染(MRT),即多重渲染目标,是 OpenGL ES 3.0 新特性,它允许应用程序一次渲染到多个缓冲区。

利用 MRT 技术,片段着色器可以输出多个颜色,可以用于保存 RGBA 颜色、 法线、 深度信息或者纹理坐标,每个颜色连接一个颜色缓冲区。

就目前接触的 MRT 技术,在图形图像算法中比较常用,主要用于获取算法中间结果、底图或者 Mask ,也用于多种高级渲染算法中,例如延迟着色和快速环境遮蔽估算。

使用 MRT 技术,一般需要为帧缓冲区对象(FBO)的设置多个颜色附着。 FBO(Frame Buffer Object)即帧缓冲区对象,实际上是一个可添加缓冲区的容器,可以为其添加纹理或渲染缓冲区对象(RBO)。

FBO 本身不能用于渲染,只有添加了纹理或者渲染缓冲区之后才能作为渲染目标,它提供了 3 种附着(Attachment),分别是颜色附着、深度附着和模板附着。

本文为演示 MRT 技术的使用,为 FBO 的颜色附着设置 4 个纹理,一个纹理作为一个颜色附着(颜色缓冲区)。

本文使用 MRT 技术对应的顶点和片段着色器如下,我们使用了 4 个纹理作为颜色附着,其中直接渲染原图到第一个纹理,分别渲染 RGB 三个通道的图像到另外三个纹理,然后再利用另外一个着色器将 4 个纹理的结果渲染到屏幕上。

用于渲染(采样) 4 个纹理的片段着色器,实际上是将 4 张图做一个拼接。

首先获取当前默认帧缓冲区的 id ,然后绑定我们新创建的 FBO 渲染,渲染完成再绑定默认帧缓冲区对象,使用另外一个着色器程序渲染四张纹理图。

OpenGL ES 多目标渲染结果。

OpenGL中的多个渲染目标与Cg

【中文标题】OpenGL中的多个渲染目标与Cg【英文标题】:Multiple Render Targets in OpenGL with Cg 【发布时间】:2012-04-30 16:20:26 【问题描述】:

我正在尝试(徒劳地)使用 OpenGL 和 NVIDIA 的 Cg 着色器系统设置 MRT,最终目标是延迟渲染。我已经成功地让单个目标的着色器和渲染到纹理工作,但是一旦我尝试将一个对象渲染到多个渲染目标,它就无法显示在其中任何一个目标中。

我正在通过以下方式设置帧缓冲区对象:

// Initialize textures
// (I'll spare you the code since I've  done that without issues)

// Initialize the FBO
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glGenRenderbuffers(1, &depthBuff);
glBindRenderbuffer(GL_RENDERBUFFER, depthBuff);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
                          GL_RENDERBUFFER, depthBuff);

// -snip-

// Bind each texture we want to use to the FBO at rtNum
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + rtNum,
                       GL_TEXTURE_2D, tex->getID(), 0);
// Check to make sure we're good to go
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) 
    throw Exceptions::GLException("Frame buffer object is not complete.",
                                __FUNCTION__);


// -snip-

// Call glDrawBuffers with the RTs we want to render to
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
unique_ptr<GLenum[]> arr(new GLenum[num]);
for (size_t c = 0; c < num; ++c)
    arr[c] = GL_COLOR_ATTACHMENT0 + c;
glDrawBuffers(num, arr.get());
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) 
    throw Exceptions::GLException("Frame buffer object is not complete.",
                                __FUNCTION__);

// -snip-

// Set up the FBO for rendering
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glPushAttrib(GL_VIEWPORT_BIT);
glViewport(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Draw calls here

glBindFramebuffer(GL_FRAMEBUFFER, 0);
glPopAttrib();

我的着色器(使用cgGLGetLatestProfile 返回的配置文件编译)是:

struct VertexShaderOutput 
    float4 position : POSITION;
    float3 normal : TEXCOORD0;
    float4 color : COLOR;
;

VertexShaderOutput VS_Main(float4 local : POSITION,
                        float4 normal : NORMAL,
                        float4 color : COLOR,
                        uniform float4x4 modelViewProj,
                        uniform float4x4 modelViewIT)

    VertexShaderOutput OUT;
    OUT.position = mul(modelViewProj, local);
    OUT.normal= mul(modelViewIT, normal).xyz;
    OUT.color = color;
    return OUT;


struct FragmentShaderOutput 
    float4 unlit : COLOR0;
    float4 normAndDepth : COLOR1;
;

FragmentShaderOutput FS_Main(VertexShaderOutput vsOut)

    FragmentShaderOutput OUT;
    OUT.unlit = float4(1.0f, 1.0f, 0.0f, 1.0f);//vsOut.color;
    OUT.normAndDepth.rgb = vsOut.normal;
    // Calculate depth later
    OUT.normAndDepth.a = 1.0f;
    return OUT;

有人知道为什么这可能会失败吗?

【问题讨论】:

您在评论中添加了// Call glDrawBuffers,但我实际上并没有在任何地方看到这个电话。这只是复制错误吗? @Tim:是的,这只是一个复制错误。我现在已经修好了。 顺便说一句,你应该只在你完成后检查帧缓冲区的完整性。进行检查的全部意义在于,您可以在从一个完整的 FBO 状态到另一个完整的 FBO 状态的过程中经历不完整的帧缓冲区状态。 这个问题似乎是 Cg 的一个更深层次的问题。当我有更多了解时,我会发布更多。 我在here 发布的问题似乎是导致问题的原因。 【参考方案1】:

上述方法是正确的。问题似乎与硬件和 Cg 的组合有关。在我的带有集成芯片组的笔记本电脑上,尽管 Cg 没有返回任何错误,但 MRT 失败并发生了许多其他与着色器相关的问题。在我的配备 GeForce GTX260 的台式机上,一切正常。

【讨论】:

以上是关于OpenGL ES 多目标渲染(MRT)的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL中的多个渲染目标与Cg

OpenGL 3.30 / GLSL 3.30 - MRT 输出黑色纹理

在 iOS 设备上将多个渲染目标 (MRT) 与多重采样组合失败,而不是在模拟器上

将两个图像附加到 fbo 以进行 mrt 渲染

将 OpenGL ES 2 移植到 OpenGL

在 OpenGL ES 2.0 中渲染到纹理时的抗锯齿