687 lines
27 KiB
C#
687 lines
27 KiB
C#
|
|
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);
|
|||
|
|
}
|
|||
|
|
}
|