【问题标题】:Only one texture gets rendered on my FrameBuffer我的 FrameBuffer 上只渲染了一个纹理
【发布时间】:2014-10-22 19:07:45
【问题描述】:

我正在尝试使用 SpriteBatch 和 FrameBuffer 渲染三张图像。

这些是我正在做的步骤。

  1. 清除屏幕、深度和模板缓冲区。
  2. 绑定帧缓冲区。请参阅 FrameBuffer.bind()。
  3. 使用我的 SpriteBatch 渲染三个具有不同大小和不同位置的实体四边形。
  4. 解绑我的 FrameBuffer。请参阅 FrameBuffer.unbind()。
  5. 绑定我的 FrameBuffers colorTexture。
  6. 用我的 SpriteBatch 渲染我的 FrameBuffer。

这是我知道的关于这个问题的一些事实

  • 纹理显示正确的颜色。他们不是白人。
  • 显示了我渲染的第一个纹理,而其他两个没有。如果我更改顺序,仍然会渲染第一个纹理。
  • 对于三个纹理,我的意思是三个独立的纹理 ID。
  • 我已启用深度测试。
  • 没有抛出 OpenGL 错误或 FrameBuffer 错误。
  • 当使用我的 SpriteBatch 直接渲染到屏幕时,所有三个四边形都会显示出来。
  • 我的 FrameBuffer 大小就是我的屏幕大小。

它应该是这样的

这是我的帧缓冲区的外观。

这是使用我的帧缓冲区并绘制第一个纹理两次的情况。仍然缺少其他两个纹理。定位不是问题。

这是我的 FrameBuffer 的代码:

// Stencil is broken currently broken, in my example. I'm not using any stencil buffers.
public FrameBuffer(int width, int height, boolean hasDepth, boolean hasStencil) {
    this.width = width;
    this.height = height;
    frameBufferID = GL30.glGenFramebuffers();
    GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, frameBufferID);

    if (hasDepth && hasStencil) {
        int depthAndStencilBufferID = GL30.glGenRenderbuffers();

        GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, depthAndStencilBufferID);
        GL30.glRenderbufferStorage(GL30.GL_RENDERBUFFER, GL30.GL_DEPTH24_STENCIL8, width, height);
        GL30.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_STENCIL_ATTACHMENT, GL30.GL_RENDERBUFFER, depthAndStencilBufferID);
    }

    else if (hasDepth) {
        int depthBufferID = GL30.glGenRenderbuffers();

        GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, depthBufferID);
        GL30.glRenderbufferStorage(GL30.GL_RENDERBUFFER, GL30.GL_DEPTH_COMPONENT32F, width, height);
        GL30.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_ATTACHMENT, GL30.GL_RENDERBUFFER, depthBufferID);
    }

    else if (hasStencil) {
        int stencilBufferID = GL30.glGenRenderbuffers();
        GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, stencilBufferID);
        GL30.glRenderbufferStorage(GL30.GL_RENDERBUFFER, GL30.GL_STENCIL_INDEX16, width, height);
        GL30.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_STENCIL_ATTACHMENT, GL30.GL_RENDERBUFFER, stencilBufferID);
    }

    colorTexture = new Texture(width, height);
    colorTexture.bind();

    GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0, GL11.GL_TEXTURE_2D, colorTexture.getTextureID(), 0);
    int result = GL30.glCheckFramebufferStatus(GL30.GL_FRAMEBUFFER);
    //error handling
    RenderUtil.unbindFrameBuffer();
}

private Texture colorTexture;

private int width, height;

private int frameBufferID, depthBufferID, stencilBufferID;

public void begin () {
    GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, frameBufferID);
    GL11.glViewport(0, 0, width, height);
}

public void end () {
    GL11.glViewport(0, 0, RenderingEngine.getWidth(), RenderingEngine.getHeight());
    RenderUtil.unbindFrameBuffer();
    RenderUtil.unbindTextures();
}

public Texture getColorTexture () {
    return colorTexture;
}

public int getWidth () {
    return width;
}

public int getHeight () {
    return height;
}

下面是我创建纹理的方法:

private void loadTexture (ByteBuffer buffer, int textureID, int width, int height) {
    GL13.glActiveTexture(GL13.GL_TEXTURE0);
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID);

    GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);

    GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, width, width, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer);

    GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);

    GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);

    GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR_MIPMAP_LINEAR);
}

