【问题标题】:deferred rendering - Renderbuffer vs Texture延迟渲染 - 渲染缓冲区与纹理
【发布时间】:2016-12-16 10:21:55
【问题描述】:

所以,我一直在阅读这方面的内容,但我仍然没有找到结论。有些示例使用纹理作为渲染目标,有些人使用渲染缓冲区,有些人同时使用!

例如,仅使用纹理:

// 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 );

有什么区别?创建纹理、渲染缓冲区然后将一个分配给另一个的意义何在?在您成功地为图像提供纹理后,它的内存被分配了,那么为什么需要将它绑定到渲染缓冲区呢? 为什么要使用纹理或渲染缓冲区?有什么优势?

我了解到您无法从渲染缓冲区中读取,只能从纹理中读取。那它有什么用呢?

编辑: 所以,我当前的 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 );

这是要走的路吗? 还是得自己写对应的shader...

【问题讨论】:

  • 第二个版本根本没有任何意义,因为它覆盖了渲染缓冲区的绑定。

标签: opengl deferred-rendering


【解决方案1】:

创建纹理、渲染缓冲区然后将其中一个分配给另一个的意义何在?

这不是正在发生的事情。但这没关系,因为第二个示例代码是错误的废话。 glFramebufferTexture2DEXT 正在覆盖来自 glFramebufferRenderbufferEXT 的绑定。渲染缓冲区在创建后从未真正使用过。

如果您在网上某处发现该代码,我强烈建议您忽略该来源告诉您的有关 OpenGL 开发的任何内容。虽然我还是建议您这样做,因为它在 2016 中使用了“EXT”扩展功能,距离核心 FBO 可用已经快十年了。

我了解到您无法从渲染缓冲区中读取,只能从纹理中读取。那它有什么用呢?

这完全是它们的重点:您对不想想要读取的图像使用渲染缓冲区。这对于延迟渲染没有用,因为您确实想从中读取。

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

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

【讨论】:

  • 好的。我要试试看。这些代码示例是在几个不同的地方找到的,所以我对这一切感到非常困惑。
【解决方案2】:

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

如果您的帧缓冲区没有存储这些数据的位置,并且使用这些片段测试的任何渲染通道都需要一个带有适当图像的帧缓冲区,则不可能进行深度/模板测试。

如果您不打算在着色器中使用深度/模板缓冲区数据,渲染缓冲区将很高兴满足固定功能片段测试的存储要求。与纹理相比,渲染缓冲区的格式限制更少,特别是如果我们将这个讨论绕到多重采样上。


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

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


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

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

尽管如此,说渲染缓冲区不可读是不正确的。它在每个意义上都是如此,但由于您的目标是延迟着色,因此需要额外的 GL 命令来将数据复制到纹理中。

【讨论】:

  • 我强烈怀疑您在第二个示例中尝试执行/显示的内容实际上是帧缓冲区之间的 blit。简单地在原件的位置附加不同类型的图像不会有任何作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-06
  • 1970-01-01
  • 2014-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多