OpenGL - 为什么我的fbo/纹理仍然是黑色的?

4
我一直在尝试使用OpenGL的帧缓冲和Java的LWJGL库来实现可渲染纹理功能。然而,我总是得到一个100%黑色的纹理。我只是想知道问题出在哪里。我没有渲染任何特定的形状。我绑定生成的帧缓冲并调用glClearColor(1,0,0,1),然后调用glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT),最后解绑帧缓冲。但是当我尝试渲染绑定到帧缓冲的纹理时,纹理只显示成了黑色,但实际上应该是红色,对吗?此外,glCheckFramebufferStatus()返回GL_FRAMEBUFFER_COMPLETE,所以我认为错误应该出现在渲染部分,而不是初始化阶段。但是我还是会展示初始化代码。
public RenderableTexture initialize(int width, int height, int internalFormat, int[] attachments, boolean useDepthBuffer) {
    if(!GLContext.getCapabilities().GL_EXT_framebuffer_object) {
        System.err.println("FrameBuffers not supported on your graphics card!");
    }

    this.width = width;
    this.height = height;
    hasDepthBuffer = useDepthBuffer;

    fbo = glGenFramebuffers();
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);

    id = glGenTextures();
    glBindTexture(GL_TEXTURE_2D, id);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

    glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (ByteBuffer) null);


    if(useDepthBuffer) {
        rbo = glGenRenderbuffers();
        glBindRenderbuffer(GL_RENDERBUFFER, rbo);
        glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo);
    }

    glFramebufferTexture2D(GL_FRAMEBUFFER, attachments[0], GL_TEXTURE_2D, id, 0);

    int[] drawBuffers = new int[attachments.length];

    for(int i = 0; i < attachments.length; i++)
        if(attachments[i] == GL_DEPTH_ATTACHMENT)
            drawBuffers[i] = GL_NONE;
        else
            drawBuffers[i] = attachments[i];

    glDrawBuffers(Util.toIntBuffer(drawBuffers));

    if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        System.err.println("Warning! Incomplete Framebuffer");
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    return this;
}

internalFormat的值为GL_RGBA8widthheight的值为512和512。 attachments[]仅包含1个值,即GL_COLOR_ATTACHMENT0useDepthBuffer设置为true

以上代码仅被调用一次。

这是渲染代码:

public RenderManager draw() {
    glClearColor(bg.x, bg.y, bg.z, bg.w);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    texture.bindAsRenderTarget(true);
    texture.releaseRenderTarget();
    quad.draw();

    return this;
}

我将清除颜色设置为黑色(0, 0, 0, 1),然后清除屏幕。接着调用texture.bindAsRenderTarget(true);方法。其中texture对象包含了上面提到的initialize方法,因此这两个方法之间共享一些变量。

该方法如下所示:

public RenderableTexture bindAsRenderTarget(boolean clear) {
    glViewport(0, 0, width, height);
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
    glClearColor(1, 0, 0, 1f);
    if(clear)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    return this;
}

正如你所看到的,我调整了视口大小以适应纹理/帧缓冲区的大小。然后,我绑定了帧缓冲区并将清除颜色设置为红色。然后,由于在渲染代码中传递了true,它(我相信)会将当前绑定的帧缓冲区清除为红色。 texture.releaseRenderTarget();调整视口以适应显示器,并调用glBindFramebuffer(GL_FRAMEBUFFER,0); 最后一行代码quad.draw();仅仅绑定了绑定到帧缓冲区的纹理ID,然后用它绘制一个简单的四边形。
基本上就是这样了。
我可以向你保证,我正在正确地渲染四边形,因为我可以将从PNG文件加载的纹理绑定到它上面,纹理能够成功地显示出来。
因此,为了澄清问题,主要问题就是: 天哪,为什么纹理在清除后是黑色的,而不是应该是红色的?我错在哪里? 编辑:我感觉这可能与各种gl对象的边界有关。渲染缓冲区必须在渲染到其帧缓冲区时被绑定吗?不需要吗?有关纹理呢?它们在什么时候应该绑定?

当你完成了对帧缓冲纹理的绘制并解除了帧缓冲绑定,正准备再次渲染到后台缓冲区之前,请尝试使用glDrawBuffer(GL_BACK)。 - Robinson
谢谢你的回答,Robinson :) 不幸的是,这并没有解决问题。问题可能在于 fbo 渲染而不是后台缓冲渲染。 - SporreKing
从你的代码中不清楚问题实际上是渲染到纹理/FBO,还是渲染到默认帧缓冲区。 - derhass
这篇文章的重点是我不太清楚问题出在哪里,但我认为它可能在于渲染到纹理而不是默认帧缓冲区。然而,我在文章中添加了一个主要问题 :) - SporreKing
是的,我的API LWJGL会处理所有这些。正如我所说,我完全能够通过我的管道进行渲染,问题只是我似乎没有将任何数据写入fbo,因为纹理仍然是黑色的。 - SporreKing
显示剩余2条评论
1个回答

1
我做了一件非常愚蠢的事情。我在RenderableTexture.class类中初始化fbo纹理,该类是Texture.class的子类。绑定方法包括textureID应该从Texture类继承,因为我已将id变量声明为protected。然而,我不小心在子类中创建了一个本地的private变量,因此,在生成纹理时将纹理ID保存到本地id变量中,并在绑定时使用来自超类的未初始化id。对于任何试图解决此问题但无法做到的人,我感到抱歉:s

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接