Android OpenGL ES 2.0 - glReadPixels() 和 glTexImage2D() 绘制黑色纹理?

发布于 2024-12-02 00:18:09 字数 2248 浏览 1 评论 0原文

我正在编写一些 Android 代码,用于在 EGL 上下文丢失和重新创建之间缓存和重绘帧缓冲区对象的颜色缓冲区。开发主要在运行 Honeycomb 的 Xoom 平板电脑上进行。不管怎样,我想做的是将 FBO 上调用 glReadPixels() 的结果存储在直接 ByteBuffer 中,然后将该缓冲区与 glTexImage2D() 一起使用,并将其绘制回(现已清除)帧缓冲区中。所有这些似乎都工作正常 - ByteBuffer 包含正确的值(根据 Java 无法理解无符号字节的说法,对于像素来说,[-1, 0, 0, -1] 等),似乎没有抛出任何 GlErrors,并且四边形被绘制到屏幕的右侧部分(当前出于测试目的,位于帧缓冲区的左上四分之一)。

然而,无论我尝试什么,glTexImage2D() 总是输出纯黑色纹理。我之前遇到过一些问题 - 在显示位图时,我最终放弃了尝试将基本的 GLES20.glTexImage2D() 与缓冲区一起使用,并跳到使用 GLUtils.glTexImage2D(),它会为您处理位图。不幸的是,这里不是一个选项(我实际上尝试将 ByteBuffer 转换为位图,以便我可以使用 GLUtils,但没有取得太大成功),所以我真的没有想法了。

谁能想到任何可能导致 glTexImage2D() 无法正确处理完美的 ByteBuffer 的原因吗?任何和所有建议都将受到欢迎。

ByteBuffer pixelBuffer;

void storePixels() {
  try {
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbuf);
    pixelBuffer = ByteBuffer.allocateDirect(width * height * 4).order(ByteOrder.nativeOrder());
    GLES20.glReadPixels(0, 0, width, height, GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE, pixelBuffer);
    GLES20.glBindFrameBuffer(GLES20.GL_FRAMEBUFFER, 0);
    gfx.checkGlError("store Pixels");
  }catch (OutOfMemoryError e) {
    pixelBuffer = null;
  }
}

void redrawPixels() {
  GLES20.glBindFramebuffer(GL20.GL_FRAMEBUFFER, fbuf);
  int[] texId = new int[1];
  GLES20.glGenTextures(1, texId, 0);
  int bufferTex = texId[0];
  GLES20.glBindTexture(GL20.GL_TEXTURE_2D, bufferTex);
  GLES20.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MAG_FILTER, GL20.GL_LINEAR);
  GLES20.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MIN_FILTER, GL20.GL_LINEAR);
  GLES20.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_WRAP_S, repeatX ? GL20.GL_REPEAT
    : GL20.GL_CLAMP_TO_EDGE);
  GLES20.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_WRAP_T, repeatY ? GL20.GL_REPEAT
    : GL20.GL_CLAMP_TO_EDGE);
  GLES20.glTexImage2D(GL20.GL_TEXTURE_2D, 0, GL20.GL_RGBA, width, height, 0, GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE, pixelBuffer);
  gfx.drawTexture(bufferTex, width, height, Transform.IDENTITY, width/2, height/2, false, false, 1);
  GLES20.glDeleteTextures(1, IntBuffer.wrap(new int[] {bufferTex}));
  pixelBuffer = null;
  GLES20.glBindFrameBuffer(GLES20.GL_FRAMEBUFFER, 0);
}

顺便说一句,gfx.drawTexture() 构建一个四边形并将其绘制到当前绑定的帧缓冲区。该代码已经在我的项目的其他部分经过了充分的测试 - 它不应该成为这里的问题。

I'm working on some Android code for caching and redrawing a framebuffer object's color buffer between the loss and recreation of EGL contexts. Development is primarily happening on a Xoom tablet running Honeycomb. Anyway, what I'm trying to do is store the result of calling glReadPixels() on the FBO in a direct ByteBuffer, then use that buffer with glTexImage2D() and draw it back into the (now cleared) framebuffer. All of this seems to work fine — the ByteBuffer contains the right values ([-1, 0, 0, -1] etc. for a pixel, according to Java's inability to understand unsigned bytes), no GlErrors seem to be thrown, and the quad is drawn to the right part of the screen (currently the top-left quarter of the framebuffer for testing purposes).

However, no matter what I try, glTexImage2D() always outputs a plain black texture. I've had some issues with this before — when displaying Bitmaps, I eventually gave up trying to use the basic GLES20.glTexImage2D() with Buffers and skipped to using GLUtils.glTexImage2D(), which processes the Bitmap for you. Unfortunately, that's less of an option here (I did actually try converting the ByteBuffer to a Bitmap so I could use GLUtils, without much success), so I've really run out of ideas.

Can anyone think of anything that could be causing glTexImage2D() to not correctly process a perfectly good ByteBuffer? Any and all suggestions would be welcome.

ByteBuffer pixelBuffer;

void storePixels() {
  try {
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbuf);
    pixelBuffer = ByteBuffer.allocateDirect(width * height * 4).order(ByteOrder.nativeOrder());
    GLES20.glReadPixels(0, 0, width, height, GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE, pixelBuffer);
    GLES20.glBindFrameBuffer(GLES20.GL_FRAMEBUFFER, 0);
    gfx.checkGlError("store Pixels");
  }catch (OutOfMemoryError e) {
    pixelBuffer = null;
  }
}

void redrawPixels() {
  GLES20.glBindFramebuffer(GL20.GL_FRAMEBUFFER, fbuf);
  int[] texId = new int[1];
  GLES20.glGenTextures(1, texId, 0);
  int bufferTex = texId[0];
  GLES20.glBindTexture(GL20.GL_TEXTURE_2D, bufferTex);
  GLES20.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MAG_FILTER, GL20.GL_LINEAR);
  GLES20.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MIN_FILTER, GL20.GL_LINEAR);
  GLES20.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_WRAP_S, repeatX ? GL20.GL_REPEAT
    : GL20.GL_CLAMP_TO_EDGE);
  GLES20.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_WRAP_T, repeatY ? GL20.GL_REPEAT
    : GL20.GL_CLAMP_TO_EDGE);
  GLES20.glTexImage2D(GL20.GL_TEXTURE_2D, 0, GL20.GL_RGBA, width, height, 0, GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE, pixelBuffer);
  gfx.drawTexture(bufferTex, width, height, Transform.IDENTITY, width/2, height/2, false, false, 1);
  GLES20.glDeleteTextures(1, IntBuffer.wrap(new int[] {bufferTex}));
  pixelBuffer = null;
  GLES20.glBindFrameBuffer(GLES20.GL_FRAMEBUFFER, 0);
}

gfx.drawTexture() builds a quad and draws it to the currently bound framebuffer, by the way. That code has been well-tested in other parts of my project — it shouldn't be the issue here.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

乖乖兔^ω^ 2024-12-09 00:18:09

对于那些在家玩的人来说,这个代码实际上是完全有效的。还记得我当时发誓 gfx.drawTexture() 已经经过充分测试,不应该是这里的问题吗?是的,这完全是那里的问题。我正在缓冲要绘制的顶点,但实际上并没有通过 glDrawElements() 调用刷新它们。

For those of you playing along at home, this code is in fact totally valid. Remember when I swore blind that gfx.drawTexture() has been well-tested and shouldn't be the issue here"? Yeah, it was totally the issue there. I was buffering vertices to draw without actually flushing them through a glDrawElements() call. Whoops.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文