Android 如何在 OpenGL ES 中有效地将一个纹理分配给另一个纹理
how to assign one texture to another efficiently in OpenGL ES for Android
我想将纹理 1 复制到纹理 2。背景是我生成15个空的纹理id绑定到GLES11Ext.GL_TEXTURE_EXTERNAL_OES
,下面是我的代码:
int[] textures = new int[15];
GLES20.glGenTextures(15, textures, 0);
GlUtil.checkGlError("glGenTextures");
for(int i=0;i<15;i++)
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[i]);
然后我总是将相机预览转移到textures[0]
,我想将纹理从textures[0]
复制到textures[1]
以保持时间戳1的帧内容,并复制纹理从 textures[0]
到 textures[2]
以保持时间戳 2 的帧内容...它看起来像在 GPU 中缓冲一些纹理数据并在将来渲染其中的一些。所以我想知道有没有办法做到这一点?我可以只使用 textures[2]=textures[0]
来复制纹理数据吗?
在 ES 2.0 中没有非常直接的方法来复制纹理数据。最简单的方法可能是使用 glCopyTexImage2D()
。要使用它,您必须创建一个 FBO,并将源纹理附加到它。假设 srcTexId
是源纹理的 ID,而 dstTexId
是目标纹理的 ID:
GLuint fboId = 0;
glGenFramebuffers(1, &fboId);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, srcTexId, 0);
glBindTexture(GL_TEXTURE_2D, dstTexId);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, width, height, 0);
话虽如此,根据您的描述,我不认为这真的是您应该做的,原因如下:
- 我认为如上所示复制纹理数据不适用于您正在使用的外部纹理。
- 复制纹理数据总是很昂贵,听起来完全没有必要解决您的问题。
听起来您想保留 15 张最近的相机图像。为此,您可以简单地跟踪 15 个纹理中的哪一个包含最新图像,并将 15 个纹理 ID 的列表视为循环缓冲区。
假设您最初创建纹理 ID:
int[] textures = new int[15];
GLES20.glGenTextures(15, textures, 0);
int newestIdx = 0;
然后每次收到新帧时,将其写入纹理 ID 列表中的下一个条目,在 15 处循环:
newestIdx = (newestIdx + 1) % 15;
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[newestIdx]);
// Capture new frame into currently bound texture.
然后,每次您想使用第 i
帧时,0 表示最近的帧,1 表示之前的帧,等等,您将其绑定为:
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[(newestIdx + i) % 15]);
所以纹理永远不会被复制。您只需跟踪哪个纹理包含哪个帧,并相应地访问它们。
我想将纹理 1 复制到纹理 2。背景是我生成15个空的纹理id绑定到GLES11Ext.GL_TEXTURE_EXTERNAL_OES
,下面是我的代码:
int[] textures = new int[15];
GLES20.glGenTextures(15, textures, 0);
GlUtil.checkGlError("glGenTextures");
for(int i=0;i<15;i++)
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[i]);
然后我总是将相机预览转移到textures[0]
,我想将纹理从textures[0]
复制到textures[1]
以保持时间戳1的帧内容,并复制纹理从 textures[0]
到 textures[2]
以保持时间戳 2 的帧内容...它看起来像在 GPU 中缓冲一些纹理数据并在将来渲染其中的一些。所以我想知道有没有办法做到这一点?我可以只使用 textures[2]=textures[0]
来复制纹理数据吗?
在 ES 2.0 中没有非常直接的方法来复制纹理数据。最简单的方法可能是使用 glCopyTexImage2D()
。要使用它,您必须创建一个 FBO,并将源纹理附加到它。假设 srcTexId
是源纹理的 ID,而 dstTexId
是目标纹理的 ID:
GLuint fboId = 0;
glGenFramebuffers(1, &fboId);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, srcTexId, 0);
glBindTexture(GL_TEXTURE_2D, dstTexId);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, width, height, 0);
话虽如此,根据您的描述,我不认为这真的是您应该做的,原因如下:
- 我认为如上所示复制纹理数据不适用于您正在使用的外部纹理。
- 复制纹理数据总是很昂贵,听起来完全没有必要解决您的问题。
听起来您想保留 15 张最近的相机图像。为此,您可以简单地跟踪 15 个纹理中的哪一个包含最新图像,并将 15 个纹理 ID 的列表视为循环缓冲区。
假设您最初创建纹理 ID:
int[] textures = new int[15];
GLES20.glGenTextures(15, textures, 0);
int newestIdx = 0;
然后每次收到新帧时,将其写入纹理 ID 列表中的下一个条目,在 15 处循环:
newestIdx = (newestIdx + 1) % 15;
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[newestIdx]);
// Capture new frame into currently bound texture.
然后,每次您想使用第 i
帧时,0 表示最近的帧,1 表示之前的帧,等等,您将其绑定为:
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[(newestIdx + i) % 15]);
所以纹理永远不会被复制。您只需跟踪哪个纹理包含哪个帧,并相应地访问它们。