NavigationPath.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. /*===============================================================================
  2. Copyright (C) 2022 Immersal - Part of Hexagon. All Rights Reserved.
  3. This file is part of the Immersal SDK.
  4. The Immersal SDK cannot be copied, distributed, or made available to
  5. third-parties for commercial purposes without written permission of Immersal Ltd.
  6. Contact sdk@immersal.com for licensing requests.
  7. ===============================================================================*/
  8. using System.Collections.Generic;
  9. using UnityEngine;
  10. using UnityEngine.Events;
  11. using UnityEngine.UI;
  12. using UnityEngine.AI;
  13. using Immersal.AR;
  14. using TMPro;
  15. namespace Immersal.Samples.Navigation
  16. {
  17. public class NavigationPath : MonoBehaviour
  18. {
  19. [HideInInspector]
  20. public float pathWidth = 0.3f;
  21. private float m_StepSize = 0.2f;
  22. private float m_ResampledStepSize = 0.2f;
  23. private bool m_Resample = true;
  24. private bool m_GenerateMesh = true;
  25. private float m_tension = 0.5f;
  26. private Mesh m_Mesh;
  27. private MeshFilter m_MeshFilter;
  28. private MeshRenderer m_MeshRenderer;
  29. private float m_PathLength;
  30. private float m_minStepSize = 0.1f;
  31. private void Awake()
  32. {
  33. if (m_Mesh == null)
  34. m_Mesh = new Mesh();
  35. m_MeshFilter = GetComponent<MeshFilter>();
  36. m_MeshRenderer = GetComponent<MeshRenderer>();
  37. if (m_MeshFilter == null)
  38. m_MeshFilter = gameObject.AddComponent<MeshFilter>();
  39. if (m_MeshRenderer == null)
  40. m_MeshRenderer = gameObject.AddComponent<MeshRenderer>();
  41. m_MeshFilter.mesh = m_Mesh;
  42. }
  43. public void GeneratePath(List<Vector3> points, Vector3 up)
  44. {
  45. if (points.Count < 2)
  46. return;
  47. if (points.Count == 2)
  48. {
  49. points.Insert(1, Vector3.Lerp(points[0], points[1], 0.333f));
  50. points.Insert(1, Vector3.Lerp(points[0], points[1], 0.666f));
  51. }
  52. List<Vector3> curvePoints = CatmullRomCurvePoints(points);
  53. if (m_Resample)
  54. curvePoints = ResampleCurve(curvePoints);
  55. if (curvePoints.Count < 2)
  56. return;
  57. if (m_GenerateMesh)
  58. GenerateMesh(curvePoints, up);
  59. }
  60. public void GeneratePath(List<Vector3> points)
  61. {
  62. GeneratePath(points, Vector3.up);
  63. }
  64. public void ClearMesh()
  65. {
  66. if (m_Mesh)
  67. m_Mesh.Clear();
  68. }
  69. private float GetT(float t, Vector3 p0, Vector3 p1)
  70. {
  71. float a = Mathf.Pow((p1.x - p0.x), 2.0f) + Mathf.Pow((p1.y - p0.y), 2.0f) + Mathf.Pow((p1.z - p0.z), 2.0f);
  72. float b = Mathf.Pow(a, 0.5f);
  73. float c = Mathf.Pow(b, m_tension);
  74. return (c + t);
  75. }
  76. private List<Vector3> CatmullRomCurveSegmentPoints(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float segmentDivisions)
  77. {
  78. List<Vector3> points = new List<Vector3>();
  79. float t0 = 1.0f;
  80. float t1 = GetT(t0, p0, p1);
  81. float t2 = GetT(t1, p1, p2);
  82. float t3 = GetT(t2, p2, p3);
  83. for (float t = t1; t < t2; t += (t2 - t1) / segmentDivisions)
  84. {
  85. Vector3 a1 = (t1 - t) / (t1 - t0) * p0 + (t - t0) / (t1 - t0) * p1;
  86. Vector3 a2 = (t2 - t) / (t2 - t1) * p1 + (t - t1) / (t2 - t1) * p2;
  87. Vector3 a3 = (t3 - t) / (t3 - t2) * p2 + (t - t2) / (t3 - t2) * p3;
  88. Vector3 b1 = (t2 - t) / (t2 - t0) * a1 + (t - t0) / (t2 - t0) * a2;
  89. Vector3 b2 = (t3 - t) / (t3 - t1) * a2 + (t - t1) / (t3 - t1) * a3;
  90. Vector3 c = (t2 - t) / (t2 - t1) * b1 + (t - t1) / (t2 - t1) * b2;
  91. points.Add(c);
  92. }
  93. return points;
  94. }
  95. private List<Vector3> CatmullRomCurvePoints(List<Vector3> in_points)
  96. {
  97. List<Vector3> out_points = new List<Vector3>();
  98. for (int i = 0; i < in_points.Count - 1; i++)
  99. {
  100. Vector3 p0;
  101. Vector3 p1;
  102. Vector3 p2;
  103. Vector3 p3;
  104. if (i == 0)
  105. {
  106. p0 = in_points[i] + (in_points[i] - in_points[i + 1]);
  107. }
  108. else
  109. {
  110. p0 = in_points[i - 1];
  111. }
  112. p1 = in_points[i];
  113. p2 = in_points[i + 1];
  114. if (i > in_points.Count - 3)
  115. {
  116. p3 = in_points[i] + (in_points[i] - in_points[i - 1]);
  117. }
  118. else
  119. {
  120. p3 = in_points[i + 2];
  121. }
  122. float segmentDivisions = Mathf.Ceil((p2 - p1).magnitude / Mathf.Max(m_minStepSize, m_StepSize));
  123. List<Vector3> segmentPoints = CatmullRomCurveSegmentPoints(p0, p1, p2, p3, segmentDivisions);
  124. out_points.AddRange(segmentPoints);
  125. }
  126. out_points.Add(in_points[in_points.Count - 1]);
  127. return out_points;
  128. }
  129. private List<Vector3> ResampleCurve(List<Vector3> oldPointPositions)
  130. {
  131. List<Vector3> points = new List<Vector3>();
  132. List<float> distanceAlongOldCurve = new List<float>();
  133. List<float> relativePositionOnOldCurve = new List<float>();
  134. List<float> relativePositionOnNewCurve = new List<float>();
  135. List<int> indexOfFirstPoint = new List<int>();
  136. List<float> blendBetweenPoints = new List<float>();
  137. float totalCurveLength = 0.0f;
  138. int oldPointCount = oldPointPositions.Count;
  139. //calculate distance along curve and total distance
  140. for (int i = 0; i < oldPointCount; i++)
  141. {
  142. float d;
  143. if (i == 0)
  144. {
  145. d = 0f;
  146. }
  147. else
  148. {
  149. Vector3 a = oldPointPositions[i - 1];
  150. Vector3 b = oldPointPositions[i];
  151. d = (b - a).magnitude;
  152. }
  153. totalCurveLength += d;
  154. distanceAlongOldCurve.Add(totalCurveLength);
  155. }
  156. m_PathLength = totalCurveLength;
  157. //calculate relative position on curve based on distance
  158. for (int i = 0; i < oldPointCount; i++)
  159. {
  160. float rp;
  161. if (i == 0)
  162. {
  163. rp = 0f;
  164. }
  165. else
  166. {
  167. rp = distanceAlongOldCurve[i] / totalCurveLength;
  168. }
  169. relativePositionOnOldCurve.Add(rp);
  170. }
  171. //calculate how many new points are needed
  172. int newPointCount = (int)Mathf.Ceil(totalCurveLength / Mathf.Max(m_minStepSize, m_ResampledStepSize));
  173. //find first old point further than the new one
  174. for (int i = 0; i < newPointCount; i++)
  175. {
  176. //new point relative position on new curve
  177. float t = (float)i / (float)(newPointCount - 1.0f);
  178. relativePositionOnNewCurve.Add(t);
  179. int k = 0;
  180. float j = relativePositionOnOldCurve[k];
  181. while (j < t)
  182. {
  183. j = relativePositionOnOldCurve[k];
  184. if (j <= t)
  185. {
  186. k++;
  187. }
  188. }
  189. indexOfFirstPoint.Add(Mathf.Min(oldPointCount - 1, k));
  190. }
  191. for (int i = 0; i < newPointCount; i++)
  192. {
  193. int lower = Mathf.Max(indexOfFirstPoint[i] - 1, 0);
  194. int upper = indexOfFirstPoint[i];
  195. Vector3 a = oldPointPositions[lower];
  196. Vector3 b = oldPointPositions[upper];
  197. float d0 = relativePositionOnOldCurve[lower];
  198. float d1 = relativePositionOnOldCurve[upper];
  199. float blend;
  200. if (d1 - d0 > 0f)
  201. {
  202. blend = (relativePositionOnNewCurve[i] - d0) / (d1 - d0);
  203. }
  204. else
  205. {
  206. blend = 0f;
  207. }
  208. Vector3 p = Vector3.Lerp(a, b, blend);
  209. points.Add(p);
  210. }
  211. return points;
  212. }
  213. private void GenerateMesh(List<Vector3> points, Vector3 y)
  214. {
  215. List<Matrix4x4> matrices = new List<Matrix4x4>();
  216. for (int i = 0; i < points.Count; i++)
  217. {
  218. Vector3 z, x = new Vector3();
  219. // last point
  220. if (i == points.Count - 1)
  221. {
  222. z = (points[i] - points[i - 1]).normalized;
  223. }
  224. else
  225. {
  226. z = (points[i + 1] - points[i]).normalized;
  227. }
  228. x = Vector3.Cross(y, z);
  229. //y = Vector3.Cross(z, x);
  230. Quaternion q = Quaternion.LookRotation(z, -y);
  231. Matrix4x4 m = Matrix4x4.TRS(points[i], q, new Vector3(1f, 1f, 1f));
  232. matrices.Add(m);
  233. //Debug.DrawRay(points[i], x * 0.4f, Color.red);
  234. //Debug.DrawRay(points[i], y * 0.4f, Color.green);
  235. //Debug.DrawRay(points[i], z * 0.4f, Color.blue);
  236. }
  237. Vector3[] shape = new Vector3[] { new Vector3(-0.5f, 0f, 0f), new Vector3(0.5f, 0f, 0f) };
  238. float[] shapeU = new float[] { 0f, 1f };
  239. int vertsInShape = shape.Length;
  240. int segments = points.Count - 1;
  241. int edgeLoops = points.Count;
  242. int vertCount = vertsInShape * edgeLoops;
  243. int triCount = shape.Length * segments;
  244. int triIndexCount = triCount * 3;
  245. int[] triIndices = new int[triIndexCount];
  246. int[] lines = new int[] { 0, 1 };
  247. Vector3[] vertices = new Vector3[vertCount];
  248. Vector2[] uvs = new Vector2[vertCount];
  249. for (int i = 0; i < points.Count; i++)
  250. {
  251. int offset = i * vertsInShape;
  252. for (int j = 0; j < vertsInShape; j++)
  253. {
  254. int id = offset + j;
  255. vertices[id] = matrices[i].MultiplyPoint(shape[j] * pathWidth);
  256. uvs[id] = new Vector2(i / (float)edgeLoops * m_PathLength, shapeU[j]);
  257. }
  258. }
  259. int ti = 0;
  260. for (int i = 0; i < segments; i++)
  261. {
  262. int offset = i * vertsInShape;
  263. for (int l = 0; l < lines.Length; l += 2)
  264. {
  265. int a = offset + lines[l] + vertsInShape;
  266. int b = offset + lines[l];
  267. int c = offset + lines[l + 1];
  268. int d = offset + lines[l + 1] + vertsInShape;
  269. triIndices[ti] = a; ti++;
  270. triIndices[ti] = b; ti++;
  271. triIndices[ti] = c; ti++;
  272. triIndices[ti] = c; ti++;
  273. triIndices[ti] = d; ti++;
  274. triIndices[ti] = a; ti++;
  275. }
  276. }
  277. m_Mesh.Clear();
  278. m_Mesh.vertices = vertices;
  279. m_Mesh.triangles = triIndices;
  280. m_Mesh.uv = uvs;
  281. }
  282. }
  283. }