﻿using System.Collections;
using UnityEngine;
using UnityEngine.Rendering;
using System;
using GCSeries.Core;

namespace GCSeries.zView
{

    public class GVirtualCameraAR : GVirtualCamera
    {
        /// <summary>
        /// class for generate a AR cutout mesh
        /// </summary>
        public class CutoutMesh
        {
            public Mesh BoxMesh { get { return _boxMesh; } }
            Mesh _boxMesh;

            public Mesh ScreenMesh { get { return _screenMesh; } }
            Mesh _screenMesh;

            public Mesh SkyBoxMesh { get { return _skyBoxMesh; } }
            Mesh _skyBoxMesh;

            public Vector2 screenSize
            {
                get { return _screenSize; }
                set { UpdateScreenSize(value); }
            }
            private Vector2 _screenSize;

            public Vector3 cutoutSize
            {
                get { return _cutoutSize; }
                set { UpdateCutoutSize(value); }
            }
            private Vector3 _cutoutSize;

            private CutoutMesh() { }

            public CutoutMesh(Vector2 screenSize, Vector3 cutoutSize)
            {
                _screenSize = screenSize;
                _cutoutSize = cutoutSize;
                _boxMesh = CreateMesh(_screenSize, _cutoutSize);
                _screenMesh = CreatePlane(screenSize);
                _skyBoxMesh = CreateSkyPlane(screenSize);
            }

            public void UpdateScreenSize(Vector2 newScreenSize)
            {
                if (newScreenSize == _screenSize) return;

                _screenSize = newScreenSize;
                Vector3[] vertices = BoxMesh.vertices;
                vertices[0] = new Vector3(_screenSize.x / 2, _screenSize.y / 2f, 0);
                vertices[1] = new Vector3(_screenSize.x / 2, -_screenSize.y / 2f, 0);
                vertices[2] = new Vector3(-_screenSize.x / 2, -_screenSize.y / 2f, 0);
                vertices[3] = new Vector3(-_screenSize.x / 2, _screenSize.y / 2f, 0);
                BoxMesh.vertices = vertices;

                Vector3[] ScreenVertices = ScreenMesh.vertices;
                ScreenVertices[0] = new Vector3(-screenSize.x / 2, -_screenSize.y / 2f, 0);
                ScreenVertices[1] = new Vector3(screenSize.x / 2, -_screenSize.y / 2f, 0);
                ScreenVertices[2] = new Vector3(-screenSize.x / 2, screenSize.y / 2f, 0);
                ScreenVertices[3] = new Vector3(screenSize.x / 2, screenSize.y / 2f, 0);
                ScreenMesh.vertices = ScreenVertices;
            }

            public void UpdateCutoutSize(Vector3 newCutoutSize)
            {
                if (newCutoutSize == _cutoutSize) return;

                _cutoutSize = newCutoutSize;
                Vector3[] vertices = _boxMesh.vertices;

                Vector3 halfSize = _cutoutSize * 0.5f;

                vertices[4] = new Vector3(-halfSize.x, halfSize.y, 0);
                vertices[5] = new Vector3(halfSize.x, halfSize.y, 0);
                vertices[6] = new Vector3(halfSize.x, -halfSize.y, 0);
                vertices[7] = new Vector3(-halfSize.x, -halfSize.y, 0);

                vertices[8] = new Vector3(-halfSize.x, halfSize.y, -_cutoutSize.z);
                vertices[9] = new Vector3(halfSize.x, halfSize.y, -_cutoutSize.z);
                vertices[10] = new Vector3(halfSize.x, -halfSize.y, -_cutoutSize.z);
                vertices[11] = new Vector3(-halfSize.x, -halfSize.y, -_cutoutSize.z);

                _boxMesh.vertices = vertices;
            }

            public void UpdateSize(Vector2 newScreenSize, Vector3 newCutoutSize)
            {
                UpdateScreenSize(newScreenSize);
                UpdateCutoutSize(newCutoutSize);
            }

