SW 중심대학 OSS GIT 서버 박건태, 이승준, 고기완, 이준호 새로운 배포
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

158 lines
7.1 KiB

4 years ago
  1. using System;
  2. using System.Collections.Generic;
  3. using Unity.Collections;
  4. namespace UnityEngine.XR.ARFoundation
  5. {
  6. /// <summary>
  7. /// Generator functions for <see cref="ARPlane"/> mesh geometery.
  8. /// </summary>
  9. /// <remarks>
  10. /// These static class provides ways to generate different parts of plane geometry, such as vertices, indices, normals and UVs.
  11. /// You can use these functions to build an ARPlane Mesh object.
  12. /// </remarks>
  13. public static class ARPlaneMeshGenerators
  14. {
  15. /// <summary>
  16. /// Generates a <c>Mesh</c> from the given parameters. The <paramref name="convexPolygon"/> is assumed to be convex.
  17. /// </summary>
  18. /// <remarks>
  19. /// <paramref name="convexPolygon"/> is not checked for its convexness. Concave polygons will produce incorrect results.
  20. /// </remarks>
  21. /// <param name="mesh">The <c>Mesh</c> to write results to.</param>
  22. /// <param name="convexPolygon">The vertices of the plane's boundary, in plane-space.</param>
  23. /// <param name="areaTolerance">If any triangle in the generated mesh is less than this, then the entire mesh is ignored.
  24. /// This handles an edge case which prevents degenerate or very small triangles. Units are meters-squared.</param>
  25. /// <returns><c>True</c> if the <paramref name="mesh"/> was generated, <c>False</c> otherwise. The <paramref name="mesh"/> may
  26. /// fail to generate if it is not a valid polygon (too few vertices) or if it contains degenerate triangles (area smaller than <paramref name="areaTolerance"/>).</returns>
  27. public static bool GenerateMesh(Mesh mesh, Pose pose, NativeArray<Vector2> convexPolygon, float areaTolerance = 1e-6f)
  28. {
  29. if (mesh == null)
  30. throw new ArgumentNullException("mesh");
  31. if (convexPolygon.Length < 3)
  32. return false;
  33. // Vertices
  34. s_Vertices.Clear();
  35. var center = Vector3.zero;
  36. foreach (var point2 in convexPolygon)
  37. {
  38. var point3 = new Vector3(point2.x, 0, point2.y);
  39. center += point3;
  40. s_Vertices.Add(point3);
  41. }
  42. center /= convexPolygon.Length;
  43. s_Vertices.Add(center);
  44. // If the polygon is too small or degenerate, no mesh is created.
  45. if (!GenerateIndices(s_Indices, s_Vertices, areaTolerance))
  46. return false;
  47. // We can't fail after this point, so it is safe to mutate the mesh
  48. mesh.Clear();
  49. mesh.SetVertices(s_Vertices);
  50. // Indices
  51. const int subMesh = 0;
  52. const bool calculateBounds = true;
  53. mesh.SetTriangles(s_Indices, subMesh, calculateBounds);
  54. // UVs
  55. GenerateUvs(s_Uvs, pose, s_Vertices);
  56. mesh.SetUVs(0, s_Uvs);
  57. // Normals
  58. // Reuse the same list for normals
  59. var normals = s_Vertices;
  60. for (int i = 0; i < normals.Count; ++i)
  61. normals[i] = Vector3.up;
  62. mesh.SetNormals(normals);
  63. return true;
  64. }
  65. /// <summary>
  66. /// Generates a <c>List<Vector2></c> of UVs from the given parameters.
  67. /// </summary>
  68. /// <param name="Uvs">The <c>List<Vector2></c> to write results to.</param>
  69. /// <param name="vertices">The vertices of the plane's boundary, in plane-space.</param>
  70. public static void GenerateUvs(List<Vector2> Uvs, Pose pose, List<Vector3> vertices)
  71. {
  72. // Get the twist rotation about the plane's normal, then apply
  73. // its inverse to the rotation to produce the "untwisted" rotation.
  74. // This is similar to Swing-Twist Decomposition.
  75. var planeRotation = pose.rotation;
  76. var rotationAxis = new Vector3(planeRotation.x, planeRotation.y, planeRotation.z);
  77. var projection = Vector3.Project(rotationAxis, planeRotation * Vector3.up);
  78. var normalizedTwist = (new Vector4(projection.x, projection.y, projection.z, planeRotation.w)).normalized;
  79. var inverseTwist = new Quaternion(normalizedTwist.x, normalizedTwist.y, normalizedTwist.z, -normalizedTwist.w);
  80. var untwistedRotation = inverseTwist * pose.rotation;
  81. // Compute the basis vectors for the plane in session space.
  82. var sessionSpaceRight = untwistedRotation * Vector3.right;
  83. var sessionSpaceForward = untwistedRotation * Vector3.forward;
  84. Uvs.Clear();
  85. foreach (var vertex in vertices)
  86. {
  87. var vertexInSessionSpace = pose.rotation * vertex + pose.position;
  88. // Project onto each axis
  89. var uv = new Vector2(
  90. Vector3.Dot(vertexInSessionSpace, sessionSpaceRight),
  91. Vector3.Dot(vertexInSessionSpace, sessionSpaceForward));
  92. Uvs.Add(uv);
  93. }
  94. }
  95. /// <summary>
  96. /// Generates a <c>List<int></c> of indices from the given parameters, forming a triangle fan.
  97. /// The <paramref name="convexPolygon"/> is assumed to be convex.
  98. /// </summary>
  99. /// <remarks>
  100. /// <paramref name="convexPolygon"/> is not checked for its convexness. Concave polygons will produce incorrect results.
  101. /// </remarks>
  102. /// <param name="Uvs">The <c>List<int></c> to write results to.</param>
  103. /// <param name="convexPolygon">The vertices of the plane's boundary, in plane-space.</param>
  104. /// <param name="areaTolerance">If any triangle in the generated mesh is less than this, then the entire mesh is ignored.
  105. /// <returns><c>True</c> if the indices were generated, <c>False</c> if a triangle whose area is less than <paramref name="areaTolerance"/> is found.</returns>
  106. public static bool GenerateIndices(List<int> indices, List<Vector3> convexPolygon, float areaTolerance = 1e-6f)
  107. {
  108. indices.Clear();
  109. var numBoundaryVertices = convexPolygon.Count - 1;
  110. var centerIndex = numBoundaryVertices;
  111. var areaToleranceSquared = areaTolerance * areaTolerance;
  112. for (int i = 0; i < numBoundaryVertices; ++i)
  113. {
  114. int j = (i + 1) % numBoundaryVertices;
  115. // Stop if the area of the triangle is too small
  116. var a = convexPolygon[i] - convexPolygon[centerIndex];
  117. var b = convexPolygon[j] - convexPolygon[centerIndex];
  118. // Area is the magnitude of the normal / 2, so the
  119. // area squared is the magnitude squared / 4
  120. var areaSquared = Vector3.Cross(a, b).sqrMagnitude * 0.25f;
  121. if (areaSquared < areaToleranceSquared)
  122. return false;
  123. indices.Add(centerIndex);
  124. indices.Add(i);
  125. indices.Add(j);
  126. }
  127. return true;
  128. }
  129. // Caches to avoid reallocing Lists during calculations
  130. static List<int> s_Indices = new List<int>();
  131. static List<Vector2> s_Uvs = new List<Vector2>();
  132. static List<Vector3> s_Vertices = new List<Vector3>();
  133. }
  134. }