標籤:www unity3d rate private 並發 imp ack glut remove
在上一節中我們介紹了多線程OpenGL繪製方案,但是如果需要在Java線程不斷修改紋理資料,會由於並發訪問導致Unity線程出現訪問非法記憶體而崩潰。因此,考慮在Java線程載入資料,然後在unity線程調用OpenGL操作更新紋理。這樣所有的OpenGL操作都在Unity繪製線程完成,從而避免了多線程OpenGL引入的各種問題。為了能夠從Java線程切換到Unity線程執行,我們擷取到Unity線程的Looper,然後使用該Looper執行個體化一個Handler,這樣就可以通過往上發送訊息或者Runnable在Unity線程執行任務了。Java代碼如下:
1 package com.thornbirds.unity; 2 3 import android.graphics.Bitmap; 4 import android.graphics.BitmapFactory; 5 import android.opengl.GLES10; 6 import android.opengl.GLES11Ext; 7 import android.opengl.GLES20; 8 import android.opengl.GLUtils; 9 import android.os.Handler;10 import android.os.Looper;11 import android.util.Log;12 13 import java.util.concurrent.ExecutorService;14 import java.util.concurrent.Executors;15 16 public class PluginTexture {17 private static final String TAG = "PluginTexture";18 19 private int mTextureID = 0;20 private int mTextureWidth = 0;21 private int mTextureHeight = 0;22 23 // 建立單線程池,用於載入圖片資源24 private final ExecutorService mJavaThread = Executors.newSingleThreadExecutor();25 // 使用Unity線程Looper的Handler,用於執行Java層的OpenGL操作26 private Handler mUnityRenderHandler;27 28 public int getStreamTextureWidth() {29 return mTextureWidth;30 }31 32 public int getStreamTextureHeight() {33 return mTextureHeight;34 }35 36 public int getStreamTextureID() {37 return mTextureID;38 }39 40 public PluginTexture() {41 }42 43 private void glLogE(String msg) {44 Log.e(TAG, msg + ", err=" + GLES10.glGetError());45 }46 47 public void setupOpenGL() {48 // 注意:該調用一定是從Unity繪製線程發起49 if (Looper.myLooper() == null) {50 Looper.prepare();51 }52 mUnityRenderHandler = new Handler(Looper.myLooper());53 // 產生OpenGL紋理ID54 int textures[] = new int[1];55 GLES20.glGenTextures(1, textures, 0);56 if (textures[0] == 0) {57 glLogE("glGenTextures failed");58 return;59 }60 mTextureID = textures[0];61 mTextureWidth = 640;62 mTextureHeight = 360;63 }64 65 public void updateTexture() {66 mJavaThread.execute(new Runnable() {67 @Override68 public void run() {69 // 載入圖片資源70 String imageFilePath = "/sdcard/test/image.png";71 final Bitmap bitmap = BitmapFactory.decodeFile(imageFilePath);72 // 切換到Unity繪製線程更新紋理73 mUnityRenderHandler.post(new Runnable() {74 @Override75 public void run() {76 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID);77 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);78 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);79 GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);80 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);81 bitmap.recycle();82 }83 });84 }85 });86 }87 88 public void destroy() {89 mJavaThread.shutdownNow();90 mUnityRenderHandler.removeCallbacksAndMessages(null);91 }92 }
至此,我們完整介紹了Unity3D開發中在Android Java Plugin中進行紋理更新的方案和實現方法。基於相同的原理,我們可以很方便地給出iOS Object-C Plugin的實現,此處不在贅述。
安卓下多線程OpenGL共用Context (三)