            private Mesh CreateMesh(Vector2 screenSize, Vector3 size)
            {
                // Create the mesh.
                Mesh temp_mesh = new Mesh();
                temp_mesh.name = "BoxMask";
                temp_mesh.vertices = new Vector3[12];
                temp_mesh.triangles = new int[]
                {
                    // Back Face Top:
                    0, 4, 5,
                    0, 5, 1,

                    // Back Face Right:
                    1, 5, 6,
                    1, 6, 2,

                    // Back Face Bottom:
                    2, 6, 7,
                    2, 7, 3,

                    // Back Face Left:
                    3, 7, 4,
                    3, 4, 0,

                    // Top Face:
                    4, 8, 9,
                    4, 9, 5,

                    // Right Face:
                    5, 9, 10,
                    5, 10, 6,

                    // Bottom Face:
                    6, 10, 11,
                    6, 11, 7,

                    // Right Face:
                    7, 11, 8,
                    7, 8, 4,

                    // Front Face:
                    8, 10, 9,
                    8, 11, 10,
                };

                Vector2 halfSize = Vector2.one * 0.5f;
                Vector3[] vertices = temp_mesh.vertices;

                vertices[0] = new Vector3(screenSize.x / 2, screenSize.y / 2f, 0);
                vertices[1] = new Vector3(screenSize.x / 2, -screenSize.y / 2f, 0);
                vertices[2] = new Vector3(-screenSize.x / 2, -screenSize.y / 2f, 0);
                vertices[3] = new Vector3(-screenSize.x / 2, screenSize.y / 2f, 0);

                halfSize = size * 0.5f;

                vertices[4] = new Vector3(-halfSize.x, halfSize.y, 0);
                vertices[5] = new Vector3(halfSize.x, halfSize.y, 0);
                vertices[6] = new Vector3(halfSize.x, -halfSize.y, 0);
                vertices[7] = new Vector3(-halfSize.x, -halfSize.y, 0);

                vertices[8] = new Vector3(-halfSize.x, halfSize.y, -size.z);
                vertices[9] = new Vector3(halfSize.x, halfSize.y, -size.z);
                vertices[10] = new Vector3(halfSize.x, -halfSize.y, -size.z);
                vertices[11] = new Vector3(-halfSize.x, -halfSize.y, -size.z);

                temp_mesh.vertices = vertices;

                return temp_mesh;
            }

            /// <summary>
            /// 屏幕平面
            /// </summary>
            /// <param name="screenSize"></param>
            /// <returns></returns>
            private Mesh CreatePlane(Vector2 screenSize)
            {
                Mesh temp_mesh = new Mesh();
                temp_mesh.name = "screenPlane";
                temp_mesh.vertices = new Vector3[4]
                {
                    new Vector3(-screenSize.x / 2, -screenSize.y / 2f, 0),
                    new Vector3(screenSize.x / 2, -screenSize.y / 2f, 0),
                    new Vector3(-screenSize.x / 2, screenSize.y / 2f, 0),
                    new Vector3(screenSize.x / 2, screenSize.y / 2f, 0)
                };
                temp_mesh.triangles = new int[]
                {
                    // lower left triangle
                    0, 2, 1,
                    // upper right triangle
                    2, 3, 1
                };
                return temp_mesh;
            }

            /// <summary>
            /// 远处天空平面
            /// </summary>
            /// <param name="screenSize"></param>
            /// <returns></returns>
            private Mesh CreateSkyPlane(Vector2 screenSize)
            {
                Mesh temp_mesh = new Mesh();
                temp_mesh.name = "skyPlane";
                temp_mesh.vertices = new Vector3[4]
                {
                    new Vector3(-0.5f, -0.5f, 0),
                    new Vector3(0.5f, -0.5f, 0),
                    new Vector3(-0.5f, 0.5f, 0),
                    new Vector3(0.5f, 0.5f, 0)
                };

                Vector2[] uv = new Vector2[4]
                {
                new Vector2(0, 0),
                new Vector2(1, 0),
                new Vector2(0, 1),
                new Vector2(1, 1)
                };

                temp_mesh.triangles = new int[]
                {
                    // lower left triangle
                    0, 2, 1,
                    // upper right triangle
                    2, 3, 1
                };
                temp_mesh.uv = uv;

                return temp_mesh;
            }
        }

        //标定位置信息
        private Matrix4x4 _camPoseMatrixInDisplaySpace;
        private CommandBuffer _arBuffer;
        private CommandBuffer _cullBuffer;
        private CutoutMesh _cutoutMesh;
        private RenderTexture _depthMask;
        private MeshFilter _skyMeshFilter;
        private MeshFilter _boxMeshFilter;
        private Camera secondCamera;
        private Camera skyBoxCamera;
        private RenderTexture _secondRT;
        private RenderTexture _skyboxRT;
        private GView _zView;
        private static RenderTexture _renderTexture = null;

        private LayerMask _ignoreLayer;
        private LayerMask _environmentMask;

