FlatMesh.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. using UnityEngine;
  2. using System;
  3. using System.Collections.Generic;
  4. public class FlatMesh {
  5. /*
  6. * Given a mesh (vertices, normals, triangles, and colors), calculates a new mesh with:
  7. * . Flat shaded triangles (splitting edges)
  8. * . Fake SSAO/Ambient Occlusion (with vertex colors)
  9. */
  10. // Properties
  11. private Vector3[] vertices;
  12. private Vector3[] normals;
  13. private int[] triangles;
  14. private Color32[] colors;
  15. private Vector3[] newVertices;
  16. private int[] newTriangles;
  17. private Vector2[] newUvs;
  18. private Color32[] newColors;
  19. private bool isMeshDirty; // If true, the mesh needs to be recalculated
  20. // ================================================================================================================
  21. // CONSTRUCTOR ----------------------------------------------------------------------------------------------------
  22. public FlatMesh(Vector3[] __vertices, Vector3[] __normals, int[] __triangles, Color32[] __colors) {
  23. D.Log("FlatMesh initialized; " + __vertices.Length + " vertices, " + (__triangles.Length/3) + " triangles, " + __colors.Length + " colors");
  24. vertices = __vertices;
  25. normals = __normals;
  26. triangles = __triangles;
  27. colors = __colors;
  28. isMeshDirty = true;
  29. }
  30. // ================================================================================================================
  31. // PUBLIC INTERFACE -----------------------------------------------------------------------------------------------
  32. public Vector3[] flatVertices {
  33. get {
  34. if (isMeshDirty) recalculateFlatMesh();
  35. return newVertices;
  36. }
  37. }
  38. public int[] flatTriangles {
  39. get {
  40. if (isMeshDirty) recalculateFlatMesh();
  41. return newTriangles;
  42. }
  43. }
  44. public Vector2[] flatUvs {
  45. get {
  46. if (isMeshDirty) recalculateFlatMesh();
  47. return newUvs;
  48. }
  49. }
  50. public Color32[] flatColors {
  51. get {
  52. if (isMeshDirty) recalculateFlatMesh();
  53. return newColors;
  54. }
  55. }
  56. // ================================================================================================================
  57. // INTERNAL INTERFACE ---------------------------------------------------------------------------------------------
  58. private void recalculateFlatMesh() {
  59. // Creates the new mesh
  60. int numTriangles = triangles.Length / 3;
  61. int numVertices = vertices.Length;
  62. int i, j, t;
  63. Vector3 v;
  64. //Vector3 n;
  65. Color32 c;
  66. // Calculates ambient occlusion
  67. float ti = Time.realtimeSinceStartup;
  68. // Finds darkness of every vertice
  69. float[] darkness = new float[numVertices]; // 0 (normal color) to 1 (black)
  70. // Creates ray samples
  71. int numSamples = 20;
  72. Vector3[] rotations = new Vector3[numSamples];
  73. Vector3 o;
  74. float radius = 400f;
  75. for (i = 0; i < numSamples; i++) {
  76. rotations[i] = UnityEngine.Random.onUnitSphere * radius;
  77. }
  78. List<Vector3> myRots;
  79. Vector3 v1xv2, v2xv3, v3xv1;
  80. Vector3 v1, v2, v3;
  81. for (i = 0; i < numVertices; i++) {
  82. // For every vertice...
  83. o = vertices[i] + normals[i];
  84. myRots = new List<Vector3>(rotations);
  85. for (t = 0; t < numTriangles * 3; t += 3) {
  86. // ...check every triangle...
  87. v1 = vertices[triangles[t]] - o;
  88. v2 = vertices[triangles[t+1]] - o;
  89. v3 = vertices[triangles[t+2]] - o;
  90. v1xv2 = Vector3.Cross(v1, v2);
  91. v2xv3 = Vector3.Cross(v2, v3);
  92. v3xv1 = Vector3.Cross(v3, v1);
  93. for (j = 0; j < myRots.Count; j++) {
  94. // ...against every ray
  95. if (GeomUtils.rayIntersectsTriangleSF_precalculated(o, myRots[j], v1xv2, v2xv3, v3xv1)) {
  96. myRots.RemoveAt(j);
  97. j--;
  98. }
  99. }
  100. }
  101. darkness[i] = Math.Abs(((float)(rotations.Length - myRots.Count) / numSamples - 0.5f) * 2f);
  102. //if (i % 100 == 0 || hits >= numSamples) {
  103. //if (i % 100 == 0) D.Log ("@" + i + " : " + o + " -> " + Vector3.back + " >> hits = " + hits + ", " + darkness[i]);
  104. }
  105. // Applies darkness to the vertex colors
  106. for (i = 0; i < numVertices; i++) {
  107. colors[i].r = (byte)(colors[i].r * (1-darkness[i]));
  108. colors[i].g = (byte)(colors[i].g * (1-darkness[i]));
  109. colors[i].b = (byte)(colors[i].b * (1-darkness[i]));
  110. //colors[i].r = (byte)Math.Max(0, colors[i].r - Math.Floor(darkness[i] * 255f));
  111. //colors[i].g = (byte)Math.Max(0, colors[i].g - Math.Floor(darkness[i] * 255f));
  112. //colors[i].b = (byte)Math.Max(0, colors[i].b - Math.Floor(darkness[i] * 255f));
  113. }
  114. D.Log("Took " + (Time.realtimeSinceStartup-ti) + "s to generate vertices ambient occlusion.");
  115. // Creates new properties
  116. newVertices = new Vector3[numTriangles * 3];
  117. newTriangles = new int[numTriangles * 3];
  118. newUvs = new Vector2[numTriangles * 3];
  119. newColors = new Color32[numTriangles * 3];
  120. // Splits edges
  121. for (i = 0; i < triangles.Length; i++) {
  122. v = vertices[triangles[i]];
  123. c = colors[triangles[i]];
  124. newVertices[i] = new Vector3(v.x, v.y, v.z);
  125. newTriangles[i] = i;
  126. newColors[i] = new Color32(c.r, c.g, c.b, c.a);
  127. }
  128. // Creates individual UVs
  129. float uvNudge = 17f/256f; // Offset so the triangle fits
  130. for (i = 0; i < triangles.Length; i += 3) {
  131. newUvs[i+0] = new Vector2(0, 0 + uvNudge);
  132. newUvs[i+1] = new Vector2(0.5f, 1 - uvNudge);
  133. newUvs[i+2] = new Vector2(1, 0 + uvNudge);
  134. }
  135. isMeshDirty = false;
  136. }
  137. }