我尝试重用Android Media Effects samples并希望能够使用相机或画廊选择的新位图更改纹理数据。目前还没有解决办法
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 x 1080
如何用新位图更改/修改/替换纹理数据?
更新:
我认为这个问题与这个问题更相关:Setting texture on 3D object using image from photo gallery 。我从图库 Intent 中抓取图像后调用changeBackground(),然后裁剪它(另一个 Intent )。
现在,如何从图库 Intent 中有效地使用位图更改纹理数据?有人知道吗?
已解决
我通过将纹理加载过程推迟到 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);
}
}
到目前为止,它有效。
最佳答案
看起来您的 changeBackground()
方法可能是从 UI 线程调用的,或者至少是从渲染线程以外的线程调用的。
GLSurfaceView
创建一个单独的渲染线程,当调用渲染方法时,该线程具有当前的 OpenGL 上下文。因此它已准备好供您的 OpenGL 调用。所有其他线程的情况并非如此。当前 OpenGL 上下文是每个线程。因此,除非您对此采取措施(这是可能的,但会显着增加复杂性),否则您无法从其他线程进行 OpenGL 调用。
有几个选项可以解决这个问题。最简单的方法可能是使用 GLSurfaceView 上的queueEvent() 方法,该方法允许您传入将在渲染线程。
我不确定代码中的 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();
关于java - Android:如何从图库/相机更改 OpenGLES 纹理数据/位图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30952459/