DetectedPlaneVisualizer.cs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /****************************************************************************
  2. * Copyright 2019 Nreal Techonology Limited. All rights reserved.
  3. *
  4. * This file is part of NRSDK.
  5. *
  6. * https://www.nreal.ai/
  7. *
  8. *****************************************************************************/
  9. namespace NRKernal.NRExamples
  10. {
  11. using System.Collections.Generic;
  12. using UnityEngine;
  13. /// <summary> Visualizes a single DetectedPlane in the Unity scene. </summary>
  14. public class DetectedPlaneVisualizer : MonoBehaviour
  15. {
  16. /// <summary> Number of planes. </summary>
  17. private static int s_PlaneCount = 0;
  18. /// <summary> List of colors of the planes. </summary>
  19. private readonly Color[] k_PlaneColors = new Color[]
  20. {
  21. new Color(1.0f, 1.0f, 1.0f),
  22. new Color(0.956f, 0.262f, 0.211f),
  23. new Color(0.913f, 0.117f, 0.388f),
  24. new Color(0.611f, 0.152f, 0.654f),
  25. new Color(0.403f, 0.227f, 0.717f),
  26. new Color(0.247f, 0.317f, 0.709f),
  27. new Color(0.129f, 0.588f, 0.952f),
  28. new Color(0.011f, 0.662f, 0.956f),
  29. new Color(0f, 0.737f, 0.831f),
  30. new Color(0f, 0.588f, 0.533f),
  31. new Color(0.298f, 0.686f, 0.313f),
  32. new Color(0.545f, 0.764f, 0.290f),
  33. new Color(0.803f, 0.862f, 0.223f),
  34. new Color(1.0f, 0.921f, 0.231f),
  35. new Color(1.0f, 0.756f, 0.027f)
  36. };
  37. /// <summary> The detected plane. </summary>
  38. private NRTrackablePlane m_DetectedPlane;
  39. /// <summary> Keep previous frame's mesh polygon to avoid mesh update every frame. </summary>
  40. private List<Vector3> m_PreviousFrameMeshVertices = new List<Vector3>();
  41. /// <summary> The mesh vertices. </summary>
  42. private List<Vector3> m_MeshVertices = new List<Vector3>();
  43. /// <summary> The plane center. </summary>
  44. private Vector3 m_PlaneCenter = new Vector3();
  45. /// <summary> List of colors of the meshes. </summary>
  46. private List<Color> m_MeshColors = new List<Color>();
  47. /// <summary> The mesh indices. </summary>
  48. private List<int> m_MeshIndices = new List<int>();
  49. /// <summary> The mesh. </summary>
  50. private Mesh m_Mesh;
  51. /// <summary> The mesh renderer. </summary>
  52. private MeshRenderer m_MeshRenderer;
  53. /// <summary> Awakes this object. </summary>
  54. public void Awake()
  55. {
  56. m_Mesh = GetComponent<MeshFilter>().mesh;
  57. m_MeshRenderer = GetComponent<UnityEngine.MeshRenderer>();
  58. }
  59. /// <summary> Updates this object. </summary>
  60. public void Update()
  61. {
  62. if (m_DetectedPlane == null)
  63. {
  64. return;
  65. }
  66. else if (m_DetectedPlane.GetTrackingState() != TrackingState.Tracking)
  67. {
  68. m_MeshRenderer.enabled = false;
  69. return;
  70. }
  71. m_MeshRenderer.enabled = true;
  72. _UpdateMeshIfNeeded();
  73. }
  74. /// <summary> Initializes the DetectedPlaneVisualizer with a DetectedPlane. </summary>
  75. /// <param name="plane"> The plane to vizualize.</param>
  76. public void Initialize(NRTrackablePlane plane)
  77. {
  78. m_DetectedPlane = plane;
  79. m_MeshRenderer.material.SetColor("_GridColor", k_PlaneColors[s_PlaneCount++ % k_PlaneColors.Length]);
  80. m_MeshRenderer.material.SetFloat("_UvRotation", Random.Range(0.0f, 360.0f));
  81. Update();
  82. }
  83. /// <summary> Update mesh with a list of Vector3 and plane's center position. </summary>
  84. private void _UpdateMeshIfNeeded()
  85. {
  86. m_DetectedPlane.GetBoundaryPolygon(m_MeshVertices);
  87. if (_AreVerticesListsEqual(m_PreviousFrameMeshVertices, m_MeshVertices))
  88. {
  89. return;
  90. }
  91. m_PreviousFrameMeshVertices.Clear();
  92. m_PreviousFrameMeshVertices.AddRange(m_MeshVertices);
  93. m_PlaneCenter = m_DetectedPlane.GetCenterPose().position;
  94. Vector3 planeNormal = m_DetectedPlane.GetCenterPose().rotation * Vector3.up;
  95. m_MeshRenderer.material.SetVector("_PlaneNormal", planeNormal);
  96. int planePolygonCount = m_MeshVertices.Count;
  97. // The following code converts a polygon to a mesh with two polygons, inner
  98. // polygon renders with 100% opacity and fade out to outter polygon with opacity 0%, as shown below.
  99. // The indices shown in the diagram are used in comments below.
  100. // _______________ 0_______________1
  101. // | | |4___________5|
  102. // | | | | | |
  103. // | | => | | | |
  104. // | | | | | |
  105. // | | |7-----------6|
  106. // --------------- 3---------------2
  107. m_MeshColors.Clear();
  108. // Fill transparent color to vertices 0 to 3.
  109. for (int i = 0; i < planePolygonCount; ++i)
  110. {
  111. m_MeshColors.Add(Color.clear);
  112. }
  113. // Feather distance 0.2 meters.
  114. const float featherLength = 0.2f;
  115. // Feather scale over the distance between plane center and vertices.
  116. const float featherScale = 0.2f;
  117. // Add vertex 4 to 7.
  118. for (int i = 0; i < planePolygonCount; ++i)
  119. {
  120. Vector3 v = m_MeshVertices[i];
  121. // Vector from plane center to current point
  122. Vector3 d = v - m_PlaneCenter;
  123. float scale = 1.0f - Mathf.Min(featherLength / d.magnitude, featherScale);
  124. m_MeshVertices.Add((scale * d) + m_PlaneCenter);
  125. m_MeshColors.Add(Color.white);
  126. }
  127. m_MeshIndices.Clear();
  128. int firstOuterVertex = 0;
  129. int firstInnerVertex = planePolygonCount;
  130. // Generate triangle (4, 5, 6) and (4, 6, 7).
  131. for (int i = 0; i < planePolygonCount - 2; ++i)
  132. {
  133. m_MeshIndices.Add(firstInnerVertex);
  134. m_MeshIndices.Add(firstInnerVertex + i + 1);
  135. m_MeshIndices.Add(firstInnerVertex + i + 2);
  136. }
  137. // Generate triangle (0, 1, 4), (4, 1, 5), (5, 1, 2), (5, 2, 6), (6, 2, 3), (6, 3, 7)
  138. // (7, 3, 0), (7, 0, 4)
  139. for (int i = 0; i < planePolygonCount; ++i)
  140. {
  141. int outerVertex1 = firstOuterVertex + i;
  142. int outerVertex2 = firstOuterVertex + ((i + 1) % planePolygonCount);
  143. int innerVertex1 = firstInnerVertex + i;
  144. int innerVertex2 = firstInnerVertex + ((i + 1) % planePolygonCount);
  145. m_MeshIndices.Add(outerVertex1);
  146. m_MeshIndices.Add(outerVertex2);
  147. m_MeshIndices.Add(innerVertex1);
  148. m_MeshIndices.Add(innerVertex1);
  149. m_MeshIndices.Add(outerVertex2);
  150. m_MeshIndices.Add(innerVertex2);
  151. }
  152. m_Mesh.Clear();
  153. m_Mesh.SetVertices(m_MeshVertices);
  154. m_Mesh.SetTriangles(m_MeshIndices, 0);
  155. m_Mesh.SetColors(m_MeshColors);
  156. }
  157. /// <summary> Determine if we are vertices lists equal. </summary>
  158. /// <param name="firstList"> List of firsts.</param>
  159. /// <param name="secondList"> List of seconds.</param>
  160. /// <returns> True if vertices lists equal, false if not. </returns>
  161. private bool _AreVerticesListsEqual(List<Vector3> firstList, List<Vector3> secondList)
  162. {
  163. if (firstList.Count != secondList.Count)
  164. {
  165. return false;
  166. }
  167. for (int i = 0; i < firstList.Count; i++)
  168. {
  169. if (firstList[i] != secondList[i])
  170. {
  171. return false;
  172. }
  173. }
  174. return true;
  175. }
  176. }
  177. }