Skip to content

Instantly share code, notes, and snippets.

@joelteply
Created August 3, 2018 21:36
Show Gist options
  • Save joelteply/416147bd1deda11ef555cd6a472e384d to your computer and use it in GitHub Desktop.
Save joelteply/416147bd1deda11ef555cd6a472e384d to your computer and use it in GitHub Desktop.
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