MeshGenerator.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. using System.Collections;
  2. using UnityEngine;
  3. using static UnityEditor.PlayerSettings;
  4. public static class MeshGenerator
  5. {
  6. public static MeshData GenerateTerrainMesh(float[,] heightMap, float heightMultiplier, AnimationCurve _heightCurve, int levelOfDetail, bool useFlatShading)
  7. {
  8. AnimationCurve heightCurve = new AnimationCurve(_heightCurve.keys);
  9. int meshSimplificationIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2;
  10. int borderedSize = heightMap.GetLength(0);
  11. int meshSize = borderedSize - 2 * meshSimplificationIncrement;
  12. int meshSizeUnsimplified = borderedSize - 2;
  13. float topLeftX = (meshSizeUnsimplified - 1) / -2f;
  14. float topLeftZ = (meshSizeUnsimplified - 1) / 2f;
  15. int verticesPerLine = (meshSize - 1) / meshSimplificationIncrement + 1;
  16. MeshData meshData = new MeshData(verticesPerLine, useFlatShading);
  17. int[,] vertexIndicesMap = new int[borderedSize, borderedSize];
  18. int meshVertexIndex = 0;
  19. int borderVertexIndex = -1;
  20. for (int y = 0; y < borderedSize; y += meshSimplificationIncrement)
  21. {
  22. for (int x = 0; x < borderedSize; x += meshSimplificationIncrement)
  23. {
  24. bool isBorderVertex = y == 0 || y == borderedSize - 1 || x == 0 || x == borderedSize - 1;
  25. if (isBorderVertex)
  26. {
  27. vertexIndicesMap[x, y] = borderVertexIndex;
  28. borderVertexIndex--;
  29. }
  30. else
  31. {
  32. vertexIndicesMap[x, y] = meshVertexIndex;
  33. meshVertexIndex++;
  34. }
  35. }
  36. }
  37. for (int y = 0; y < borderedSize; y += meshSimplificationIncrement)
  38. {
  39. for (int x = 0; x < borderedSize; x += meshSimplificationIncrement)
  40. {
  41. int vertexIndex = vertexIndicesMap[x, y];
  42. Vector2 percent = new Vector2((x - meshSimplificationIncrement) / (float)meshSize, (y - meshSimplificationIncrement) / (float)meshSize);
  43. float height = heightCurve.Evaluate(heightMap[x, y]) * heightMultiplier;
  44. Vector3 vertexPosition = new Vector3(topLeftX + percent.x * meshSizeUnsimplified, height, topLeftZ - percent.y * meshSizeUnsimplified);
  45. meshData.AddVertex(vertexPosition, percent, vertexIndex);
  46. if (x < borderedSize - 1 && y < borderedSize - 1)
  47. {
  48. int a = vertexIndicesMap[x, y];
  49. int b = vertexIndicesMap[x + meshSimplificationIncrement, y];
  50. int c = vertexIndicesMap[x, y + meshSimplificationIncrement];
  51. int d = vertexIndicesMap[x + meshSimplificationIncrement, y + meshSimplificationIncrement];
  52. meshData.AddTriangle(a, d, c);
  53. meshData.AddTriangle(d, a, b);
  54. }
  55. vertexIndex++;
  56. }
  57. }
  58. meshData.Finish();
  59. return meshData;
  60. }
  61. }
  62. public class MeshData
  63. {
  64. Vector3[] vertices;
  65. int[] triangles;
  66. Vector2[] uvs;
  67. Vector3[] bakedNormals;
  68. Vector3[] borderVertices;
  69. int[] borderTriangles;
  70. int triangleIndex;
  71. int borderTriangleIndex;
  72. bool useFlatShading;
  73. public MeshData(int verticesPerLine, bool useFlatShading)
  74. {
  75. this.useFlatShading = useFlatShading;
  76. vertices = new Vector3[verticesPerLine * verticesPerLine];
  77. uvs = new Vector2[verticesPerLine * verticesPerLine];
  78. triangles = new int[(verticesPerLine - 1) * (verticesPerLine - 1) * 6];
  79. borderVertices = new Vector3[verticesPerLine * 4 + 4];
  80. borderTriangles = new int[24 * verticesPerLine];
  81. }
  82. public void AddVertex(Vector3 vertexPosition, Vector2 uv, int vertexIndex)
  83. {
  84. if (vertexIndex < 0)
  85. {
  86. borderVertices[-vertexIndex - 1] = vertexPosition;
  87. }
  88. else
  89. {
  90. vertices[vertexIndex] = vertexPosition;
  91. uvs[vertexIndex] = uv;
  92. }
  93. }
  94. public void AddTriangle(int a, int b, int c)
  95. {
  96. if (a < 0 || b < 0 || c < 0)
  97. {
  98. borderTriangles[borderTriangleIndex] = a;
  99. borderTriangles[borderTriangleIndex + 1] = b;
  100. borderTriangles[borderTriangleIndex + 2] = c;
  101. borderTriangleIndex += 3;
  102. }
  103. else
  104. {
  105. triangles[triangleIndex] = a;
  106. triangles[triangleIndex + 1] = b;
  107. triangles[triangleIndex + 2] = c;
  108. triangleIndex += 3;
  109. }
  110. }
  111. Vector3[] CalculateNormals()
  112. {
  113. Vector3[] vertexNormals = new Vector3[vertices.Length];
  114. int triangleCount = triangles.Length / 3;
  115. for (int i = 0; i < triangleCount; i++)
  116. {
  117. int normalTriangleIndex = i * 3;
  118. int vertexIndexA = triangles[normalTriangleIndex];
  119. int vertexIndexB = triangles[normalTriangleIndex + 1];
  120. int vertexIndexC = triangles[normalTriangleIndex + 2];
  121. Vector3 triangleNormal = SurfaceNormalFromIndices(vertexIndexA, vertexIndexB, vertexIndexC);
  122. vertexNormals[vertexIndexA] += triangleNormal;
  123. vertexNormals[vertexIndexB] += triangleNormal;
  124. vertexNormals[vertexIndexC] += triangleNormal;
  125. }
  126. int borderTriangleCount = borderTriangles.Length / 3;
  127. for (int i = 0; i < borderTriangleCount; i++)
  128. {
  129. int normalTriangleIndex = i * 3;
  130. int vertexIndexA = borderTriangles[normalTriangleIndex];
  131. int vertexIndexB = borderTriangles[normalTriangleIndex + 1];
  132. int vertexIndexC = borderTriangles[normalTriangleIndex + 2];
  133. Vector3 triangleNormal = SurfaceNormalFromIndices(vertexIndexA, vertexIndexB, vertexIndexC);
  134. if (vertexIndexA >= 0)
  135. {
  136. vertexNormals[vertexIndexA] += triangleNormal;
  137. }
  138. if (vertexIndexB >= 0)
  139. {
  140. vertexNormals[vertexIndexB] += triangleNormal;
  141. }
  142. if (vertexIndexC >= 0)
  143. {
  144. vertexNormals[vertexIndexC] += triangleNormal;
  145. }
  146. }
  147. for (int i = 0; i < vertexNormals.Length; i++)
  148. {
  149. vertexNormals[i].Normalize();
  150. }
  151. return vertexNormals;
  152. }
  153. Vector3 SurfaceNormalFromIndices(int indexA, int indexB, int indexC)
  154. {
  155. Vector3 pointA = (indexA < 0) ? borderVertices[-indexA - 1] : vertices[indexA];
  156. Vector3 pointB = (indexB < 0) ? borderVertices[-indexB - 1] : vertices[indexB];
  157. Vector3 pointC = (indexC < 0) ? borderVertices[-indexC - 1] : vertices[indexC];
  158. Vector3 sideAB = pointB - pointA;
  159. Vector3 sideAC = pointC - pointA;
  160. return Vector3.Cross(sideAB, sideAC).normalized;
  161. }
  162. public void Finish()
  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. }