我的帧缓冲区有啥问题?
Posted
技术标签:
【中文标题】我的帧缓冲区有啥问题?【英文标题】:What's wrong with my framebuffer?我的帧缓冲区有什么问题? 【发布时间】:2014-03-07 19:04:19 【问题描述】:我正在创建一个帧缓冲区对象作为延迟着色的 gbuffer。我主要从http://ogldev.atspace.co.uk/ 学习,并修改为更...理智一点。这是我创建帧缓冲区的源代码:
/* Create the FBO */
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
/* Create the gbuffer textures */
glGenTextures(GBUFFER_NUM_TEXTURES, tex);
/* Create the color buffer */
glBindTexture(GL_TEXTURE_2D, tex[GBUFFER_COLOR]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex[GBUFFER_COLOR], 0);
/* Create the normal buffer */
glBindTexture(GL_TEXTURE_2D, tex[GBUFFER_NORMAL]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16F, width, height, 0, GL_RG, GL_FLOAT, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, tex[GBUFFER_NORMAL], 0);
/* Create the depth-stencil buffer */
glBindTexture(GL_TEXTURE_2D, tex[GBUFFER_DEPTH_STENCIL]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, width, height, 0, GL_DEPTH_STENCIL, GL_FLOAT, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, tex[GBUFFER_DEPTH_STENCIL], 0);
GLenum drawBuffers[] = GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1;
glDrawBuffers(2, drawBuffers);
glReadBuffer(GL_NONE);
/* Check for errors */
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE)
error("In GBuffer::init():\n");
errormore("Failed to create Framebuffer, status: 0x%x\n", status);
fbo = 0;
return;
// restore default FBO
glBindFramebuffer(GL_FRAMEBUFFER, 0);
但是,当我运行它时,状态返回 GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
。如果不清楚,我正在尝试创建 3 个 gbuffers:
我可以看到的可能问题区域可能是将 GL_FLOAT 用于普通缓冲区,将 GL_FLOAT 用于深度模板缓冲区。我想 GL_HALF_FLOAT 会更适合法线,但这不在我可以与 glTexImage2D 一起使用的类型列表中。同样,我不知道哪种类型最适合用于深度模板缓冲区。
我做错了什么?
【问题讨论】:
对于深度模板纹理,GL_UNSIGNED_INT_24_8 似乎比 GL_FLOAT 更合适。 【参考方案1】:您对GL_FLOAT
的使用大部分无关紧要,因为实际上没有发生像素传输。
只要是有意义的数据类型,您就可以在那里提供任何您想要的东西。虽然当您为数据传递NULL
时不会发生像素传输,但 GL 仍会根据有效类型集验证像素传输数据类型,如果您做错了会引发错误。为此,如果引发错误,纹理将不完整,因此不能用作 FBO 附件。
这就是问题所在,GL_FLOAT
不是一个有意义的数据类型,用于将像素转换为压缩的 GL_DEPTH_STENCIL
图像格式......它需要一个压缩的数据类型,例如 GL_UNSIGED_INT_24_8
或像 @ 这样的真正奇特的数据类型987654327@(64 位压缩浮点深度 + 模板格式)。
无论如何,实际上有两个组件需要打包到您的数据类型中。 GL_FLOAT
只能描述两个组件之一,因为浮点模板缓冲区没有意义。
顺便说一句,如果您使用glTexStorage2D (...)
之类的东西仅为纹理分配存储空间,则可以完全避免这种关于像素传输数据类型的混乱混乱。 glTexImage2D (...)
具有双重职责,为纹理 LOD 分配存储空间并提供使用数据对其进行初始化的机制。如果您使用 FBO 绘制到纹理中,您真的不关心后面的部分,因为这是它获取任何数据的唯一位置。
【讨论】:
您的两个建议都有效。非常感谢你!作为旁注,对于我的普通缓冲区,我应该使用GL_RG16F
(半浮点数)还是GL_RG16I
(签名短裤)?
@HaydnV.Harach: GL_RG16I
没有意义,那是整数格式。你想要的是浮点或定点。这是因为(标准化)法线中的值的范围为 [-1,1]。 GL_RG16
(定点)就足够了,但由于范围为 [0,1],因此您必须应用比例+偏差将其重新调整为 [-1,1]。我假设您正在使用sqrt
技巧来重建您正常的缺失组件?如果您正在寻找能够提供 > 8 位精度的存储优化格式,您还可以尝试 RGBA 10:10:10:2(定点)或 RGB 11:11:10(浮点)。
我应该补充一点,如果你想要一个 signed 定点图像格式,你需要使用所谓的@ 987654336@(签名标准化)。典型的图像格式(例如GL_RGB8
)就是所谓的UNORM
(无符号归一化)。 GL_RG16I
与 GL_RG16_SNORM
完全不同,但要了解为什么您需要了解整数格式与定点(归一化)格式。我建议阅读this,它应该能更好地解释事情。
谢谢,GL_RG16_SNORM
是我的意思,也是我一直在寻找的。span>
哪个更好,使用GL_RG16_SNORM
/GL_HALF_FLOAT
并使用sqrt
技巧来重建z,或者使用GL_R11F_G11F_B10F
并将值缩放到[-1,+1]?我想前者会给我更高的质量,而后者需要更少的片段着色器指令......以上是关于我的帧缓冲区有啥问题?的主要内容,如果未能解决你的问题,请参考以下文章