LightUtility.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using UnityEngine.Experimental.Rendering.Universal.LibTessDotNet;
  4. namespace UnityEngine.Experimental.Rendering.Universal
  5. {
  6. internal static class LightUtility
  7. {
  8. public static bool CheckForChange(int a, ref int b)
  9. {
  10. bool changed = a != b;
  11. b = a;
  12. return changed;
  13. }
  14. public static bool CheckForChange(float a, ref float b)
  15. {
  16. bool changed = a != b;
  17. b = a;
  18. return changed;
  19. }
  20. public static bool CheckForChange(bool a, ref bool b)
  21. {
  22. bool changed = a != b;
  23. b = a;
  24. return changed;
  25. }
  26. public static bool CheckForChange(Vector2 a, ref Vector2 b)
  27. {
  28. bool changed = a != b;
  29. b = a;
  30. return changed;
  31. }
  32. public static bool CheckForChange(Sprite a, ref Sprite b)
  33. {
  34. bool changed = !Equals(a, b);
  35. b = a;
  36. return changed;
  37. }
  38. public static Bounds CalculateBoundingSphere(ref Vector3[] vertices, ref Color[] colors, float falloffDistance)
  39. {
  40. Bounds localBounds = new Bounds();
  41. Vector3 minimum = new Vector3(float.MaxValue, float.MaxValue);
  42. Vector3 maximum = new Vector3(float.MinValue, float.MinValue);
  43. for (int i = 0; i < vertices.Length; i++)
  44. {
  45. Vector3 vertex = vertices[i];
  46. vertex.x += falloffDistance * colors[i].r;
  47. vertex.y += falloffDistance * colors[i].g;
  48. minimum.x = vertex.x < minimum.x ? vertex.x : minimum.x;
  49. minimum.y = vertex.y < minimum.y ? vertex.y : minimum.y;
  50. maximum.x = vertex.x > maximum.x ? vertex.x : maximum.x;
  51. maximum.y = vertex.y > maximum.y ? vertex.y : maximum.y;
  52. }
  53. localBounds.max = maximum;
  54. localBounds.min = minimum;
  55. return localBounds;
  56. }
  57. // Takes in a mesh that
  58. public static Bounds GenerateParametricMesh(ref Mesh mesh, float radius, float falloffDistance, float angle, int sides)
  59. {
  60. if (mesh == null)
  61. mesh = new Mesh();
  62. float angleOffset = Mathf.PI / 2.0f + Mathf.Deg2Rad * angle;
  63. if (sides < 3)
  64. {
  65. radius = 0.70710678118654752440084436210485f * radius;
  66. sides = 4;
  67. }
  68. if(sides == 4)
  69. {
  70. angleOffset = Mathf.PI / 4.0f + Mathf.Deg2Rad * angle;
  71. }
  72. // Return a shape with radius = 1
  73. Vector3[] vertices;
  74. int[] triangles;
  75. Color[] colors;
  76. int centerIndex;
  77. vertices = new Vector3[1 + 2 * sides];
  78. colors = new Color[1 + 2 * sides];
  79. triangles = new int[3 * 3 * sides];
  80. centerIndex = 2 * sides;
  81. // Color will contain r,g = x,y extrusion direction, a = alpha. b is unused at the moment. The inner shape should not be extruded
  82. Color color = new Color(0, 0, 0, 1);
  83. vertices[centerIndex] = Vector3.zero;
  84. colors[centerIndex] = color;
  85. float radiansPerSide = 2 * Mathf.PI / sides;
  86. for (int i = 0; i < sides; i++)
  87. {
  88. float endAngle = (i + 1) * radiansPerSide;
  89. Vector3 extrudeDir = new Vector3(Mathf.Cos(endAngle + angleOffset), Mathf.Sin(endAngle + angleOffset), 0);
  90. Vector3 endPoint = radius * extrudeDir;
  91. int vertexIndex;
  92. vertexIndex = (2 * i + 2) % (2 * sides);
  93. vertices[vertexIndex] = endPoint; // This is the extruded endpoint
  94. vertices[vertexIndex + 1] = endPoint;
  95. colors[vertexIndex] = new Color(extrudeDir.x, extrudeDir.y, 0, 0);
  96. colors[vertexIndex + 1] = color;
  97. // Triangle 1 (Tip)
  98. int triangleIndex = 9 * i;
  99. triangles[triangleIndex] = vertexIndex + 1;
  100. triangles[triangleIndex + 1] = 2 * i + 1;
  101. triangles[triangleIndex + 2] = centerIndex;
  102. // Triangle 2 (Upper Top Left)
  103. triangles[triangleIndex + 3] = vertexIndex;
  104. triangles[triangleIndex + 4] = 2 * i;
  105. triangles[triangleIndex + 5] = 2 * i + 1;
  106. // Triangle 2 (Bottom Top Left)
  107. triangles[triangleIndex + 6] = vertexIndex + 1;
  108. triangles[triangleIndex + 7] = vertexIndex;
  109. triangles[triangleIndex + 8] = 2 * i + 1;
  110. }
  111. mesh.Clear();
  112. mesh.vertices = vertices;
  113. mesh.colors = colors;
  114. mesh.triangles = triangles;
  115. return CalculateBoundingSphere(ref vertices, ref colors, falloffDistance);
  116. }
  117. public static Bounds GenerateSpriteMesh(ref Mesh mesh, Sprite sprite, float scale)
  118. {
  119. if (mesh == null)
  120. mesh = new Mesh();
  121. if (sprite != null)
  122. {
  123. Vector2[] vertices2d = sprite.vertices;
  124. Vector3[] vertices3d = new Vector3[vertices2d.Length];
  125. Color[] colors = new Color[vertices2d.Length];
  126. Vector4[] volumeColor = new Vector4[vertices2d.Length];
  127. ushort[] triangles2d = sprite.triangles;
  128. int[] triangles3d = new int[triangles2d.Length];
  129. Vector3 center = 0.5f * scale * (sprite.bounds.min + sprite.bounds.max);
  130. for (int vertexIdx = 0; vertexIdx < vertices2d.Length; vertexIdx++)
  131. {
  132. Vector3 pos = new Vector3(vertices2d[vertexIdx].x, vertices2d[vertexIdx].y) - center;
  133. vertices3d[vertexIdx] = scale * pos;
  134. colors[vertexIdx] = new Color(0,0,0,1); // This will not have any extrusion available. Alpha will be 1 * the pixel alpha
  135. }
  136. for (int triangleIdx = 0; triangleIdx < triangles2d.Length; triangleIdx++)
  137. {
  138. triangles3d[triangleIdx] = (int)triangles2d[triangleIdx];
  139. }
  140. mesh.Clear();
  141. mesh.vertices = vertices3d;
  142. mesh.uv = sprite.uv;
  143. mesh.triangles = triangles3d;
  144. mesh.colors = colors;
  145. return CalculateBoundingSphere(ref vertices3d, ref colors, 0);
  146. }
  147. return new Bounds(Vector3.zero, Vector3.zero);
  148. }
  149. static void GetFalloffExtrusion(ContourVertex[] contourPoints, int contourPointCount, ref List<Vector2> extrusionDir)
  150. {
  151. for (int i = 0; i < contourPointCount; ++i)
  152. {
  153. int h = (i == 0) ? (contourPointCount - 1) : (i - 1);
  154. int j = (i + 1) % contourPointCount;
  155. Vector2 pp = new Vector2(contourPoints[h].Position.X, contourPoints[h].Position.Y);
  156. Vector2 cp = new Vector2(contourPoints[i].Position.X, contourPoints[i].Position.Y);
  157. Vector2 np = new Vector2(contourPoints[j].Position.X, contourPoints[j].Position.Y);
  158. Vector2 cpd = cp - pp;
  159. Vector2 npd = np - cp;
  160. if (cpd.magnitude < 0.001f || npd.magnitude < 0.001f)
  161. continue;
  162. Vector2 vl = cpd.normalized;
  163. Vector2 vr = npd.normalized;
  164. vl = new Vector2(-vl.y, vl.x);
  165. vr = new Vector2(-vr.y, vr.x);
  166. Vector2 va = vl.normalized + vr.normalized;
  167. Vector2 vn = -va.normalized;
  168. if (va.magnitude > 0 && vn.magnitude > 0)
  169. {
  170. Vector2 dir = new Vector2(vn.x, vn.y);
  171. extrusionDir.Add(dir);
  172. }
  173. }
  174. }
  175. static object InterpCustomVertexData(Vec3 position, object[] data, float[] weights)
  176. {
  177. return data[0];
  178. }
  179. public static void GetFalloffShape(Vector3[] shapePath, ref List<Vector2> extrusionDir)
  180. {
  181. int pointCount = shapePath.Length;
  182. var inputs = new ContourVertex[pointCount];
  183. for (int i = 0; i < pointCount; ++i)
  184. inputs[i] = new ContourVertex() { Position = new Vec3() { X = shapePath[i].x, Y = shapePath[i].y }, Data = null };
  185. GetFalloffExtrusion(inputs, pointCount, ref extrusionDir);
  186. }
  187. public static Bounds GenerateShapeMesh(ref Mesh mesh, Vector3[] shapePath, float falloffDistance)
  188. {
  189. Bounds localBounds;
  190. Color meshInteriorColor = new Color(0,0,0,1);
  191. List<Vector3> finalVertices = new List<Vector3>();
  192. List<int> finalIndices = new List<int>();
  193. List<Color> finalColors = new List<Color>();
  194. // Create interior geometry
  195. int pointCount = shapePath.Length;
  196. var inputs = new ContourVertex[pointCount];
  197. for (int i = 0; i < pointCount; ++i)
  198. inputs[i] = new ContourVertex() { Position = new Vec3() { X = shapePath[i].x, Y = shapePath[i].y }, Data = meshInteriorColor };
  199. Tess tessI = new Tess();
  200. tessI.AddContour(inputs, ContourOrientation.Original);
  201. tessI.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3, InterpCustomVertexData);
  202. var indicesI = tessI.Elements.Select(i => i).ToArray();
  203. var verticesI = tessI.Vertices.Select(v => new Vector3(v.Position.X, v.Position.Y, 0)).ToArray();
  204. var colorsI = tessI.Vertices.Select(v => new Color(((Color)v.Data).r, ((Color)v.Data).g, ((Color)v.Data).b, ((Color)v.Data).a)).ToArray();
  205. finalVertices.AddRange(verticesI);
  206. finalIndices.AddRange(indicesI);
  207. finalColors.AddRange(colorsI);
  208. // Create falloff geometry
  209. List<Vector2> extrusionDirs = new List<Vector2>();
  210. GetFalloffShape(shapePath, ref extrusionDirs);
  211. pointCount = finalVertices.Count;
  212. int falloffPointCount = 2 * shapePath.Length;
  213. for (int i = 0; i < shapePath.Length; i++)
  214. {
  215. // Making triangles ABD and DCA
  216. int triangleIndex = 2 * i;
  217. int aIndex = pointCount + triangleIndex;
  218. int bIndex = pointCount + triangleIndex + 1;
  219. int cIndex = pointCount + (triangleIndex + 2) % falloffPointCount;
  220. int dIndex = pointCount + (triangleIndex + 3) % falloffPointCount;
  221. Vector3 point = shapePath[i];
  222. // We are making degenerate triangles which will be extruded by the shader
  223. finalVertices.Add(point);
  224. finalVertices.Add(point);
  225. finalIndices.Add(aIndex);
  226. finalIndices.Add(bIndex);
  227. finalIndices.Add(dIndex);
  228. finalIndices.Add(dIndex);
  229. finalIndices.Add(cIndex);
  230. finalIndices.Add(aIndex);
  231. Color aColor = new Color(0, 0, 0, 1);
  232. Color bColor = new Color(extrusionDirs[i].x, extrusionDirs[i].y, 0, 0);
  233. finalColors.Add(aColor);
  234. finalColors.Add(bColor);
  235. }
  236. Color[] colors = finalColors.ToArray();
  237. Vector3[] vertices = finalVertices.ToArray();
  238. mesh.Clear();
  239. mesh.vertices = vertices;
  240. mesh.colors = colors;
  241. mesh.SetIndices(finalIndices.ToArray(), MeshTopology.Triangles, 0);
  242. localBounds = CalculateBoundingSphere(ref vertices, ref colors, falloffDistance);
  243. return localBounds;
  244. }
  245. public static void AddShadowCasterGroupToList(ShadowCasterGroup2D shadowCaster, List<ShadowCasterGroup2D> list)
  246. {
  247. int positionToInsert = 0;
  248. for (positionToInsert = 0; positionToInsert < list.Count; positionToInsert++)
  249. {
  250. if (shadowCaster.GetShadowGroup() == list[positionToInsert].GetShadowGroup())
  251. break;
  252. }
  253. list.Insert(positionToInsert, shadowCaster);
  254. }
  255. public static void RemoveShadowCasterGroupFromList(ShadowCasterGroup2D shadowCaster, List<ShadowCasterGroup2D> list)
  256. {
  257. list.Remove(shadowCaster);
  258. }
  259. static CompositeShadowCaster2D FindTopMostCompositeShadowCaster(ShadowCaster2D shadowCaster)
  260. {
  261. CompositeShadowCaster2D retGroup = null;
  262. Transform transformToCheck = shadowCaster.transform.parent;
  263. while(transformToCheck != null)
  264. {
  265. CompositeShadowCaster2D currentGroup = transformToCheck.GetComponent<CompositeShadowCaster2D>();
  266. if (currentGroup != null)
  267. retGroup = currentGroup;
  268. transformToCheck = transformToCheck.parent;
  269. }
  270. return retGroup;
  271. }
  272. public static bool AddToShadowCasterGroup(ShadowCaster2D shadowCaster, ref ShadowCasterGroup2D shadowCasterGroup)
  273. {
  274. ShadowCasterGroup2D newShadowCasterGroup = FindTopMostCompositeShadowCaster(shadowCaster) as ShadowCasterGroup2D;
  275. if (newShadowCasterGroup == null)
  276. newShadowCasterGroup = shadowCaster.GetComponent<ShadowCaster2D>();
  277. if (newShadowCasterGroup != null && shadowCasterGroup != newShadowCasterGroup)
  278. {
  279. newShadowCasterGroup.RegisterShadowCaster2D(shadowCaster);
  280. shadowCasterGroup = newShadowCasterGroup;
  281. return true;
  282. }
  283. return false;
  284. }
  285. public static void RemoveFromShadowCasterGroup(ShadowCaster2D shadowCaster, ShadowCasterGroup2D shadowCasterGroup)
  286. {
  287. if(shadowCasterGroup != null)
  288. shadowCasterGroup.UnregisterShadowCaster2D(shadowCaster);
  289. }
  290. #if UNITY_EDITOR
  291. public static int GetShapePathHash(Vector3[] path)
  292. {
  293. unchecked
  294. {
  295. int hashCode = (int)2166136261;
  296. if (path != null)
  297. {
  298. foreach (var point in path)
  299. hashCode = hashCode * 16777619 ^ point.GetHashCode();
  300. }
  301. else
  302. {
  303. hashCode = 0;
  304. }
  305. return hashCode;
  306. }
  307. }
  308. #endif
  309. }
  310. }