ShadowUtility.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using System;
  5. using Unity.Collections;
  6. using System.Linq;
  7. using UnityEngine.Experimental.Rendering.Universal.LibTessDotNet;
  8. namespace UnityEngine.Experimental.Rendering.Universal
  9. {
  10. internal class ShadowUtility
  11. {
  12. internal struct Edge : IComparable<Edge>
  13. {
  14. public int vertexIndex0;
  15. public int vertexIndex1;
  16. public Vector4 tangent;
  17. private bool compareReversed; // This is done so that edge AB can equal edge BA
  18. public void AssignVertexIndices(int vi0, int vi1)
  19. {
  20. vertexIndex0 = vi0;
  21. vertexIndex1 = vi1;
  22. compareReversed = vi0 > vi1;
  23. }
  24. public int Compare(Edge a, Edge b)
  25. {
  26. int adjustedVertexIndex0A = a.compareReversed ? a.vertexIndex1 : a.vertexIndex0;
  27. int adjustedVertexIndex1A = a.compareReversed ? a.vertexIndex0 : a.vertexIndex1;
  28. int adjustedVertexIndex0B = b.compareReversed ? b.vertexIndex1 : b.vertexIndex0;
  29. int adjustedVertexIndex1B = b.compareReversed ? b.vertexIndex0 : b.vertexIndex1;
  30. // Sort first by VI0 then by VI1
  31. int deltaVI0 = adjustedVertexIndex0A - adjustedVertexIndex0B;
  32. int deltaVI1 = adjustedVertexIndex1A - adjustedVertexIndex1B;
  33. if (deltaVI0 == 0)
  34. return deltaVI1;
  35. else
  36. return deltaVI0;
  37. }
  38. public int CompareTo(Edge edgeToCompare)
  39. {
  40. return Compare(this, edgeToCompare);
  41. }
  42. }
  43. static Edge CreateEdge(int triangleIndexA, int triangleIndexB, List<Vector3> vertices, List<int> triangles)
  44. {
  45. Edge retEdge = new Edge();
  46. retEdge.AssignVertexIndices(triangles[triangleIndexA], triangles[triangleIndexB]);
  47. Vector3 vertex0 = vertices[retEdge.vertexIndex0];
  48. Vector3 vertex1 = vertices[retEdge.vertexIndex1];
  49. Vector3 edgeDir = Vector3.Normalize(vertex1 - vertex0);
  50. retEdge.tangent = Vector3.Cross(-Vector3.forward, edgeDir);
  51. return retEdge;
  52. }
  53. static void PopulateEdgeArray(List<Vector3> vertices, List<int> triangles, List<Edge> edges)
  54. {
  55. for(int triangleIndex=0;triangleIndex<triangles.Count;triangleIndex+=3)
  56. {
  57. edges.Add(CreateEdge(triangleIndex, triangleIndex + 1, vertices, triangles));
  58. edges.Add(CreateEdge(triangleIndex+1, triangleIndex + 2, vertices, triangles));
  59. edges.Add(CreateEdge(triangleIndex+2, triangleIndex, vertices, triangles));
  60. }
  61. }
  62. static bool IsOutsideEdge(int edgeIndex, List<Edge> edgesToProcess)
  63. {
  64. int previousIndex = edgeIndex - 1;
  65. int nextIndex = edgeIndex + 1;
  66. int numberOfEdges = edgesToProcess.Count;
  67. Edge currentEdge = edgesToProcess[edgeIndex];
  68. return (previousIndex < 0 || (currentEdge.CompareTo(edgesToProcess[edgeIndex - 1]) != 0)) && (nextIndex >= numberOfEdges || (currentEdge.CompareTo(edgesToProcess[edgeIndex + 1]) != 0));
  69. }
  70. static void SortEdges(List<Edge> edgesToProcess)
  71. {
  72. edgesToProcess.Sort();
  73. }
  74. static void CreateShadowTriangles(List<Vector3> vertices, List<int> triangles, List<Vector4> tangents, List<Edge> edges)
  75. {
  76. for(int edgeIndex=0; edgeIndex<edges.Count; edgeIndex++)
  77. {
  78. if(IsOutsideEdge(edgeIndex, edges))
  79. {
  80. Edge edge = edges[edgeIndex];
  81. tangents[edge.vertexIndex1] = -edge.tangent;
  82. int newVertexIndex = vertices.Count;
  83. vertices.Add(vertices[edge.vertexIndex0]);
  84. tangents.Add(-edge.tangent);
  85. triangles.Add(edge.vertexIndex0);
  86. triangles.Add(newVertexIndex);
  87. triangles.Add(edge.vertexIndex1);
  88. }
  89. }
  90. }
  91. static object InterpCustomVertexData(Vec3 position, object[] data, float[] weights)
  92. {
  93. return data[0];
  94. }
  95. static void InitializeTangents(int tangentsToAdd, List<Vector4> tangents)
  96. {
  97. for (int i = 0; i < tangentsToAdd; i++)
  98. tangents.Add(Vector4.zero);
  99. }
  100. public static void GenerateShadowMesh(Mesh mesh, Vector3[] shapePath)
  101. {
  102. Color meshInteriorColor = new Color(0, 0, 0, 1);
  103. List<Vector3> vertices = new List<Vector3>();
  104. List<int> triangles = new List<int>();
  105. List<Vector4> tangents = new List<Vector4>();
  106. // Create interior geometry
  107. int pointCount = shapePath.Length;
  108. var inputs = new ContourVertex[pointCount];
  109. for (int i = 0; i < pointCount; ++i)
  110. inputs[i] = new ContourVertex() { Position = new Vec3() { X = shapePath[i].x, Y = shapePath[i].y }, Data = meshInteriorColor };
  111. Tess tessI = new Tess();
  112. tessI.AddContour(inputs, ContourOrientation.Original);
  113. tessI.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3, InterpCustomVertexData);
  114. var indicesI = tessI.Elements.Select(i => i).ToArray();
  115. var verticesI = tessI.Vertices.Select(v => new Vector3(v.Position.X, v.Position.Y, 0)).ToArray();
  116. vertices.AddRange(verticesI);
  117. triangles.AddRange(indicesI);
  118. InitializeTangents(vertices.Count, tangents);
  119. List<Edge> edges = new List<Edge>();
  120. PopulateEdgeArray(vertices, triangles, edges);
  121. SortEdges(edges);
  122. CreateShadowTriangles(vertices, triangles, tangents, edges);
  123. Vector3[] finalVertices = vertices.ToArray();
  124. int[] finalTriangles = triangles.ToArray();
  125. Vector4[] finalTangents = tangents.ToArray();
  126. mesh.Clear();
  127. mesh.vertices = finalVertices;
  128. mesh.triangles = finalTriangles;
  129. mesh.tangents = finalTangents;
  130. }
  131. }
  132. }