OpenGL ES 无法使 LUMINANCE FBO 在 Android 中工作
Posted
技术标签:
【中文标题】OpenGL ES 无法使 LUMINANCE FBO 在 Android 中工作【英文标题】:OpenGL ES can't make LUMINANCE FBO work in Android 【发布时间】:2013-02-05 22:37:26 【问题描述】:我正在使用帧缓冲区在视频渲染器上进行一些后期处理着色器。其中一个着色器的查找非常密集,因此我想更改为仅亮度的帧缓冲区以加快速度。我尝试在初始化时将 glTexImage2D 调用从 RGBA 更改为 LUMINANCE,但是当我尝试在“onDrawFrame”中附加缓冲区时出现错误。
问题是我已经从示例中破解了代码并且不太了解它所做的一切。一方面,我还创建了一个深度附件,因为我正在渲染视频,所以我不需要任何深度信息,但我不知道我是否可以禁用它。无论如何,这是我在 onSurfaceCreated 中对 FBO 的初始化:
GLES20.glGenTextures(1, renTex, 0);
// generate
GLES20.glGenFramebuffers(1, fb2, 0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE4);
// generate color texture
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, renTex[0]);
// parameters
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
// create it
// create an empty intbuffer first?
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, texW, texH, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, texBuffer);
//**THIS WORKS AS IS, CHANGING FROM RGBA TO LUMINANCE BREAKS IT**
// create render buffer and bind 16-bit depth buffer
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, depthRb[0]);
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16, texW, texH);
这是在 onDrawFrame 中附加缓冲区的代码:
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fb[0]);
// specify texture as color attachment
GLES20.glViewport(0, 0, w, h);
Matrix.frustumM(mProjMatrix, 0, -.30f, .30f, -.30f, .30f, 3, 7);
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, renTex[0], 0);
// attach render buffer as depth buffer
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER, depthRb[0]);
int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
if (status != GLES20.GL_FRAMEBUFFER_COMPLETE)
System.out.println("Frame buffer not obtained :(");
//This works for RGBA but returns an error for LUMINANCE
有人有什么建议吗?我也可以放弃深度缓冲区组件还是必须的
【问题讨论】:
你试过用 GL_DEPTH_COMPONENT 代替亮度吗? @BlueVoodoo 我会试试这个。我猜你的意思是根本不需要绑定颜色纹理,我会尝试弄清楚如何写入深度组件。 您可能仍然需要颜色纹理。我只是指 glTexImage2D() 方法。 不幸的是,使用 GL_DEPTH_COMPONENT 与 GL_LUMINANCE 或 GL_LUMINANCE_ALPHA 具有相同的效果,帧缓冲区不起作用。只有 GL_RGBA 和 GL_RGB 似乎有效。我可以在 RGB 和 RGBA 之间切换的事实让我认为我的代码可能是正确的,我怀疑存在硬件限制(我使用的是 Mali 400 GPU 的 AML8726-MX。)顺便说一句,我确实通过删除深度缓冲区显着加快了速度,但我仍然认为我的着色器最终读取的数据是所需数据的 4 倍。 【参考方案1】:GL_LUMINANCE 不是可呈现颜色的格式。来自OpenGL ES 2.0 specification 第 4.4.5 节:
表 4.5 中未列出的格式,包括压缩的内部格式。不是 颜色、深度或模板可渲染,无论它们包含哪些组件。
表中列出的可呈现颜色的格式为:RGBA4、RGB5_A1 和 RGB565。
即使 RGB8 和 RGBA8 也未在表中列出,但由于您可以使用 RGBA8,您的设备可能支持 OES_rgb8_rgba8 和/或 ARM_rgba8 扩展。
【讨论】:
【参考方案2】:使用两个纹理作为帧缓冲目标,一个具有 GL_RED_EXT 格式的 Y 平面,另一个具有 GL_RG_EXT 的 UV 平面。第二个纹理将具有第一个的一半尺寸,因此您不能一次将它们分配给不同的 COLOR_ATTACHMENTS,并且需要使用不同的视口进行两次渲染。
#include "gl2ext.h"
...
glGenTextures(1, &mYTextureId);
glBindTexture(GL_TEXTURE_2D, mYTextureId);
...
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED_EXT, mCameraFrameWidth, mCameraFrameHeight, 0, GL_RED_EXT, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mYTextureId, 0);
glViewport(0, 0, mCameraFrameWidth, mCameraFrameHeight);
...
glGenTextures(1, &mUVTextureId);
glBindTexture(GL_TEXTURE_2D, mUVTextureId);
...
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG_EXT, mCameraFrameWidth/2, mCameraFrameHeight/2, 0, GL_RG_EXT, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mUVTextureId, 0);
glViewport(0, 0, mCameraFrameWidth/2, mCameraFrameHeight/2);
...
这适用于大多数带有 arm7+ 的 iPhone 和 android 手机
【讨论】:
以上是关于OpenGL ES 无法使 LUMINANCE FBO 在 Android 中工作的主要内容,如果未能解决你的问题,请参考以下文章