java - Android:如何从图库/相机更改 OpenGLES 纹理数据/位图

标签 java android opengl-es effects

我尝试重用Android Media Effects samples并希望能够使用相机或画廊选择的新位图更改纹理数据。目前还没有解决办法

这是示例中的初始加载纹理: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 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/

相关文章:

opengl-es - 如何更改opengles中glDrawArrays方法中使用的顶点缓冲区的内容

java - 异常 java.lang.ClassNotFoundException : com. google.api.server.spi.EndpointsServlet

android - 类 java.awt.Font 错误 - Android

android-layout - 安卓用户界面 : Button with shape inside?

Android——几乎完全在 OpenGL 中制作用户界面有什么问题吗?

ios - 除了组合器中的前一个和当前纹理单元之外,我还可以引用其他纹理单元吗?

java - 如何正确使用 ItemTouchHelper

java - 如何自动滚动 ScrollPane 以便节点在 Pane 顶部对齐

java - 我怎么能改变 "http.connection-manager.timeout"?

java - 在 Parse 上检索文件 - 图像