Created
August 3, 2018 21:36
-
-
Save joelteply/416147bd1deda11ef555cd6a472e384d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using UnityEngine; | |
using System.Collections; | |
using UnityEngine.XR.iOS; | |
using System; | |
using System.Runtime.InteropServices; | |
using System.Threading; | |
using Object = System.Object; | |
namespace Cambrian.iOS | |
{ | |
public class CambrianARMeshGenerator : MonoBehaviour | |
{ | |
private static CambrianARMeshGenerator m_instance; | |
private Vector2 m_meshScale = new Vector2(0.4F, 1.6F); //32x72 ,avg size | |
float m_elevation; | |
bool m_hasFloor = false; | |
const float EPSILON = 0.00001F; | |
bool m_requestedFeatures = false; | |
bool m_clearMesh = true; | |
private bool m_touchedFloor = false; | |
private Texture2D m_shadowsYTexture; | |
private Matrix4x4 m_displayTransform; | |
private bool m_needsDisplay = false; | |
private CBSurfaceData m_surfaceData; | |
//x,z,width,height | |
private Vector4 m_maskExtents = new Vector4(0.0F,0.0F,1.0F,1.0F); | |
private Vector4 m_shadowsExtents = new Vector4(0.0F,0.0F,1.0F,1.0F); | |
private Object m_meshLock = new Object(); | |
private bool m_maskShadowsNeedsUpdate = false; | |
private Mesh m_mesh; | |
// Use this for initialization | |
void Start() | |
{ | |
m_instance = this; | |
Reset(); | |
CambrianARMaskIntegrator.CBSurfaceContoursUpdatedEvent += CBContoursUpdated; | |
CambrianARMaskIntegrator.CBSurfaceCreatedEvent += CambrianArMaskIntegratorOnCbSurfaceCreatedEvent; | |
CambrianARMaskIntegrator.CBSurfaceMaskUpdatedEvent += CambrianArMaskIntegratorOnCbSurfaceMaskUpdatedEvent; | |
CambrianARMaskIntegrator.CBSurfaceShadowsUpdatedEvent += CambrianArMaskIntegratorOnCbSurfaceShadowsUpdatedEvent; | |
CambrianARSessionNativeInterface.ARSessionStoppedEvent += CambrianArSessionNativeInterfaceOnArSessionStoppedEvent; | |
UnityARSessionNativeInterface.ARFrameUpdatedEvent += UpdateFrame; | |
UnityARSessionNativeInterface.ARAnchorAddedEvent += UnityARSessionNativeInterface_ARAnchorAddedEvent; | |
UnityARSessionNativeInterface.ARAnchorUpdatedEvent += UnityARSessionNativeInterface_ARAnchorUpdatedEvent; | |
//Camera.main.gameObject.GetComponent<CambrianARVideo>().SetRenderTexure(m_cameraYSourceTexture); | |
//getMaterial().SetTexture("_CameraY", m_cameraYSourceTexture); | |
} | |
private void OnDestroy() { | |
Reset(); | |
m_instance = null; | |
CambrianARMaskIntegrator.CBSurfaceContoursUpdatedEvent -= CBContoursUpdated; | |
CambrianARMaskIntegrator.CBSurfaceCreatedEvent -= CambrianArMaskIntegratorOnCbSurfaceCreatedEvent; | |
CambrianARMaskIntegrator.CBSurfaceMaskUpdatedEvent -= CambrianArMaskIntegratorOnCbSurfaceMaskUpdatedEvent; | |
CambrianARMaskIntegrator.CBSurfaceShadowsUpdatedEvent -= CambrianArMaskIntegratorOnCbSurfaceShadowsUpdatedEvent; | |
CambrianARSessionNativeInterface.ARSessionStoppedEvent -= CambrianArSessionNativeInterfaceOnArSessionStoppedEvent; | |
UnityARSessionNativeInterface.ARFrameUpdatedEvent -= UpdateFrame; | |
UnityARSessionNativeInterface.ARAnchorAddedEvent -= UnityARSessionNativeInterface_ARAnchorAddedEvent; | |
UnityARSessionNativeInterface.ARAnchorUpdatedEvent -= UnityARSessionNativeInterface_ARAnchorUpdatedEvent; | |
} | |
private void Reset() { | |
m_hasFloor = false; | |
m_elevation = 0; | |
m_requestedFeatures = false; | |
m_touchedFloor = false; | |
m_needsDisplay = true; | |
CB.Log("RESET"); | |
GetComponent<MeshFilter>().mesh = new Mesh();//empty to start | |
} | |
private void CambrianArSessionNativeInterfaceOnArSessionStoppedEvent(CambrianARSessionState sessionstate) { | |
Reset(); | |
} | |
private void CambrianArMaskIntegratorOnCbSurfaceCreatedEvent(CBSurfaceData surfaceData) { | |
m_surfaceData = surfaceData; | |
getMaterial().SetTexture("_MaskY", m_surfaceData.maskTexture); | |
getMaterial().SetTexture("_ShadowsY", m_surfaceData.shadowsTexture); | |
} | |
private void CambrianArMaskIntegratorOnCbSurfaceShadowsUpdatedEvent(CBSurfaceAssetParams data, Vector4 extents) { | |
m_shadowsExtents = extents; | |
CB.Log("Received shadow extents {0}", extents); | |
m_maskShadowsNeedsUpdate = true; | |
} | |
private void CambrianArMaskIntegratorOnCbSurfaceMaskUpdatedEvent(CBSurfaceAssetParams data, Vector4 extents) { | |
m_maskExtents = extents; | |
CB.Log("Received mask extents {0}", extents); | |
m_maskShadowsNeedsUpdate = true; | |
} | |
void UpdateFrame(UnityARCamera cam) { | |
if (!m_needsDisplay) return; | |
m_needsDisplay = false; | |
m_displayTransform = new Matrix4x4(); | |
m_displayTransform.SetColumn(0, cam.displayTransform.column0); | |
m_displayTransform.SetColumn(1, cam.displayTransform.column1); | |
m_displayTransform.SetColumn(2, cam.displayTransform.column2); | |
m_displayTransform.SetColumn(3, cam.displayTransform.column3); | |
} | |
void UnityARSessionNativeInterface_ARAnchorAddedEvent(ARPlaneAnchor anchorData) | |
{ | |
var floorPosition = UnityARMatrixOps.GetPosition(anchorData.transform); | |
if (floorPosition.y > -2 && Math.Abs(m_elevation - floorPosition.y) < 0.3) | |
{ | |
m_elevation = floorPosition.y; | |
Vector3 floorNormal = new Vector3(0, 1, 0); | |
CambrianARSessionNativeInterface.GetARSessionNativeInterface().setGroundPlane(ref floorPosition, ref floorNormal); | |
//only affects Y | |
transform.position = new Vector3(transform.position.x, m_elevation, this.transform.position.z); | |
} | |
} | |
void UnityARSessionNativeInterface_ARAnchorUpdatedEvent(ARPlaneAnchor anchorData) | |
{ | |
var floorPosition = UnityARMatrixOps.GetPosition(anchorData.transform); | |
if (floorPosition.y > -2 && (Math.Abs(m_elevation - floorPosition.y) < 0.3 || floorPosition.y < m_elevation)) | |
{ | |
m_elevation = floorPosition.y; | |
Vector3 floorNormal = new Vector3(0, 1, 0); | |
CambrianARSessionNativeInterface.GetARSessionNativeInterface().setGroundPlane(ref floorPosition, ref floorNormal); | |
//only affects Y | |
transform.position = new Vector3(transform.position.x, m_elevation, this.transform.position.z); | |
} | |
} | |
void handleHit(Matrix4x4 trans) { | |
var floorPosition = UnityARMatrixOps.GetPosition(trans); | |
if (floorPosition.y > -2 && (Math.Abs(m_elevation - floorPosition.y) < 0.3 || floorPosition.y < m_elevation)) | |
{ | |
m_elevation = floorPosition.y; | |
Vector3 floorNormal = new Vector3(0, 1, 0); | |
CambrianARSessionNativeInterface.GetARSessionNativeInterface().setGroundPlane(ref floorPosition, ref floorNormal); | |
//only affects Y | |
transform.position = new Vector3(transform.position.x, m_elevation, this.transform.position.z); | |
m_hasFloor = true; | |
getFeatures(); | |
} | |
} | |
private void CBContoursUpdated(CBContourData data) { | |
if (!m_hasFloor) return; | |
CreateMesh(ref data); | |
getFeatures(); | |
} | |
void getFeatures() { | |
CambrianARSessionNativeInterface.GetARSessionNativeInterface().PerformDeepSegmentation(); | |
m_requestedFeatures = true; | |
} | |
void Update() { | |
bool uvsNeedUpdate = m_maskShadowsNeedsUpdate; | |
m_maskShadowsNeedsUpdate = false; | |
lock (m_meshLock) { | |
if (m_mesh != null) { | |
uvsNeedUpdate = true; | |
GetComponent<MeshFilter>().mesh = m_mesh; | |
GetComponent<MeshCollider>().sharedMesh = m_mesh; | |
} | |
m_mesh = null; | |
} | |
if (uvsNeedUpdate) { | |
updateMaskShadowUVS(); | |
} | |
//if (m_cameraYTexture == null) { | |
//m_cameraYTexture = Camera.main.gameObject.GetComponent<CambrianARVideo>().GetYTexure(); | |
//getMaterial().SetMatrix("m_displayTransform", m_displayTransform); | |
//} | |
if (m_surfaceData != null) { | |
//getMaterial().SetTexture("_MaskY", m_surfaceData.maskTexture); | |
//getMaterial().SetTexture("_ShadowsY", m_surfaceData.shadowsTexture); | |
} | |
//getMaterial().SetTexture("_CameraY", m_cameraYTexture); | |
if (Input.touchCount > 0 && !m_requestedFeatures) | |
{ | |
var touch = Input.GetTouch(0); | |
if (touch.phase == TouchPhase.Began ) | |
{ | |
m_clearMesh = true; | |
m_touchedFloor = true; | |
CambrianARMaskIntegrator.ClearAllSurfaces(); | |
CB.Log("Camera is at {0}", Camera.main.transform.position); | |
if (m_hasFloor) { | |
getFeatures(); | |
} else { | |
var screenPosition = Camera.main.ScreenToViewportPoint(touch.position); | |
ARPoint point = new ARPoint | |
{ | |
x = screenPosition.x, | |
y = screenPosition.y | |
}; | |
ARHitTestResultType[] resultTypes = { | |
ARHitTestResultType.ARHitTestResultTypeFeaturePoint, | |
ARHitTestResultType.ARHitTestResultTypeExistingPlaneUsingExtent, | |
// if you want to use infinite planes use this: | |
ARHitTestResultType.ARHitTestResultTypeExistingPlane, | |
ARHitTestResultType.ARHitTestResultTypeEstimatedHorizontalPlane, | |
}; | |
foreach (var resultType in resultTypes) { | |
List<ARHitTestResult> hitResults = UnityARSessionNativeInterface.GetARSessionNativeInterface().HitTest(point, resultType); | |
if (hitResults.Count > 0) { | |
handleHit(hitResults[0].worldTransform); | |
return; | |
} | |
} | |
} | |
} | |
} | |
} | |
private Material getMaterial() | |
{ | |
return GetComponent<Renderer>().material; | |
} | |
private void TriangulateGroundPoints(Vector3[] points3D, out Vector3[] vertices, out int[] indices) { | |
//all have same Y | |
Vector2[] points2D = new Vector2[points3D.Length]; | |
for (int i = 0; i < points3D.Length; i++) { | |
points2D[i].x = points3D[i].x; | |
points2D[i].y = points3D[i].z; | |
} | |
Triangulator tr = new Triangulator(points2D); | |
indices = tr.Triangulate(); | |
// Create the Vector3 vertices | |
vertices = new Vector3[points2D.Length]; | |
for (int i = 0; i < vertices.Length; i++) { | |
vertices[i] = new Vector3(points2D[i].x, 0.0F, points2D[i].y); | |
} | |
} | |
//List<Mesh> meshes = new List<Mesh>(); | |
//private void mergeMeshes() { | |
// meshes.Add(mesh); | |
// | |
// List<CombineInstance> ci = new List<CombineInstance>(); | |
// foreach (var m in meshes) | |
// ci.Add(new CombineInstance() { mesh = m }); | |
// | |
// var g = new GameObject("combined"); | |
// g.AddComponent<MeshFilter>().mesh = new Mesh(); | |
// g.GetComponent<MeshFilter>().mesh.CombineMeshes(ci.ToArray(), true, false); | |
// g.AddComponent<MeshRenderer>().sharedMaterial = getMaterial(); | |
// | |
// var combinedMesh = g.GetComponent<MeshFilter>().mesh; | |
//Destroy(g); | |
//} | |
private void updateMaskShadowUVS() { | |
var mesh = GetComponent<MeshFilter>().mesh; | |
if (mesh.vertices.Length == 0) { | |
return; | |
} | |
Vector2[] shadows_mask_uvs = new Vector2[mesh.vertices.Length]; | |
Vector2 maskSize = new Vector2(m_shadowsExtents.z, m_shadowsExtents.w); | |
for (var i = 0; i < mesh.vertices.Length; i++) { | |
shadows_mask_uvs[i] = new Vector2( | |
(mesh.vertices[i].x - m_shadowsExtents.x) / maskSize.x, | |
(mesh.vertices[i].z - m_shadowsExtents.y) / maskSize.y); | |
} | |
mesh.uv2 = shadows_mask_uvs; | |
mesh.uv3 = shadows_mask_uvs; | |
} | |
//project point onto plane | |
private void CreateMesh(ref CBContourData contour) | |
{ | |
Vector3[] vertices; | |
int[] indices; | |
TriangulateGroundPoints(contour.points3D, out vertices, out indices); | |
Mesh mesh = new Mesh(); | |
mesh.vertices = vertices; | |
mesh.triangles = indices; | |
mesh.RecalculateNormals(); | |
mesh.RecalculateBounds(); | |
Vector2[] uvs = new Vector2[vertices.Length]; | |
for (int i = 0; i < vertices.Length; i++) { | |
uvs[i] = new Vector2(vertices[i].x, vertices[i].z); | |
} | |
mesh.uv = uvs; | |
lock (m_meshLock) { | |
m_mesh = mesh; | |
} | |
GetComponent<MeshRenderer>().sharedMaterial = getMaterial(); | |
GetComponent<MeshRenderer>().material.mainTextureScale = new Vector2(1.0F / m_meshScale.x, 1.0F / m_meshScale.y); | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment