標籤:getc jar包 ima end utils 需要 bug width idt
最近在研究Unity3D開發中使用Java Plugin進行紋理更新,想法很簡單,在Java線程更新紋理資料,然後Unity情境中的紋理將自動更新。
首先,建立Java類,定義建立紋理及擷取紋理參數的介面,並建立單線程池用於進行載入Bitmap並綁定紋理資料等OpenGL操作。Java程式碼範例:
1 package com.thornbirds.unity; 2 3 import android.graphics.Bitmap; 4 import android.graphics.BitmapFactory; 5 import android.opengl.GLES11Ext; 6 import android.opengl.GLES20; 7 import android.opengl.GLUtils; 8 import android.util.Log; 9 10 import java.util.concurrent.ExecutorService;11 import java.util.concurrent.Executors;12 13 public class PluginTexture {14 private static final String TAG = "PluginTexture";15 private int mTextureID = 0;16 private int mTextureWidth = 0;17 private int mTextureHeight = 0;18 19 // 建立單線程池,用於處理OpenGL紋理20 private final ExecutorService mRenderThread = Executors.newSingleThreadExecutor();21 22 public int getStreamTextureWidth() {23 return mTextureWidth;24 }25 26 public int getStreamTextureHeight() {27 return mTextureHeight;28 }29 30 public int getStreamTextureID() {31 return mTextureID;32 }33 34 public PluginTexture() {35 }36 37 public void setupOpenGL() {38 mRenderThread.execute(new Runnable() {39 @Override40 public void run() {41 // 產生OpenGL紋理ID42 int textures[] = new int[1];43 GLES20.glGenTextures(1, textures, 0);44 if (textures[0] == 0) {45 Log.e(TAG, "glGenTextures failed");46 return;47 }48 mTextureID = textures[0];49 mTextureWidth = 640;50 mTextureHeight = 360;51 }52 });53 }54 55 public void updateTexture() {56 mRenderThread.execute(new Runnable() {57 @Override58 public void run() {59 String imageFilePath = "/sdcard/test/image.png";60 final Bitmap bitmap = BitmapFactory.decodeFile(imageFilePath);61 62 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID);63 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);64 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);65 GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);66 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);67 68 bitmap.recycle();69 }70 });71 }72 73 public void destroy() {74 mRenderThread.shutdownNow();75 }76 }
然後,建立C#指令碼,在指令碼中樣本化Java對象,並調用Java方法初始化OpenGL;為了展示更新紋理,需擷取到Java產生的紋理ID,並將其與指令碼當前GameObject綁定。C#程式碼範例:
1 public class PluginTestureDemo : MonoBehaviour { 2 private AndroidJavaObject mPluginTexture; 3 private int mTextureId; 4 private int mWidth; 5 private int mHeight; 6 7 void Start () { 8 // 執行個體化com.thornbirds.unity.PluginTexture類的對象 9 mPluginTexture = new AndroidJavaObject ("com.thornbirds.unity.PluginTexture");10 // 初始化OpenGL11 mPluginTexture.Call ("setupOpenGL");12 }13 14 void BindTexture () {15 // 擷取JavaPlugin產生的紋理ID16 mTextureId = mPluginTexture.Call<int> ("getPluginTextureID");17 if (mTextureId == 0) {18 Debug.LogError ("getPluginTextureID failed");19 return;20 }21 mWidth = mPluginTexture.Call<int> ("getPluginTextureWidth");22 mHeight = mPluginTexture.Call<int> ("getPluginTextureHeight");23 // 將紋理ID與當前GameObject綁定24 GetComponent<MeshRenderer> ().material.mainTexture = Texture2D.CreateExternalTexture 25 (mWidth, mHeight, TextureFormat.ARGB32, false, false, (IntPtr) mTextureId);26 // 更新紋理資料27 mPluginTexture.Call ("updateTexture");28 }29 }
注意:C#中使用了方法名調用Java方法,因此需要防止編譯Jar包時Java類及其public方法被混淆。在Proguard檔案中加入如下代碼:
1 -keep class com.thornbirds.unity.PluginTexture {2 public *;3 }
該方案存在一個問題,在Java線程中訪問進行OpenGL操作,會報Missing GLContext,需要為Java線程初始化OpenGL繪製環境。下回繼續。
安卓下多線程OpenGL共用Context (一)