延迟渲染 - Renderbuffer vs Texture

时间:2016-12-16 10:21:56

标签: opengl deferred-rendering

所以,我一直在读这个,我还没有得出结论。一些例子使用纹理作为渲染目标,有些人使用渲染缓冲区,有些人同时使用它们!

例如,仅使用纹理:

// Create the gbuffer textures
glGenTextures(ARRAY_SIZE_IN_ELEMENTS(m_textures), m_textures);
glGenTextures(1, &m_depthTexture);

for (unsigned int i = 0 ; i < ARRAY_SIZE_IN_ELEMENTS(m_textures) ; i++) {
    glBindTexture(GL_TEXTURE_2D, m_textures[i]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, WindowWidth, WindowHeight, 0, GL_RGB, GL_FLOAT, NULL);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, m_textures[i], 0);
}

两个

glGenRenderbuffersEXT ( 1, &m_diffuseRT );
glBindRenderbufferEXT ( GL_RENDERBUFFER_EXT, m_diffuseRT );
glRenderbufferStorageEXT ( GL_RENDERBUFFER_EXT, GL_RGBA, m_width, m_height );
glFramebufferRenderbufferEXT ( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, m_diffuseRT );
glGenTextures ( 1, &m_diffuseTexture );
glBindTexture ( GL_TEXTURE_2D, m_diffuseTexture );
glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
// Attach the texture to the FBO
glFramebufferTexture2DEXT ( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_diffuseTexture, 0 );

区别是什么?什么是创建纹理,渲染缓冲区,然后分配给另一个?在成功为图像提供纹理后,它已经分配了内存,那么为什么需要将它绑定到渲染缓冲区? 为什么会使用纹理或渲染缓冲区?有什么好处?

我读过你无法从renderbuffer中读取,只能读取纹理。是什么时候使用它呢?

编辑: 所以,我目前的GBuffer代码是这样的:

    enum class GBufferTextureType
        {
        Depth = 0,
        Position,
        Diffuse,
        Normal,
        TexCoord
        };

。 。

glGenFramebuffers ( 1, &OpenGLID );
if ( Graphics::GraphicsBackend->CheckError() == false )
    {
    Delete();
    return false;
    }

glBindFramebuffer ( GL_FRAMEBUFFER, OpenGLID );
if ( Graphics::GraphicsBackend->CheckError() == false )
    {
    Delete();
    return false;
    }

uint32_t TextureGLIDs[5];
glGenTextures ( 5, TextureGLIDs );
if ( Graphics::GraphicsBackend->CheckError() == false )
    {
    Delete();
    return false;
    }

// Create the depth texture
glBindTexture ( GL_TEXTURE_2D, TextureGLIDs[ ( int ) GBufferTextureType::Depth] );
glTexImage2D ( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, In_Dimensions.x, In_Dimensions.y, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL );
glFramebufferTexture2D ( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, TextureGLIDs[ ( int ) GBufferTextureType::Depth], 0 );

// Create the color textures
for ( unsigned cont = 1; cont < 5; ++cont )
    {
    glBindTexture ( GL_TEXTURE_2D, TextureGLIDs[cont] );
    glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGB32F, In_Dimensions.x, In_Dimensions.y, 0, GL_RGB, GL_FLOAT, NULL );
    glFramebufferTexture2D ( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + cont, GL_TEXTURE_2D, TextureGLIDs[cont], 0 );
    }

// Specify draw buffers
GLenum DrawBuffers[4];
for ( unsigned cont = 0; cont < 4; ++cont )
    DrawBuffers[cont] = GL_COLOR_ATTACHMENT0 + cont;

glDrawBuffers ( 4, DrawBuffers );

if ( Graphics::GraphicsBackend->CheckError() == false )
    {
    Delete();
    return false;
    }

GLenum Status = glCheckFramebufferStatus ( GL_FRAMEBUFFER );
if ( Status != GL_FRAMEBUFFER_COMPLETE )
    {
    Delete();
    return false;
    }

Dimensions = In_Dimensions;

// Unbind
glBindFramebuffer ( GL_FRAMEBUFFER, 0 );

这是要走的路吗? 我仍然需要编写相应的着色器......

2 个答案:

答案 0 :(得分:6)

  

创建纹理,渲染缓冲区然后将其分配给另一个是什么意思?

那不是发生了什么。但那没关系,因为第二个示例代码是错误的无意义。 glFramebufferTexture2DEXT覆盖了glFramebufferRenderbufferEXT的绑定。渲染缓冲区在创建后实际上从未使用过。

如果您在某处找到了在线代码,我强烈建议您忽略源告诉您有关OpenGL开发的任何内容。虽然我会建议,但是因为它使用&#34; EXT&#34; 2016 中的扩展功能,自核心FBO上市以来已近十年。

  

我读过你无法从renderbuffer中读取,只能读取纹理。是什么时候使用它呢?

这完全是他们的观点:您使用渲染缓冲区来处理您 想要阅读的图像。这对延迟渲染没用,因为你真的想从中读取它们。

但是想象一下,如果您正在生成场景的反射图像,稍后您将在主场景中将其用作纹理。那么,要渲染反射场景,您需要一个深度缓冲区。但是你不会从那个深度缓冲区读取(不管是纹理,无论如何);你需要一个深度缓冲来进行深度测试。但是,您之后要阅读的唯一图像是彩色图像。

因此,您可以将深度缓冲区设为渲染缓冲区。这告诉实现可以将图像放入任何最有效用作深度缓冲区的存储器中,而不必担心回读性能。这可能或可能不会对性能产生影响。但至少,它不会比使用纹理慢。

答案 1 :(得分:1)

大多数渲染场景需要深度和/或模板缓冲区,尽管您很少需要从着色器中对存储在模板缓冲区中的数据进行采样。

如果你的帧缓冲区没有存储这些数据的位置,那么进行深度/模板测试将不可能,并且任何使用这些片段测试的渲染通道都需要附加了相应图像的帧缓冲区。

如果您不打算在着色器中使用深度/模板缓冲区数据,则渲染缓冲区将很乐意满足固定功能片段测试的存储要求。渲染缓冲区的格式限制比纹理更少,尤其是如果我们将此讨论排除在多重采样之外。

D3D10引入了对多重采样颜色纹理的支持,但省略了多重采样深度纹理; D3D10.1后来解决了这个问题,并在D3D10的初始设计监督得到纠正后最终确定了GL3.0。

预GL3 / D3D10.1设计会在GL中表现为多重采样帧缓冲对象,它允许纹理或渲染缓冲区颜色附件,但会强制您使用渲染缓冲区进行深度附加。

Renderbuffers最终是存储的最低标准,它们可以帮助您解决功能有限的硬件问题。在某些无法直接绘制到纹理中的情况下,您实际上可以将存储在渲染缓冲区中的数据blit放入纹理中。

为此,您可以通过从一个帧缓冲区到另一个帧缓冲区进行blitting,将多重采样渲染缓冲区解析为单个采样纹理。这是隐式多重采样,(将)允许您使用标准纹理查找使用先前渲染过程的消除锯齿结果。不幸的是,对于延迟着色中的抗锯齿而言,它完全没用 - 你需要显式多重采样解析。

尽管如此,说渲染缓冲区不可读是不正确的;它在各个方面都是如此,但由于你的目标是延迟着色,因此需要额外的GL命令才能将数据复制到纹理中。