        /// <summary>
        /// 裁剪盒大小
        /// </summary>
        private Vector3 _cutoutMeshSizeScaler = Vector3.one;

        /// <summary>
        /// 屏幕背景色
        /// </summary>
        //private Color _screenMaskColor = new Color(0.572549f, 0.7019608f, 0.8588236f, 1f);

        void Awake()
        {
            // Dynamically create a new Unity camera and disable it to allow for manual 
            // rendering via Camera.Render().
            _arCamera = gameObject.AddComponent<Camera>();

            if (_arCamera == null)
            {
                Debug.LogError("GVirtualCameraAR.Awake():创建相机失败!");
            }
            else
            {
                _arCamera.enabled = false;
                _arCamera.nearClipPlane = 0.03f;

                _arCamera.targetDisplay = 0;
                _arCamera.stereoTargetEye = StereoTargetEyeMask.None;
            }

        }

        void OnPreCull()
        {
            if (skyBoxCamera != null)
            {
                skyBoxCamera.Render();
            }

            if (secondCamera != null)
            {
                secondCamera.Render();
            }
        }

        public override void SetUp(GView zView, IntPtr connection, GView.ModeSetupPhase phase)
        {
            _zView = zView;
            _arCamera.enabled = true;

            _zCameraRig = FindObjectOfType<ZCameraRig>();

            _imageWidth = zView.imageWidth;
            _imageHeight = zView.imageHeight;

            if (_renderTexture == null)
                _renderTexture = Resources.Load<RenderTexture>("gViewRT");

            _arCamera.targetTexture = _renderTexture;

            _ignoreLayer = zView.ARModeIgnoreLayers;
            _environmentMask = zView.ARModeEnvironmentLayers;
            _cutoutMeshSizeScaler = zView.ARModeMaskSize;
            //_screenMaskColor = zView.screenMaskColor;

            _cullBuffer = null;
            _arBuffer = null;
            ReadArCamTransform(out _camPoseMatrixInDisplaySpace);
            StartCoroutine(InitCamera(SetupCommandBuffer));
        }

        public override void TearDown()
        {
            CloseCamera();

            if (_cullBuffer != null)
            {
                _cullBuffer.Release();
                _cullBuffer = null;
            }

            if (_arBuffer != null)
            {
                _arBuffer.Release();
                _arBuffer = null;
            }

            if (secondCamera != null)
            {
                secondCamera.enabled = false;
            }

            _arCamera.RemoveAllCommandBuffers();
            _arCamera.enabled = false;

            if (_depthMask != null)
            {
                _depthMask.Release();
                _depthMask = null;
            }

            if (_secondRT != null)
            {
                _secondRT.Release();
                _secondRT = null;
            }

            if (_skyboxRT != null)
            {
                _skyboxRT.Release();
                _skyboxRT = null;
            }

            if (_skyMeshFilter != null)
            {
                _skyMeshFilter.gameObject.SetActive(false);
            }
        }

        public override void Render(GView zView, IntPtr connection, IntPtr receivedFrame)
        {
            if (_cutoutMesh != null)
            {
                // The camera's parent transform represents viewport center and
                // is used here to align the AR camera against.
                Transform cameraParentTransform = zView.ActiveZCamera?.transform.parent;

                // 实时更新相机位置
                // TODO:GCSeries编辑器下这个值不会随拖动编辑器窗口而修改，发布后表现一致
                Matrix4x4 temp_matrix = Matrix4x4.TRS(cameraParentTransform.position,
                                                       cameraParentTransform.rotation,
                                                       Vector3.one);
                //Debug.Log($"GVirtualCameraAr.Render(): ViewportMatrix = {temp_matrix}");
                Matrix4x4 displayToWorld = cameraParentTransform?.localToWorldMatrix ?? Matrix4x4.identity;
                //displayToWorld.SetColumn(3, new Vector4(0.1257f, -0.04232f, 0.0f, 1f));//这个是返回的结果
                Matrix4x4 cameraWorldMatrix = displayToWorld * _camPoseMatrixInDisplaySpace;
                transform.position = cameraWorldMatrix.GetColumn(3);
                transform.rotation = Quaternion.LookRotation(cameraWorldMatrix.GetColumn(2), cameraWorldMatrix.GetColumn(1));

                //更新遮挡mesh
                _cutoutMesh.screenSize = ZProvider.DisplayReferenceSize * _zCameraRig.ViewerScale;
                _cutoutMesh.cutoutSize = _cutoutMeshSizeScaler * _zCameraRig.ViewerScale;

                _boxMeshFilter.mesh.vertices = _cutoutMesh.BoxMesh.vertices;
                _boxMeshFilter.gameObject.transform.position = cameraParentTransform.position;
                _boxMeshFilter.gameObject.transform.rotation = cameraParentTransform.rotation;

                if (_cullBuffer != null)
                {
                    //更新绘制命令矩阵
                    _cullBuffer.Clear();
                    _cullBuffer.SetRenderTarget(_depthMask);
                    _cullBuffer.ClearRenderTarget(true, true, Color.black);
                    _cullBuffer.DrawMesh(_cutoutMesh.BoxMesh, temp_matrix, _depthRenderMat);
                }
                _arCamera.Render();
            }
        }

