使用帧缓冲区将深度缓冲区渲染到纹理中

Posted

技术标签:

【中文标题】使用帧缓冲区将深度缓冲区渲染到纹理中【英文标题】:Render the depth buffer into a texture using a frame buffer 【发布时间】:2012-09-22 18:03:34 【问题描述】:

我正在使用 JOGL,但这个问题通常适用于 OpenGL。周围似乎有类似的问题,但它们要么针对 GLSL 代码,与复制帧缓冲区的内容有关,要么是一般建议 - 使用帧缓冲区对象而不是 glCopyTexSubImage2D

问题

我正在做一些阴影映射。如何使用帧缓冲区对象将深度通道直接渲染到纹理?

能否请您发布一段初始化纹理和帧缓冲区对象的代码,以及在渲染场景之前初始化所有内容的代码?

目前,我使用glCopyTexSubImage2D。我像这样初始化纹理:

glGenTextures(1, &textureNo)
glBindTexture(GL_TEXTURE_2D, textureNo)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL)
glTexParameterf(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY)
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 2048, 2048, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, null)

然后我像这样渲染:

glBindTexture(GL_TEXTURE_2D, textureNo)
glClear(GL_DEPTH_BUFFER_BIT)
drawScene()
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 2048, 2048)

这很好用,纹理最终保持场景的深度通道 - 这意味着我的投影和视图矩阵设置正确,可以从光的角度查看场景。我想改用帧缓冲区对象。

我需要在上面进行哪些更改才能直接渲染到纹理而不是使用帧缓冲区对象?

编辑:

这是我尝试过的。我首先初始化了帧缓冲对象:

glGenFramebuffers(1, &fbo)

然后我这样渲染:

glBindFramebuffer(GL_FRAMEBUFFER, fbo)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, textureNo, 0)
glBindTexture(GL_TEXTURE_2D, textureNo)
drawScene()

我已经确认上述方法适用于GL_RGBGL_COLOR_ATTACHMENT0 类型的纹理,但它似乎不适用于GL_DEPTH_COMPONENT 类型的纹理和GL_DEPTH_ATTACHMENT - 深度通道不会渲染到纹理中textureNo 以上。

【问题讨论】:

您是否尝试过一些不起作用的东西,或者您只是在寻找某人为您编写代码以便您可以将其复制并粘贴到您的应用程序中? FBOs 并不难理解。 实际上,我写了一些不起作用的东西。我正在初始化一个帧缓冲区对象,然后将纹理附加到它上面。但是,这并没有将场景的深度通道渲染到纹理上。有趣的是,当我使用帧缓冲区对象将场景渲染为常规的GL_RGB 纹理时,它可以正常工作。我无法在文档中了解使用帧缓冲区对象渲染深度通道与渲染 RGB 通道有何不同。 我在 JOGL 上为 Scala (github.com/axel22/scalagl) 编写代码,它旨在提供一些 oo 风格的资源管理和更结构化的编码,所以我不得不调整我的代码一点点 - 我已经编辑了问题以显示我做了什么。 【参考方案1】:

假设这是所有 FBO 设置代码,我看不到您调用 glCheckFramebufferStatus 的部分。你知道,这个函数会告诉你你的Framebuffer Object was incomplete,因此渲染它会失败。

具体来说,它会给你GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER​,因为你没有设置一个有效的绘图缓冲区。如果不使用颜色附件,则需要使用glDrawBuffer 将所有颜色缓冲区写入设置为GL_NONE

这是一个常见的 FBO 问题;你不会是第一个没有看到它的人。但这就是为什么在修改 FBO 后始终检查glCheckFramebufferStatus 至关重要的原因。

【讨论】:

@axel22: “不知道为什么”出于同样的原因,您必须将绘图缓冲区设置为无。

以上是关于使用帧缓冲区将深度缓冲区渲染到纹理中的主要内容,如果未能解决你的问题,请参考以下文章

Opengl渲染到深度纹理 - 红色?

OpenGL 帧缓冲区 - 渲染到纹理创建带有主帧缓冲区内容的纹理

创建没有帧缓冲区绑定的 Opengl 渲染缓冲区

JOGL 和帧缓冲区渲染到纹理的问题:无效帧缓冲区操作错误

我是不是需要将渲染缓冲区附加到已经附加了纹理的帧缓冲区?

WebGL入门(四十一)-使用帧缓冲区对象(FBO)实现将渲染结果作为纹理绘制到另一个物体上