Android 如何在 OpenGL ES 中渲染深度纹理

How to render to a depth texture in OpenGL ES on Android

我需要渲染到 Android 中的深度纹理,但我无法弄清楚。我在网上搜索了几天,拼凑了以下代码:

  public void loadFrameBuffer(Context context, int resourceId) {
    final Bitmap bitmap = createBitmap(context, resourceId);

    // generate the framebuffer and texture object names
    glGenFramebuffers(1, frameBuffers, 0);
    glGenTextures(2, textures, 0);

    // bind color texture and load the texture mip level 0 texels are RGB565
    // no texels need to specified as we are going to draw into the texture
    glBindTexture(GL_TEXTURE_2D, textures[COLOR_TEXTURE]);
    texImage2D(GL_TEXTURE_2D, 0, GL_RGB, bitmap, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    // bind depth texture and load the texture mip level 0
    // no texels need to specified as we are going to draw into
    // the texture
    glBindTexture(GL_TEXTURE_2D, textures[DEPTH_TEXTURE]);
    texImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, bitmap, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

    // bind the framebuffer
    glBindFramebuffer(GL_FRAMEBUFFER, frameBuffers[0]);

    // specify texture as color attachment
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
      GL_TEXTURE_2D, textures[COLOR_TEXTURE],
      0);

    checkStatus();

    // specify texture as depth attachment
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
      GL_TEXTURE_2D, textures[DEPTH_TEXTURE],
      0);

    checkStatus();
  }

颜色附件的 checkStatus() 成功:GL_FRAMEBUFFER_COMPLETE 但是深度附件的 checkStatus() 是:GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT

错误状态的文档:

Not all framebuffer attachment points are framebuffer attachment complete. This means that at least one attachment point with a renderbuffer or texture attached has its attached object no longer in existence or has an attached image with a width or height of zero, or the color attachment point has a non-color-renderable image attached, or the depth attachment point has a non-depth-renderable image attached, or the stencil attachment point has a non-stencil-renderable image attached.

Color-renderable formats include GL_RGBA4, GL_RGB5_A1, and GL_RGB565. GL_DEPTH_COMPONENT16 is the only depth-renderable format. GL_STENCIL_INDEX8 is the only stencil-renderable format.

我很茫然,即使有了这个关于问题所在的描述。颜色附件效果很好。

编辑:

我在前面提到的状态错误之前的日志中看到了这一点:

<core_glTexImage2D:501>: GL_INVALID_OPERATION

看来是因为这行代码:

texImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, bitmap, 0);

编辑:

我克服了错误。我从通话切换到:

texImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, bitmap, 0);

这实际上是错误的,现在我打电话给:

glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, texWidth, texHeight, 0, GL_DEPTH_COMPONENT, GLES30.GL_FLOAT, null);

有效。我没有看到更多的错误。但是,我仍然遇到问题。

这是直接渲染到默认缓冲区的模型(直接渲染到 window):

但是当我尝试渲染附加到我的 FrameBuffer 的纹理映射到以下内容时:

// x, y, z, S, T
      new float[]{
        // left triangle
        -1f, -1f, 0f, 0f, 0f, //
        1f, 1f, 0f, 1f, 1f, //
        -1f, 1f, 0f, 0f, 1f, //

        // right triangle
        -1f, -1f, 0f, 0f, 0f, //
        1f, -1f, 0f, 1f, 0f, //
        1f, 1f, 0f, 1f, 1f //
      }
    );

拉伸纹理:

如果我删除左边的三角形并进行渲染,我会得到:

最后,渲染深度纹理给了我所有的红色:

一切正常,无需修复

你的深度纹理是正确的。没有什么可以解决的了。

问题似乎是您期望对比度更高的东西。我下载了你的照片并在图像编辑器中增强了对比度:

你可以看到里面有细节!但是,这里丢失了大量数据。你的屏幕可能最多有一个 8 位帧缓冲区,然后我将结果下载为 JPEG 格式,进一步量化它,但是......原始深度纹理本身可能是 16 位。所以我猜想当我制作上面的图像时我们可能已经丢失了 ~10 位。

换句话说,深度缓冲区有16位精度,但屏幕只有8位。所以,你当然看不到细节。数据没问题

为什么是红色的?

当然是红色的。这是一张只有一个通道的图像。如果您想为其着色不同,请使用纹理调配,或在片段着色器中应用颜色。