        // public override IntPtr GetNativeTexturePtr()
        // {
        //     Debug.LogError("GVirtualCameraAR.GetNativeTexturePtr():未使用渲染到纹理");
        //     if (_renderTexture == null) return IntPtr.Zero;
        //     return _renderTexture.GetNativeTexturePtr();
        // }
        public override IntPtr[] GetNativeTexturePtr(out int count)
        {
            count = 1;
            if (_renderTexture == null) return new IntPtr[] { IntPtr.Zero };
            return new IntPtr[] { _renderTexture.GetNativeTexturePtr() };
        }

        public override RenderTexture[] GetRenderTexture(out int count)
        {
            count = 1;
            return new RenderTexture[] { _renderTexture };
        }

        Material _depthRenderMat;

        private void SetupCommandBuffer(Texture webCamTexture)
        {
            // The camera's parent transform represents viewport center and
            // is used here to align the AR camera against.
            Transform cameraParentTransform = _zView.ActiveZCamera?.transform.parent;

            //arCamera.depthTextureMode = DepthTextureMode.Depth;
            _arCamera.renderingPath = RenderingPath.Forward;
            _arCamera.clearFlags = CameraClearFlags.Color;
            _arCamera.backgroundColor = new Color(0f, 0f, 0f, 0f);
            _arCamera.cullingMask = _arCamera.cullingMask & ~_ignoreLayer;
            _cutoutMesh = new CutoutMesh(ZProvider.DisplayReferenceSize, Vector3.one);

            if (_skyMeshFilter == null)
            {
                GameObject skyOBJ = new GameObject();
                skyOBJ.transform.parent = transform;
                skyOBJ.hideFlags = HideFlags.HideAndDontSave;
                skyOBJ.name = "HiddenSkyObj";
                _skyMeshFilter = skyOBJ.AddComponent<MeshFilter>();
                MeshRenderer boxRenderer = skyOBJ.AddComponent<MeshRenderer>();
                Material boxMat = new Material(Shader.Find("GcAR/SkyPlane"));
                boxRenderer.material = boxMat;
                boxRenderer.material.mainTexture = _skyboxRT;
                _skyMeshFilter.mesh = _cutoutMesh.SkyBoxMesh;
            }
            _skyMeshFilter.gameObject.SetActive(true);
            _skyMeshFilter.gameObject.transform.localPosition = new Vector3(0f, 0f, 0f);
            _skyMeshFilter.gameObject.transform.rotation = Quaternion.identity;
            _skyMeshFilter.mesh.vertices = new Vector3[4]
            {
                _arCamera.ScreenToWorldPoint(new Vector3(0f, 0f, _arCamera.farClipPlane * 0.9f)),
                _arCamera.ScreenToWorldPoint(new Vector3(_imageWidth, 0f, _arCamera.farClipPlane * 0.9f)),
                _arCamera.ScreenToWorldPoint(new Vector3(0f, _imageHeight, _arCamera.farClipPlane * 0.9f)),
                _arCamera.ScreenToWorldPoint(new Vector3(_imageWidth, _imageHeight, _arCamera.farClipPlane * 0.9f))
            };

            //这个buffer可以避免透明物体与环境物体混合问题
            //不过环境物体需要使用本例中StandardEnvironment.shader材质
            if (_boxMeshFilter == null)
            {
                GameObject boxOBJ = new GameObject();
                boxOBJ.transform.parent = transform;
                boxOBJ.hideFlags = HideFlags.HideAndDontSave;
                boxOBJ.name = "HiddenBoxObj";
                _boxMeshFilter = boxOBJ.AddComponent<MeshFilter>();
                MeshRenderer boxRenderer = boxOBJ.AddComponent<MeshRenderer>();
                Material boxMat = new Material(Shader.Find("GcAr/StencilWriter"));
                boxRenderer.materials = new Material[] { boxMat };
                _boxMeshFilter.mesh = _cutoutMesh.BoxMesh;
            }
            _boxMeshFilter.gameObject.transform.position = cameraParentTransform.position;
            _boxMeshFilter.gameObject.transform.rotation = cameraParentTransform.rotation;

            if (_cullBuffer == null)
            {
                _cullBuffer = new CommandBuffer();
                if (_depthMask == null)
                    _depthMask = new RenderTexture(_imageWidth, _imageHeight, 24);
                _cullBuffer.SetRenderTarget(_depthMask);
                _cullBuffer.ClearRenderTarget(true, true, Color.black);
                _cullBuffer.name = "Draw Cutout Mesh";
                _depthRenderMat = new Material(Shader.Find("GcAR/DepthRenderer"));
                Matrix4x4 temp_matrix = Matrix4x4.TRS(cameraParentTransform.position,
                                                        cameraParentTransform.rotation,
                                                        Vector3.one);
                _cullBuffer.DrawMesh(_cutoutMesh.BoxMesh, temp_matrix, _depthRenderMat);
                _arCamera.AddCommandBuffer(CameraEvent.AfterForwardOpaque, _cullBuffer);
            }

            if (_arBuffer == null)
            {
                _arBuffer = new CommandBuffer();
                Material material = new Material(Shader.Find("GcAR/DepthGrayscale"));

                _arBuffer.name = "GcAr Buffer";
                int customDepthID = Shader.PropertyToID("_customDepthMask");
                _arBuffer.GetTemporaryRT(customDepthID, -1, -1, 0, FilterMode.Bilinear);
                _arBuffer.Blit(_depthMask, customDepthID);

                int depthCameraID = Shader.PropertyToID("_noneCameraDepthTexture");
                _arBuffer.GetTemporaryRT(depthCameraID, -1, -1, 0, FilterMode.Bilinear);
                _arBuffer.Blit(_secondRT, depthCameraID);

                if (webCamTexture != null)
                {
                    int webCamTextureID = Shader.PropertyToID("_webCamTexture");
                    _arBuffer.GetTemporaryRT(webCamTextureID, -1, -1, 0, FilterMode.Bilinear);
                    _arBuffer.Blit(webCamTexture, webCamTextureID);
                }

                int texID = Shader.PropertyToID("_RenderTexture");
                _arBuffer.GetTemporaryRT(texID, -1, -1, 0, FilterMode.Bilinear);
                _arBuffer.Blit(BuiltinRenderTextureType.CameraTarget, texID);
                _arBuffer.Blit(texID, BuiltinRenderTextureType.CameraTarget, material);
                _arCamera.AddCommandBuffer(CameraEvent.AfterForwardAlpha, _arBuffer);
            }

        }

