MeshGenerator.cs 6.3 KB

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