Android OpenGL:如何更改附加到纹理的位图?

4
我已经创建了这样的一种纹理。
public int createTexture(Bitmap bitmap){
 final int[] textureHandle = new int[1];
 GLES20.glGenTextures(1, textureHandle, 0);
 glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);       
 glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
 glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
 // Load the bitmap into the bound texture.
 GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); 
 return textureHandle[0];
}

现在根据用户输入,我想用新的位图更新我的纹理。我尝试使用不同的位图重新调用相同的函数,但它没有被更新。我在这里做错了什么吗? 编辑 我按照Tommy在他的答案中所说的方法尝试过了,但没有用。让我详细说明一下我如何使用纹理。
public void changeFilter(){
  //create required bitmap here
  if(mTextureDataHandle1==0) 
    mTextureDataHandle1 =loadTexture(bitmap); 
  else 
      updateTexture(mTextureDataHandle1);
}

onDrawFrame
 glActiveTexture(GL_TEXTURE1);
 glBindTexture(GL_TEXTURE_2D, mTextureDataHandle1);
 glUniform1i(mTextureUniformHandle1, 1);

2
当您更新纹理时,您从哪个线程进行这些调用?您必须从渲染线程中进行所有OpenGL调用。 - Reto Koradi
@RetoKoradi 我正在从渲染线程中执行它。 - Praveena
1
@RetoKoradi 您是正确的。它正在从GL线程中调用。您有想法为什么简单地调用updateTexture会脱离GL线程吗? - Praveena
3个回答

4

这个方法既创建了一个新的纹理,同时也将一个Bitmap上传到了它上面。听起来你只想做第二件事情而不是第一件?如果是这样,那么提供int纹理名称作为参数,而不是将其作为结果接收,并直接跳转到glBindTexture(即省略glGenTextures,这是创建新纹理的步骤)。

例如:

public int createTexture(Bitmap bitmap){
 final int[] textureHandle = new int[1];
 GLES20.glGenTextures(1, textureHandle, 0);
 glBindTexture(GLES20.GL_TEXTURE_2D, textureName);       
 glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
 glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
 updateTexture(textureHandle[0], bitmap);
 return textureHandle[0];
}

public void updateTexture(int textureName, Bitmap bitmap) {
 glBindTexture(GLES20.GL_TEXTURE_2D, textureName);       
 // Load the bitmap into the bound texture.
 GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); 
}

因此,上传Bitmap的部分已从创建纹理并设置其过滤类型的部分分离出来;要更新现有纹理,请使用之前获取的int,并直接调用updateTexture


我按照你说的尝试了。如果纹理的id不等于0,我跳过了'glGenTextures',但是没有用。我希望这就是你所说的。如果我有误,请纠正我。 - Praveena
等一下,我大约15分钟后会到电脑面前——然后我会尝试添加一些示例代码。从手机上完成这个任务太困难了。 - Tommy
谢谢你的代码。我尝试了同样的方法,但它返回相同的纹理。这是我调用这些方法的方式: if(mTextureDataHandle1==0) mTextureDataHandle1 =loadTexture(bitmap); else updateTexture(mTextureDataHandle1); - Praveena
好的。第二个“Bitmap”作为纹理肯定是可接受的吗?如果检查“glGetError”,会发生什么?非2次幂纹理的普遍支持缺乏曾经在我从iOS移植某些东西时困扰过我(在那里只有一个GPU系列,因此有时会忘记您没有按规范编写)。 - Tommy
我认为这不是问题,因为每次我都使用相同大小的“Bitmap”,而且为了更清晰地阐述我的问题,我更新了我的问题。请在有空的时候检查一下。 - Praveena
4
我刚遇到了一个问题,updateTexture 方法被从不同的线程调用。我使用了 GLSurfaceView.queueEvent 方法来解决它。但是我不知道为什么单独调用 updateTexture 会脱离 GL 线程。如果你有任何想法,请告诉我。非常感谢你的回答。 - Praveena

2

当你改变Bitmap时,可能不在OpenGL渲染线程中。当你改变Bitmap时,保存一个布尔值,表示已经这么做了,然后只有在渲染线程中才调用texImage2D。


2
我尝试了上述回复中的技术,但表现很差。如果您想要像60 fps那样实时更新纹理,则有更好的方法。顺便说一句,我没有找到相关文档,不得不从不同的来源中拼凑出来。

(1)您必须告诉OpenGL扩展使用外部纹理。也就是说,在定义纹理时,您不能使用GLES20.GL_TEXTURE0,而是要使用GLES11Ext.GL_TEXTURE_EXTERNAL_OES

(2)您必须使用Surface和SurfaceTexture类。(查看消费者和生产者以获取更多信息。它们的工作原理类似于服务器/客户端,但架构被称为消费者/生产者)

(3)您必须在片段着色器上启用一个扩展。您不能使用sampler2D,而必须使用samplerExternalOES。要启用扩展,您需要在着色器代码的顶部放置以下行:

#extension GL_OES_EGL_image_external: require

代码快照

以上是我的代码快照,下面是片段着色器。

片段着色器


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接