        /// <summary>
        /// 读取标定位置
        /// </summary>
        private void ReadArCamTransform(out Matrix4x4 viewPoseMatrixInDisplaySpace)
        {
            viewPoseMatrixInDisplaySpace = Matrix4x4.identity;
            bool readPoseSuccess = false;
            try
            {
                Matrix4x4 mat = new Matrix4x4();
                GView.FARError res = GView.xxGetARCameraPose(out mat);
                if (res == GView.FARError.Ok)
                {
                    viewPoseMatrixInDisplaySpace = mat;
                    readPoseSuccess = true;
                    UnityEngine.Debug.Log("GVirtualCameraAR.ReadArCamTransform():FAR相机Pose读取成功.");
                }
                else if (res == GView.FARError.Unknown)
                {
                    UnityEngine.Debug.LogError("GVirtualCameraAR.ReadArCamTransform():未知错误!");
                }
                else if (res == GView.FARError.NoCalib)
                {
                    UnityEngine.Debug.LogError("GVirtualCameraAR.ReadArCamTransform():先使用工具软件进行罗技摄像头的标定.");
                }
                else if (res == GView.FARError.NoLicense)
                {
                    UnityEngine.Debug.LogError("GVirtualCameraAR.ReadArCamTransform():系统没有FAR的License.");
                }
            }
            catch (Exception e)
            {
                UnityEngine.Debug.LogError("GVirtualCameraAR.ReadArCamTransform():执行xxGetARCameraPose()异常!e=" + e.Message);
            }
            if (!readPoseSuccess)
            {
                Debug.LogWarning("GVirtualCameraAR.ReadArCamTransform():FAR结果读取失败,设置一个默认值.");
                //*********GCSeries的标定位置矩阵**********
                viewPoseMatrixInDisplaySpace.SetColumn(0, new Vector4(0.58063f, -0.57597f, -0.57543f, 0f));
                viewPoseMatrixInDisplaySpace.SetColumn(1, new Vector4(0.38956f, 0.81716f, -0.42485f, 0f));
                viewPoseMatrixInDisplaySpace.SetColumn(2, new Vector4(0.71492f, 0.02251f, 0.69885f, 0f));
                viewPoseMatrixInDisplaySpace.SetColumn(3, new Vector4(-0.3647f, -0.02495f, -0.3946f, 1f));
                //*********************
            }
        }

