2015-06-20 25 views
2

我尝试重用Android Media Effects samples并希望能够使用来自相机或图库拾取的新位图来更改纹理数据。无解到目前为止Android:如何更改来自图库/相机的OpenGLES纹理数据/位图

这是从样品初始加载质地:https://github.com/googlesamples/android-MediaEffects/blob/master/Application/src/main/java/com/example/android/mediaeffects/MediaEffectsFragment.java

private void loadTextures() { 
     // Generate textures 
     GLES20.glGenTextures(2, mTextures, 0); 

     // Load input bitmap 
     Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.puppy); 
     mImageWidth = bitmap.getWidth(); 
     mImageHeight = bitmap.getHeight(); 
     mTexRenderer.updateTextureSize(mImageWidth, mImageHeight); 

     // Upload to texture 
     GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextures[0]); 
     GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); 

     // Set texture parameters 
     GLToolbox.initTexParams(); 
    } 

,这是我的麻烦功能:

public void changeBackground(Uri bitmapUri) { 

    Log.d(TAG, "changeBackground : " + bitmapUri.getPath()); 

    Bitmap bitmap = BitmapFactory.decodeFile(bitmapUri.getPath()); 
    mImageWidth = bitmap.getWidth(); 
    mImageHeight = bitmap.getHeight(); 
    mTexRenderer.updateTextureSize(mImageWidth, mImageHeight); 

    GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, bitmap); 

    theBackground.requestRender(); //my GLSurfaceView 
    bitmap.recycle(); 
} 

我试了几种方法:

  • 只使用texSubImage2D - >纹理未更新

  • 删除并重新创建新的位图纹理 - >黑色质感

注:位图的尺寸是固定的,在1080×1080

如何改变/修改/更换新的纹理数据位图?

UPDATE:

我认为这个问题更涉及到这样一个问题:Setting texture on 3D object using image from photo gallery。我从gallery意图抓取图像后调用changeBackground(),然后裁剪(另一个意图)。

现在,如何有效地改变从画廊意图位图纹理数据?任何人都有线索?

解决

我通过defering纹理加载过程onSurfaceChange()函数解决了这个问题。只需使用一个标志来指示要加载的文件并onSurfaceChange再次检查该标志。

private Uri mFileToLoad = null; 
 

 
public void changeBackground(Uri bitmapUri) { 
 
    Log.d(TAG, "changeBackground : " + bitmapUri.getPath()); 
 
    mFileToLoad = bitmapUri; 
 
    theBackground.requestRender(); 
 
}

和我onSurfaceChange()

public void onSurfaceChanged(GL10 gl, int width, int height) { 
 
     Log.d(TAG, "onSurfaceChanged w:" + width + " h:" + height); 
 
     if (mFileToLoad!=null) { 
 
      GLES20.glDeleteTextures(mTextures.length, mTextures, 0); 
 
      GLES20.glGenTextures(mTextures.length, mTextures, 0); 
 

 
      Bitmap bitmap = BitmapFactory.decodeFile(mFileToLoad.getPath()); 
 
      mImageWidth = bitmap.getWidth(); 
 
      mImageHeight = bitmap.getHeight(); 
 
      mTexRenderer.updateTextureSize(mImageWidth, mImageHeight); 
 

 
      // Upload to texture 
 
      GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextures[0]); 
 
      GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); 
 

 
      // Set texture parameters 
 
      GLToolbox.initTexParams(); 
 

 
      mFileToLoad = null; 
 
      bitmap.recycle(); 
 
     } 
 

 
     if (mTexRenderer != null) { 
 
      mTexRenderer.updateViewSize(width, height); 
 
     } 
 
    }

到目前为止,它的工作原理。

+0

你有一个以上的质感吗?如果是这样,你需要'glBindTexture'你想编辑的那个。 – immibis

+0

像媒体效果样本,我有两个纹理。一个用于原始位图,另一个用于存储后效应纹理。 试图在texSubImage2D之前调用glBind,并且仍然没有纹理更新 –

回答

1

看起来你的changeBackground()方法可能是从UI线程调用的,或者至少是除了渲染线程之外的一个线程。

GLSurfaceView创建一个单独的渲染线程,当您的渲染方法被调用时,它具有当前的OpenGL上下文。因此它准备好您的OpenGL调用。所有其他线程都不是这种情况。当前的OpenGL上下文是,每个线程。所以除非你做了些什么(这是可能的,但增加了很大的复杂性),你不能从其他线程进行OpenGL调用。

有几个选项可以解决这个问题。最简单的方法可能是在GLSurfaceView上使用queueEvent()方法,该方法允许您传递将在渲染线程中执行的Runnable

我不确定代码中mTexRenderer.updateTextureSize()方法的用途。但通常,如果纹理尺寸发生变化,则必须使用GLUtils.texImage2D()而不是GLUtils.texSubImage2D()来更新纹理。

的代码看起来是这样的(未经测试,所以它可能不是完全一样的类型化工作):

final Bitmap bitmap = BitmapFactory.decodeFile(bitmapUri.getPath()); 

theBackground.queueEvent(new Runnable() { 
    @Override 
    void run() { 
     mImageWidth = bitmap.getWidth(); 
     mImageHeight = bitmap.getHeight(); 
     mTexRenderer.updateTextureSize(mImageWidth, mImageHeight); 

     GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextures[0]); 
     GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); 

     bitmap.recycle(); 
    } 
}); 

theBackground.requestRender(); 
+0

是的,你是对的,但问题仍然存在。搜索后,我发现这个问题可能与图库有关的意图抓住源位图。 –

+0

您是否有透明度问题?到目前为止,我还没有做过很多测试,但是看起来像素像素阵列和GLES20.TexImage2D代替具有适当颜色格式的助手可以很好地显示透明像素,而透明像素图像加载DecodeFile然后GLUtils.TexImage2D帮助器显示像素alpha分量为0时的黑色像素。 –