• 安卓下多线程OpenGL共享Context (一)


        最近在研究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             @Override
    40             public void run() {
    41                 // 生成OpenGL纹理ID
    42                 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             @Override
    58             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 using System;
     2 using UnityEngine;
     3 
     4 public class PluginTestureDemo : MonoBehaviour {
     5     private AndroidJavaObject mPluginTexture; 
     6     private int mTextureId;
     7     private int mWidth;
     8     private int mHeight;
     9 
    10     void Start () {
    11         // 实例化com.thornbirds.unity.PluginTexture类的对象
    12         mPluginTexture = new AndroidJavaObject ("com.thornbirds.unity.PluginTexture");
    13         // 初始化OpenGL
    14         mPluginTexture.Call ("setupOpenGL");
    15     }
    16 
    17     void BindTexture () {
    18         // 获取JavaPlugin生成的纹理ID
    19         mTextureId = mPluginTexture.Call<int> ("getPluginTextureID");
    20         if (mTextureId == 0) {
    21             Debug.LogError ("getPluginTextureID failed");
    22             return;
    23         }
    24         mWidth = mPluginTexture.Call<int> ("getPluginTextureWidth");
    25         mHeight = mPluginTexture.Call<int> ("getPluginTextureHeight");
    26         // 将纹理ID与当前GameObject绑定
    27         GetComponent<MeshRenderer> ().material.mainTexture = Texture2D.CreateExternalTexture 
    28             (mWidth, mHeight, TextureFormat.ARGB32, false, false, (IntPtr) mTextureId);
    29         // 更新纹理数据
    30         mPluginTexture.Call ("updateTexture");
    31     }
    32 }

    注意:C#中使用了方法名调用Java方法,因此需要防止编译Jar包时Java类及其public方法被混淆。在Proguard文件中加入如下代码:

    1 -keep class com.thornbirds.unity.PluginTexture {
    2     public *;
    3 }

        该方案存在一个问题,在Java线程中访问进行OpenGL操作,会报Missing GLContext,需要为Java线程初始化OpenGL绘制环境。下回继续。

  • 相关阅读:
    Hdu 3564 Another LIS 线段树+LIS
    利用ESLINT进行js 语法检查,以及局部安装时遇到的一些坑
    操作系统杂谈
    算法杂谈
    前端杂谈
    操作系统复习
    vue之——从彩笔的进步之路
    一丢丢学习之webpack4 + Vue单文件组件的应用
    计蒜客 2017复赛 百度地图导航
    electron打包之真的恶心
  • 原文地址:https://www.cnblogs.com/moderate-fish/p/6890749.html
Copyright © 2020-2023  润新知