        /// <summary>
        /// 相机采图
        /// </summary>
        private static WebCamTexture _camTex;

        IEnumerator InitCamera(Action<Texture> callback = null)
        {
            if (!Application.isPlaying) yield break;
            //获取授权
            //yield return Application.RequestUserAuthorization(UserAuthorization.WebCam);
            if (Application.HasUserAuthorization(UserAuthorization.WebCam))
            {
                var devices = WebCamTexture.devices;
                string _deviceName = "";
                foreach (var item in devices)
                {
                    //因为红外追踪相机都会以F3DXXXX命名
                    if (!item.name.Contains("F3D"))
                    {
                        _deviceName = item.name;
                        _arCamera.fieldOfView = 42.3f;

                        if (secondCamera == null)
                        {
                            GameObject secondCameraOBJ = new GameObject();
                            secondCameraOBJ.hideFlags = HideFlags.HideAndDontSave;
                            secondCameraOBJ.name = "SecondCamera";
                            secondCameraOBJ.transform.parent = transform;
                            secondCamera = secondCameraOBJ.AddComponent<Camera>();
                            secondCamera.stereoTargetEye = StereoTargetEyeMask.None;
                        }
                        if (_secondRT == null)
                            _secondRT = new RenderTexture(_imageWidth, _imageHeight, 24);

                        secondCamera.enabled = false; //渲染深度图可能会慢一帧
                        secondCamera.CopyFrom(_arCamera);
                        secondCamera.cullingMask = _arCamera.cullingMask & ~(_ignoreLayer) & ~(_environmentMask);
                        secondCamera.SetReplacementShader(Shader.Find("GcAR/DepthReplacement"), "");
                        secondCamera.targetTexture = _secondRT;

                        if (skyBoxCamera == null)
                        {
                            GameObject skyBoxCameraOBJ = new GameObject();
                            skyBoxCameraOBJ.hideFlags = HideFlags.HideAndDontSave;
                            skyBoxCameraOBJ.name = "skyBoxCameraOBJ";
                            skyBoxCameraOBJ.transform.parent = transform;
                            skyBoxCamera = skyBoxCameraOBJ.AddComponent<Camera>();
                            skyBoxCamera.CopyFrom(_arCamera);
                            skyBoxCamera.cullingMask = 0;
                            skyBoxCamera.clearFlags = CameraClearFlags.Skybox;


                            if (_skyboxRT == null)
                                _skyboxRT = new RenderTexture(_imageWidth, _imageHeight, 24);
                            skyBoxCamera.targetTexture = _skyboxRT;
                            skyBoxCamera.enabled = false;
                        }

                        break;
                    }
                }
                if (string.IsNullOrEmpty(_deviceName))
                {
                    UnityEngine.Debug.LogError("GVirtualCameraAR.InitCamera():相机启动失败，没有外接相机");
                    yield break;
                }
                else
                {
                    if (_camTex == null)
                    {
                        _camTex = new WebCamTexture(_deviceName, 1280, 720, 30);//设置为1280x720可以减少相机延迟
                        _camTex.Play();
                    }
                    else
                    {
                        _camTex.Play();
                    }

                    if (callback != null)
                        callback.Invoke(_camTex);
                    UnityEngine.Debug.Log("GVirtualCameraAR.InitCamera():相机启动");
                }

            }
        }

        /// <summary>
        /// 关闭罗技相机采图
        /// </summary>
        public void CloseCamera()
        {
            if (_camTex != null)
            {
                if (_camTex.isPlaying)
                {
                    _camTex.Stop();
                }
            }
        }

        private void OnApplicationQuit()
        {
            CloseCamera();
        }

        private Camera _arCamera = null;
        private UInt16 _imageWidth = 1920;
        private UInt16 _imageHeight = 1080;
        private ZCameraRig _zCameraRig;
        // private readonly Vector2 _screenSize = new Vector2(0.52f, 0.2925f);
    }
}