MeshGenerator.cs 7.7 KB

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