MeshGenerator.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. using UnityEngine;
  2. public static class MeshGenerator
  3. {
  4. public static MeshData GenerateTerrainMesh(float[,] heightMap, float heightMultiplier, AnimationCurve _heightCurve, int levelOfDetail, bool useFlatShading)
  5. {
  6. AnimationCurve heightCurve = new AnimationCurve(_heightCurve.keys);
  7. int meshSimplificationIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2;
  8. int borderedSize = heightMap.GetLength(0);
  9. int meshSize = borderedSize - 2 * meshSimplificationIncrement;
  10. int meshSizeUnsimplified = borderedSize - 2;
  11. float topLeftX = (meshSizeUnsimplified - 1) / -2f;
  12. float topLeftZ = (meshSizeUnsimplified - 1) / 2f;
  13. int verticesPerLine = (meshSize - 1) / meshSimplificationIncrement + 1;
  14. MeshData meshData = new MeshData(verticesPerLine, useFlatShading);
  15. int[,] vertexIndicesMap = new int[borderedSize, borderedSize];
  16. int meshVertexIndex = 0;
  17. int borderVertexIndex = -1;
  18. for (int y = 0; y < borderedSize; y += meshSimplificationIncrement)
  19. {
  20. for (int x = 0; x < borderedSize; x += meshSimplificationIncrement)
  21. {
  22. bool isBorderVertex = y == 0 || y == borderedSize - 1 || x == 0 || x == borderedSize - 1;
  23. if (isBorderVertex)
  24. {
  25. vertexIndicesMap[x, y] = borderVertexIndex;
  26. borderVertexIndex--;
  27. }
  28. else
  29. {
  30. vertexIndicesMap[x, y] = meshVertexIndex;
  31. meshVertexIndex++;
  32. }
  33. }
  34. }
  35. for (int y = 0; y < borderedSize; y += meshSimplificationIncrement)
  36. {
  37. for(int x = 0; x < borderedSize; x += meshSimplificationIncrement)
  38. {
  39. int vertexIndex = vertexIndicesMap[x, y];
  40. Vector2 percent = new Vector2((x - meshSimplificationIncrement) / (float)meshSize, (y - meshSimplificationIncrement) / (float)meshSize);
  41. float height = heightCurve.Evaluate(heightMap[x, y]) * heightMultiplier;
  42. Vector3 vertexPosition = new Vector3(topLeftX + percent.x * meshSizeUnsimplified, height, topLeftZ - percent.y * meshSize);
  43. meshData.AddVertex(vertexPosition, percent, vertexIndex);
  44. if(x < borderedSize - 1 && y < borderedSize - 1)
  45. {
  46. int a = vertexIndicesMap[x, y];
  47. int b = vertexIndicesMap[x + meshSimplificationIncrement, y];
  48. int c = vertexIndicesMap[x, y + meshSimplificationIncrement];
  49. int d = vertexIndicesMap[x + meshSimplificationIncrement, y + meshSimplificationIncrement];
  50. meshData.AddTriangle(a,d,c);
  51. meshData.AddTriangle(d,a,b);
  52. }
  53. vertexIndex++;
  54. }
  55. }
  56. meshData.Finalize();
  57. return meshData;
  58. }
  59. }
  60. public class MeshData
  61. {
  62. public Vector3[] vertices;
  63. public int[] triangles;
  64. Vector2[] uvs;
  65. Vector3[] bakedNormals;
  66. Vector3[] borderVertices;
  67. int[] borderTriangles;
  68. int triangleIndex;
  69. int borderTriangleIndex;
  70. bool useFlatShading;
  71. public MeshData(int verticesPerLine, bool useFlatShading)
  72. {
  73. this.useFlatShading = useFlatShading;
  74. vertices = new Vector3[verticesPerLine * verticesPerLine];
  75. uvs = new Vector2[verticesPerLine * verticesPerLine];
  76. triangles = new int[(verticesPerLine-1) * (verticesPerLine-1) * 6];
  77. borderVertices = new Vector3[verticesPerLine * 4 + 4];
  78. borderTriangles = new int[24 * verticesPerLine];
  79. }
  80. public void AddVertex(Vector3 vertexPosition, Vector2 uv, int vertexIndex)
  81. {
  82. if(vertexIndex < 0)
  83. {
  84. borderVertices[-vertexIndex - 1] = vertexPosition;
  85. }
  86. else
  87. {
  88. vertices[vertexIndex] = vertexPosition;
  89. uvs[vertexIndex] = uv;
  90. }
  91. }
  92. public void AddTriangle(int a, int b, int c)
  93. {
  94. if(a < 0 || b < 0 || c < 0)
  95. {
  96. borderTriangles[borderTriangleIndex] = a;
  97. borderTriangles[borderTriangleIndex + 1] = b;
  98. borderTriangles[borderTriangleIndex + 2] = c;
  99. borderTriangleIndex += 3;
  100. }
  101. else
  102. {
  103. triangles[triangleIndex] = a;
  104. triangles[triangleIndex + 1] = b;
  105. triangles[triangleIndex + 2] = c;
  106. triangleIndex += 3;
  107. }
  108. }
  109. Vector3[] CalculateNormals()
  110. {
  111. Vector3[] vertexNormals = new Vector3[vertices.Length];
  112. int triangleCount = triangles.Length / 3;
  113. for (int i = 0; i < triangleCount; i++)
  114. {
  115. int normalTriangleIndex = i * 3;
  116. int vertexIndexA = triangles[normalTriangleIndex];
  117. int vertexIndexB = triangles[normalTriangleIndex + 1];
  118. int vertexIndexC = triangles[normalTriangleIndex + 2];
  119. Vector3 triangleNormal = SurfaceNormalFromIndices(vertexIndexA, vertexIndexB, vertexIndexC);
  120. vertexNormals[vertexIndexA] += triangleNormal;
  121. vertexNormals[vertexIndexB] += triangleNormal;
  122. vertexNormals[vertexIndexC] += triangleNormal;
  123. }
  124. int borderTriangleCount = borderTriangles.Length / 3;
  125. for (int i = 0; i < borderTriangleCount; i++)
  126. {
  127. int normalTriangleIndex = i * 3;
  128. int vertexIndexA = borderTriangles[normalTriangleIndex];
  129. int vertexIndexB = borderTriangles[normalTriangleIndex + 1];
  130. int vertexIndexC = borderTriangles[normalTriangleIndex + 2];
  131. Vector3 triangleNormal = SurfaceNormalFromIndices(vertexIndexA, vertexIndexB, vertexIndexC);
  132. if(vertexIndexA >= 0)
  133. {
  134. vertexNormals[vertexIndexA] += triangleNormal;
  135. }
  136. if (vertexIndexB >= 0)
  137. {
  138. vertexNormals[vertexIndexB] += triangleNormal;
  139. }
  140. if (vertexIndexC >= 0)
  141. {
  142. vertexNormals[vertexIndexC] += triangleNormal;
  143. }
  144. }
  145. for (int i = 0; i < vertexNormals.Length; i++)
  146. {
  147. vertexNormals[i].Normalize();
  148. }
  149. return vertexNormals;
  150. }
  151. Vector3 SurfaceNormalFromIndices(int indexA, int indexB, int indexC)
  152. {
  153. Vector3 pointA = (indexA < 0) ? borderVertices[-indexA-1] : vertices[indexA];
  154. Vector3 pointB = (indexB < 0) ? borderVertices[-indexB - 1] : vertices[indexB];
  155. Vector3 pointC = (indexC < 0) ? borderVertices[-indexC - 1] : vertices[indexC];
  156. Vector3 sideAB = pointB - pointA;
  157. Vector3 sideAC = pointC - pointA;
  158. return Vector3.Cross(sideAB, sideAC).normalized;
  159. }
  160. #pragma warning disable CS0465 // Introducing a 'Finalize' method can interfere with destructor invocation
  161. public void Finalize()
  162. #pragma warning restore CS0465 // Introducing a 'Finalize' method can interfere with destructor invocation
  163. {
  164. if (useFlatShading)
  165. {
  166. FlatShading();
  167. }
  168. else
  169. {
  170. BakeNormals();
  171. }
  172. }
  173. void BakeNormals()
  174. {
  175. bakedNormals = CalculateNormals();
  176. }
  177. void FlatShading()
  178. {
  179. Vector3[] flatShadedVertices = new Vector3[triangles.Length];
  180. Vector2[] flatShadedUvs = new Vector2[triangles.Length];
  181. for (int i = 0; i < triangles.Length; i++)
  182. {
  183. flatShadedVertices[i] = vertices[triangles[i]];
  184. flatShadedUvs[i] = uvs[triangles[i]];
  185. triangles[i] = i;
  186. }
  187. vertices = flatShadedVertices;
  188. uvs = flatShadedUvs;
  189. }
  190. public Mesh CreateMesh()
  191. {
  192. Mesh mesh = new Mesh();
  193. mesh.vertices = vertices;
  194. mesh.triangles = triangles;
  195. mesh.uv = uvs;
  196. if (useFlatShading)
  197. {
  198. mesh.RecalculateNormals();
  199. }
  200. else
  201. {
  202. mesh.normals = bakedNormals;
  203. }
  204. return mesh;
  205. }
  206. }