切换纹理时,我的 SpriteBatch 似乎有问题。以下是切换的工作原理。 我提醒你,使用我的 SpriteBatch 渲染到屏幕可以得到我想要的结果。但是渲染到 FrameBuffer 不起作用。

`

public void flush () {

    flushes++;
    buffer.flip();
    MESH.setVertices(buffer);

    if (lastTexture != null) {
        lastTexture.bind();
    }

    MESH.draw();

    buffer.clear();
}

/** Begins the SpriteBatch. */
public void begin () {
    if (rendering) {
        new IllegalStateException("You have to SpriteBatch.end() before calling begin again!").printStackTrace();
    }
    flushes = 0;
    rendering = true;
    shader.bind();
    shader.setUniformMat4f("projection", camera.getCombined());
    shader.setUniformVec4("color", color);
}

/** Ends the SpriteBatch, also flushes it. */
public void end () {
    if (!rendering) {
        new IllegalStateException("You've to SpriteBatch.begin before ending the spritebatch").printStackTrace();
    }
    rendering = false;
    flush();
    RenderUtil.unbindShaders();
    RenderUtil.unbindTextures();
}

/** Switches the textures and flushes the old one.
 * @param t */
private void switchTextures (Texture t) {
    if (lastTexture != null) {
        flush();
    }
    lastTexture = t;
}

` 将创建一个小示例。应该快起来了。

编辑: 问题不是我的 FrameBuffer。是我的 SpriteBatch。

【问题讨论】:

  • 快速浏览一下您的代码,我注意到一个错误......当hasStencil hasDepth 都为真时会发生什么?您尝试将附件绑定到 DEPTH 和 STENCIL,但这在大多数情况下会导致兼容性问题。在这种特殊情况下,您应该添加第三种情况,将打包的深度+模板附件绑定到 GL_DEPTH_STENCIL_ATTACHMENT。这里更大的问题是您使用 16 位模板缓冲区,当您也有深度缓冲区时,这几乎永远不会起作用:-\
  • 是的,您可以为渲染缓冲区使用深度+模板图像格式。在这种情况下,您使用的是 32 位浮点深度缓冲区,因此您想要的格式是 GL_DEPTH32F_STENCIL8​。这实际上是一种特别讨厌的格式,硬件不喜欢 40 位数据,所以实际发生的情况是您浪费了额外的 24 位数据,因此打包的深度+模板被填充为 64 位。老实说,我建议您尝试使用 24 位深度缓冲区,因为这样您就可以使用 GL_DEPTH24_STENCIL8 而不会浪费任何内存/带宽。
  • 不小心删除了我的问题。这里是为 Andon 的回答提供一些背景信息:我只需要创建一个渲染缓冲区吗?
  • @AndonM.Coleman 我更新了代码,depth+stencil 的创建效果如何?
  • 最后一件事:你能显示你实际清除缓冲区的代码吗?我期待在函数begin (...) 中看到它,但它不存在。您需要在绑定 FBO 时清除缓冲区,否则您只会清除与窗口关联的颜色/模板/深度缓冲区。

标签: opengl lwjgl framebuffer


【解决方案1】:

您需要在绑定 FBO 时清除缓冲区,否则您只会清除与窗口关联的颜色/模板/深度缓冲区。这不是您想要的行为,因为这种情况下的深度测试使用您的 FBO 的深度而不是窗口的(默认帧缓冲区)。

public void begin () 是这样做最合乎逻辑的地方:

public void begin () {
    GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, frameBufferID);
    GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_STENCIL_BUFFER_BIT);
    GL11.glViewport(0, 0, width, height);
}

【讨论】:

  • 没有改变任何东西。
  • 切换贴图好像有问题。
  • 这是我没有做的事情。但还是。这不是答案。
  • @theodor:您显示的代码没有任何其他直接问题,但我认为问题与您的纹理绑定有关。除了应用纹理,您可以尝试为每个四边形分配不同的常量颜色(使用“颜色”制服)吗?这将排除这是纹理问题还是其他问题。
  • 我很确定这是纹理绑定。我可以多次绘制相同的纹理,并且它们都被渲染,如您在第三张图像中看到的那样。我将尝试使用 glReadPixels 来查看它是否有效。 glReadPixels 和 glFramebufferTexture2D 有性能差异吗?。
猜你喜欢
  • 2014-07-22
  • 1970-01-01
  • 1970-01-01
  • 2021-01-03
  • 1970-01-01
  • 2012-05-16
  • 1970-01-01
  • 2019-08-31
  • 1970-01-01
相关资源
最近更新 更多