簡體   English   中英

Android:如何從圖庫/相機更改 OpenGLES 紋理數據/位圖

[英]Android: How to change OpenGLES texture data / bitmap from gallery / camera

我嘗試重用Android 媒體效果示例,並希望能夠使用來自相機或圖庫選擇的新位圖更改紋理數據。 目前沒有解決辦法

這是示例的初始加載紋理: 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

如何使用新位圖更改/修改/替換紋理數據?

更新:

我認為這個問題與這個問題更相關: 使用照片庫中的圖像在 3D 對象上設置紋理 我從畫廊意圖抓取圖像后調用 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 上下文是每個線程的 因此,除非您對此采取一些措施(這是可能的,但會增加顯着的復雜性),否則您無法從其他線程進行 OpenGL 調用。

有幾個選項可以解決這個問題。 最簡單的一個可能是使用queueEvent()的方法GLSurfaceView ,它允許你在一個通過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();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM