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
}

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容