Android:如何从图库/相机更改 OpenGLES 纹理数据/位图
Android: How to change OpenGLES texture data / bitmap from gallery / camera
我尝试重新使用 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
如何change/modify/replace 使用新位图对数据进行纹理处理?
更新:
我认为这个问题与这个问题更相关:Setting texture on 3D object using image from photo gallery。从画廊意图中获取图像然后裁剪它(另一个意图)后,我调用 changeBackground() 。
现在,如何从图库意图中有效地更改带有位图的纹理数据?有人知道吗?
已解决
我通过将纹理加载过程推迟到 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 上下文是 per thread。所以除非你对此做些什么(这是可能的,但会增加显着的复杂性),否则你不能从其他线程进行 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();
我尝试重新使用 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
如何change/modify/replace 使用新位图对数据进行纹理处理?
更新:
我认为这个问题与这个问题更相关:Setting texture on 3D object using image from photo gallery。从画廊意图中获取图像然后裁剪它(另一个意图)后,我调用 changeBackground() 。
现在,如何从图库意图中有效地更改带有位图的纹理数据?有人知道吗?
已解决
我通过将纹理加载过程推迟到 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 上下文是 per thread。所以除非你对此做些什么(这是可能的,但会增加显着的复杂性),否则你不能从其他线程进行 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();