无法使用深度附件渲染到 FBO

Posted

技术标签:

【中文标题】无法使用深度附件渲染到 FBO【英文标题】:Not being able to render into FBO with Depth Attachment 【发布时间】:2014-02-04 19:56:28 【问题描述】:

我正在尝试实施阴影贴图几天,我想我开始看到手头的真正问题:我有一个附加了深度纹理的 FBO,用于阴影贴图的光通道,但是里面没有渲染任何东西。甚至没有硬编码值。

我已经仔细检查了可视化深度纹理的程序部分,它正在使用常规纹理,而且我没有看到我的场景中出现阴影,所以我认为肯定有问题。

初始化:

    //shadow FBO and texture
    depthFBO = new FrameBufferObject().create().bind();
    depthTexture = new Texture2D().create().bind()
            .storage2D(12, GL_DEPTH_COMPONENT32F, 4096, 4096)
            .minFilter(GL_LINEAR)
            .magFilter(GL_LINEAR)
            .compareMode(GL_COMPARE_REF_TO_TEXTURE)
            .compareFunc(GL_LEQUAL);
    depthFBO.texture2D(GL_DEPTH_ATTACHMENT, GL11.GL_TEXTURE_2D, depthTexture, 0)
            .checkStatus().unbind();
    depthTexture.unbind();

渲染:

    depthFBO.bind();
    glViewport(0, 0, 4096, 4096);
    glEnable(GL_POLYGON_OFFSET_FILL);
    glPolygonOffset(4.0f, 4.0f);
    glDrawBuffer(GL_NONE);
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClearDepthf(1f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    Drawable.drawAllLightPass(drawables, lightNormalProgram, lightTessellationProgram);
    glDisable(GL_POLYGON_OFFSET_FILL);
    depthFBO.unbind();

直接gl* 调用中的代码。

初始化:

int frameBufferObjectId = GL30.glGenFramebuffers();
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, frameBufferObjectId);

int textureId = GL11.glGenTextures();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureId);
GL42.glTexStorage2D(GL11.GL_TEXTURE_2D, 12, GL_DEPTH_COMPONENT32F, 4096, 4096);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL_LINEAR);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL_LINEAR);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL14.GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL14.GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);

GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL11.GL_TEXTURE_2D, textureId, 0);
if (GL30.glCheckFramebufferStatus(GL30.GL_FRAMEBUFFER) != GL30.GL_FRAMEBUFFER_COMPLETE) 
    throw new RuntimeException(this + " is not complete.");

GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, 0);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);

渲染:

GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, frameBufferObjectId);
glViewport(0, 0, 4096, 4096);
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(4.0f, 4.0f);
glDrawBuffer(GL_NONE);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClearDepthf(1f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

//appropiate calls to glDraw* are being done, this is confirmed to work as it works for displaying data

glDisable(GL_POLYGON_OFFSET_FILL);
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, 0);

现在最重要的着色器:

light-normal.vs.glsl

#version 430 core

layout(location = 4) uniform mat4 light_model_matrix;
layout(location = 5) uniform mat4 light_view_matrix;
layout(location = 6) uniform mat4 light_projection_matrix;

layout(location = 0) in vec4 position;

void main(void) 
    gl_Position = light_projection_matrix * light_view_matrix * light_model_matrix * position;

light-normal.fs.glsl

#version 430 core

layout(location = 0) out float depth;

void main(void) 
    depth = gl_FragCoord.z;

甚至将depth 硬编码为0.0f0.5f1.0f 都不起作用。

只是为了澄清我的期望是否正确:当我将相机靠近屏幕上正在渲染的对象时,深度缓冲区的颜色应该改变吗?那么深度会接近0.0f,而远离1.0f?

还有一个说明:我所看到的深度值是一个到处都是白色的矩形。

根据要求,着色器将深度纹理数据可视化:

depth-box.vs.glsl

#version 430 core

void main(void) 
    const vec4 vertices[6] = vec4[](
        vec4(-1.0, -1.0, 1.0, 1.0),
        vec4(-1.0, 1.0, 1.0, 1.0),
        vec4(1.0, 1.0, 1.0, 1.0),

        vec4(1.0, 1.0, 1.0, 1.0),
        vec4(1.0, -1.0, 1.0, 1.0),
        vec4(-1.0, -1.0, 1.0, 1.0)
    ); 

    gl_Position = vertices[gl_VertexID];

depth-box.fs.glsl

#version 430 core

layout(location = 7) uniform int screen_width;
layout(location = 8) uniform int screen_height;

layout(binding = 0) uniform sampler2D shadow_tex;

out vec4 color;

void main(void) 
    vec2 tex_coords = vec2(
        (gl_FragCoord.x - 100) / (screen_width / 5),
        (gl_FragCoord.y - (screen_height - (screen_height / 5) - 100)) / (screen_height / 5)
    );
    color = vec4(vec3(texture(shadow_tex, tex_coords).r), 1.0);

【问题讨论】:

【参考方案1】:

这不起作用,您忘记禁用纹理比较。除了GL_NONE 之外,您不能使用sampler2D 对纹理进行采样。 结果将是不确定的。

sampler2DShadow 是读取启用比较的纹理所必需的。当你这样做时,前两个纹理坐标正常工作,但第三个是要比较的深度值,texture (...) 的返回是一个浮点值(1.0 表示通过,0.0 表示失败)。如果你有一个线性过滤器,它可以介于两者之间。

【讨论】:

更新了,可惜还是不行。将sampler2DGL_NONE 一起使用时。 还通过将render 中的glClearDepthf(1f); 更改为例如0.5f 来确认它确实做了一些事情(即变成灰色),所以没有任何东西被绘制到纹理中? 至于在你的着色器中输出depth,那是完全没有意义的。我开始讨厌你得到这些着色器的书。您正在将窗口空间深度写入颜色缓冲区,但您有glDrawBuffers (GL_NONE)。您的着色器甚至不应该有一个名为 depth 的输出,为了您自己的利益将其删除并使用一个空的片段着色器来创建阴影贴图。 如果你真的想在片段着色器中写一些东西来影响深度,你可以写gl_FragDepth。但是,不要这样做除了调试之外,因为光栅器已经生成了这个值,如果你覆盖它,你将失去几个硬件优化。 那么,总结一下,写一个空的着色器更好,这样驱动程序/硬件可以优化,并提供一致性?是的,我也不再那么喜欢这本书了,但是网上的解释更难找到。

以上是关于无法使用深度附件渲染到 FBO的主要内容,如果未能解决你的问题,请参考以下文章

FBO深度纹理附件的最佳设置

GLSL:无法从 FBO 读取纹理并使用片段着色器渲染到另一个 FBO

是否可以将默认渲染缓冲区附加到 FBO?

带有模板缓冲区 FBO 的延迟渲染器

GL_TEXTURE_3D 颜色和模板 FBO 附件

OpenGL(FBO)中的普通后台缓冲区+渲染到深度纹理