Unity使用Android SurfaceTexture渲染

OpenGL ES
SurfaceTexture是Android端的贴图,是GL_TEXTURE_EXTERNAL_OES类型,是Android特有的类型相比普通的2D贴图有更好的性能,类似于Unity内的RenderTexture。

Unity设置

关闭多线程渲染,并且图形API选择OpenGLES2(必须)。

Unity Setting

Unity使用SurfaceTexture

有两种方案可以实现:

一,FBO转换

已知SurfaceTexture是一个GL_TEXTURE_EXTERNAL_OES类型,在Android端使用FBO(离屏渲染)将GL_TEXTURE_EXTERNAL_OES转换到GL_TEXTURE_2D类型,Unity将GL_TEXTURE_2D转换为Texture2D再进行渲染。

二,Unity GLSL Shader

Unity 中的 GLSL - Unity 手册 (unity3d.com)
Unity中是可以直接编写OpenGL ES Shader的,将GL_TEXTURE_EXTERNAL_OES类型的贴图在Unity端直接采样渲染。

第二种方案比第一种方案更好,第二种实现:
案例-Unity打开Android摄像头并预览画面
Android代码:

    private SurfaceTexture mSurfaceTexture; //camera preview
    private int mTextureID; 
    private boolean mFrameUpdated;  //帧是否更新
    private Camera mCamera;
//注意处理Android权限
public void openCamera() {
        mFrameUpdated = false;
        mCamera = Camera.open(0);
        int[] temps = new int[1];
        GLES30.glGenTextures(1, temps, 0);
        mTextureID = temps[0];
        GLES30.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureID);
        GLES30.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_NEAREST);
        GLES30.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
        GLES30.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE);
        GLES30.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE);
        GLES30.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
        mSurfaceTexture = new SurfaceTexture(mTextureOES.getTextureID());
        mSurfaceTexture.setOnFrameAvailableListener(this);
        try {
            mCamera.setPreviewTexture(mSurfaceTexture);
        } catch (IOException e) {
            e.printStackTrace();
        }
        mCamera.startPreview();
    }

@Override
    public void onFrameAvailable(SurfaceTexture surfaceTexture) {
        mFrameUpdated = true;
    }

public int updateTexture() {
        synchronized (this) {
            if (mFrameUpdated) { 
                mFrameUpdated = false; 
            }

            mSurfaceTexture.updateTexImage();

            return mTextureID;
        }
    }

    public boolean isFrameUpdated() {
        return mFrameUpdated;
    }

    public int getWidth() {
        return mCamera.getParameters().getPreviewSize().width;
    }

    public int getHeight() {
        return mCamera.getParameters().getPreviewSize().height;
    }

Unity代码:

    public MeshRenderer meshRenderer;
    public Material material;//使用OESShader
    public Texture2D texture;
    int textureId;
    AndroidJavaObject nativeCameraHolder;
    void Awake()
    {
        nativeCameraHolder = new AndroidJavaObject("com.inmo.unitycore.opengles.CameraHolder");
    }

    void Start()
    {
        _openCamera();
    }
void Update()
    {
        if (_isFrameUpdated())
        {
            textureId = _updateTexture();
            GL.InvalidateState();
            if (texture == null && textureId != 0)
            {
                texture = Texture2D.CreateExternalTexture(_getWidth(), _getHeight(),TextureFormat.RGB565, false, false, (IntPtr)textureId);
                texture.wrapMode = TextureWrapMode.Clamp;
                texture.filterMode = FilterMode.Bilinear;
            }
            else if (textureId != 0)
            {
                texture.UpdateExternalTexture((IntPtr)textureId);
                meshRenderer.material.SetTexture("_MainTex", texture);
            }
        }
    }
private void _openCamera()
    {
        nativeCameraHolder.Call("openCamera");
    }
    private void _closeCamera()
    {
        nativeCameraHolder.Call("closeCamera");
    }
    private bool _isFrameUpdated()
    {
        return nativeCameraHolder.Call<bool>("isFrameUpdated");
    }
    private int _updateTexture()
    {
        return nativeCameraHolder.Call<int>("updateTexture");
    }
    private int _getWidth()
    {
        return nativeCameraHolder.Call<int>("getWidth");
    }
    private int _getHeight()
    {
        return nativeCameraHolder.Call<int>("getHeight");
    }

Unity Shader代码:

Shader "CF/OESShader"
{
    Properties{
       _MainTex("Texture", 2D) = "white" {}
       _UvLeftTopBottom("UV of left corners",Vector) = (0,1,0,0)
       _UvRightTopBottom("UV of right corners",Vector) = (1,1,1,0)
    }
        // For GLES3
           SubShader
       {
           Pass
           {
               ZWrite Off
               GLSLPROGRAM
               #extension GL_OES_EGL_image_external : require
               uniform vec4 _UvLeftTopBottom;
               uniform vec4 _UvRightTopBottom;

               #ifdef VERTEX
               varying vec2 textureCoord;
               void main()
               {
                   vec2 uvLeft = mix(_UvLeftTopBottom.xy, _UvLeftTopBottom.zw, gl_MultiTexCoord0.y);
                   vec2 uvRight = mix(_UvRightTopBottom.xy, _UvRightTopBottom.zw, gl_MultiTexCoord0.y);
                   textureCoord = mix(uvLeft, uvRight, gl_MultiTexCoord0.x);

                   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
               }
               #endif

               #ifdef FRAGMENT
               precision mediump float; //精度为float
               varying vec2 textureCoord;
               uniform samplerExternalOES _MainTex;
               void main()
               {
                   gl_FragColor = texture2D(_MainTex, textureCoord);
               }
               #endif

               ENDGLSL
           }
       }
           FallBack Off
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352

推荐阅读更多精彩内容