|
@@ -0,0 +1,211 @@
|
|
|
|
|
+using UnityEngine;
|
|
|
|
|
+using System.Collections;
|
|
|
|
|
+
|
|
|
|
|
+public static class MeshGenerator {
|
|
|
|
|
+
|
|
|
|
|
+ public static MeshData GenerateTerrainMesh(float[,] heightMap, float heightMultiplier, AnimationCurve _heightCurve, int levelOfDetail, bool useFlatShading) {
|
|
|
|
|
+ AnimationCurve heightCurve = new AnimationCurve (_heightCurve.keys);
|
|
|
|
|
+
|
|
|
|
|
+ int meshSimplificationIncrement = (levelOfDetail == 0)?1:levelOfDetail * 2;
|
|
|
|
|
+
|
|
|
|
|
+ int borderedSize = heightMap.GetLength (0);
|
|
|
|
|
+ int meshSize = borderedSize - 2*meshSimplificationIncrement;
|
|
|
|
|
+ int meshSizeUnsimplified = borderedSize - 2;
|
|
|
|
|
+
|
|
|
|
|
+ float topLeftX = (meshSizeUnsimplified - 1) / -2f;
|
|
|
|
|
+ float topLeftZ = (meshSizeUnsimplified - 1) / 2f;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ int verticesPerLine = (meshSize - 1) / meshSimplificationIncrement + 1;
|
|
|
|
|
+
|
|
|
|
|
+ MeshData meshData = new MeshData (verticesPerLine,useFlatShading);
|
|
|
|
|
+
|
|
|
|
|
+ int[,] vertexIndicesMap = new int[borderedSize,borderedSize];
|
|
|
|
|
+ int meshVertexIndex = 0;
|
|
|
|
|
+ int borderVertexIndex = -1;
|
|
|
|
|
+
|
|
|
|
|
+ for (int y = 0; y < borderedSize; y += meshSimplificationIncrement) {
|
|
|
|
|
+ for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) {
|
|
|
|
|
+ bool isBorderVertex = y == 0 || y == borderedSize - 1 || x == 0 || x == borderedSize - 1;
|
|
|
|
|
+
|
|
|
|
|
+ if (isBorderVertex) {
|
|
|
|
|
+ vertexIndicesMap [x, y] = borderVertexIndex;
|
|
|
|
|
+ borderVertexIndex--;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ vertexIndicesMap [x, y] = meshVertexIndex;
|
|
|
|
|
+ meshVertexIndex++;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for (int y = 0; y < borderedSize; y += meshSimplificationIncrement) {
|
|
|
|
|
+ for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) {
|
|
|
|
|
+ int vertexIndex = vertexIndicesMap [x, y];
|
|
|
|
|
+ Vector2 percent = new Vector2 ((x-meshSimplificationIncrement) / (float)meshSize, (y-meshSimplificationIncrement) / (float)meshSize);
|
|
|
|
|
+ float height = heightCurve.Evaluate (heightMap [x, y]) * heightMultiplier;
|
|
|
|
|
+ Vector3 vertexPosition = new Vector3 (topLeftX + percent.x * meshSizeUnsimplified, height, topLeftZ - percent.y * meshSizeUnsimplified);
|
|
|
|
|
+
|
|
|
|
|
+ meshData.AddVertex (vertexPosition, percent, vertexIndex);
|
|
|
|
|
+
|
|
|
|
|
+ if (x < borderedSize - 1 && y < borderedSize - 1) {
|
|
|
|
|
+ int a = vertexIndicesMap [x, y];
|
|
|
|
|
+ int b = vertexIndicesMap [x + meshSimplificationIncrement, y];
|
|
|
|
|
+ int c = vertexIndicesMap [x, y + meshSimplificationIncrement];
|
|
|
|
|
+ int d = vertexIndicesMap [x + meshSimplificationIncrement, y + meshSimplificationIncrement];
|
|
|
|
|
+ meshData.AddTriangle (a,d,c);
|
|
|
|
|
+ meshData.AddTriangle (d,a,b);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ vertexIndex++;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ meshData.ProcessMesh ();
|
|
|
|
|
+
|
|
|
|
|
+ return meshData;
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+public class MeshData {
|
|
|
|
|
+ Vector3[] vertices;
|
|
|
|
|
+ int[] triangles;
|
|
|
|
|
+ Vector2[] uvs;
|
|
|
|
|
+ Vector3[] bakedNormals;
|
|
|
|
|
+
|
|
|
|
|
+ Vector3[] borderVertices;
|
|
|
|
|
+ int[] borderTriangles;
|
|
|
|
|
+
|
|
|
|
|
+ int triangleIndex;
|
|
|
|
|
+ int borderTriangleIndex;
|
|
|
|
|
+
|
|
|
|
|
+ bool useFlatShading;
|
|
|
|
|
+
|
|
|
|
|
+ public MeshData(int verticesPerLine, bool useFlatShading) {
|
|
|
|
|
+ this.useFlatShading = useFlatShading;
|
|
|
|
|
+
|
|
|
|
|
+ vertices = new Vector3[verticesPerLine * verticesPerLine];
|
|
|
|
|
+ uvs = new Vector2[verticesPerLine * verticesPerLine];
|
|
|
|
|
+ triangles = new int[(verticesPerLine-1)*(verticesPerLine-1)*6];
|
|
|
|
|
+
|
|
|
|
|
+ borderVertices = new Vector3[verticesPerLine * 4 + 4];
|
|
|
|
|
+ borderTriangles = new int[24 * verticesPerLine];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void AddVertex(Vector3 vertexPosition, Vector2 uv, int vertexIndex) {
|
|
|
|
|
+ if (vertexIndex < 0) {
|
|
|
|
|
+ borderVertices [-vertexIndex - 1] = vertexPosition;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ vertices [vertexIndex] = vertexPosition;
|
|
|
|
|
+ uvs [vertexIndex] = uv;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void AddTriangle(int a, int b, int c) {
|
|
|
|
|
+ if (a < 0 || b < 0 || c < 0) {
|
|
|
|
|
+ borderTriangles [borderTriangleIndex] = a;
|
|
|
|
|
+ borderTriangles [borderTriangleIndex + 1] = b;
|
|
|
|
|
+ borderTriangles [borderTriangleIndex + 2] = c;
|
|
|
|
|
+ borderTriangleIndex += 3;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ triangles [triangleIndex] = a;
|
|
|
|
|
+ triangles [triangleIndex + 1] = b;
|
|
|
|
|
+ triangles [triangleIndex + 2] = c;
|
|
|
|
|
+ triangleIndex += 3;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Vector3[] CalculateNormals() {
|
|
|
|
|
+
|
|
|
|
|
+ Vector3[] vertexNormals = new Vector3[vertices.Length];
|
|
|
|
|
+ int triangleCount = triangles.Length / 3;
|
|
|
|
|
+ for (int i = 0; i < triangleCount; i++) {
|
|
|
|
|
+ int normalTriangleIndex = i * 3;
|
|
|
|
|
+ int vertexIndexA = triangles [normalTriangleIndex];
|
|
|
|
|
+ int vertexIndexB = triangles [normalTriangleIndex + 1];
|
|
|
|
|
+ int vertexIndexC = triangles [normalTriangleIndex + 2];
|
|
|
|
|
+
|
|
|
|
|
+ Vector3 triangleNormal = SurfaceNormalFromIndices (vertexIndexA, vertexIndexB, vertexIndexC);
|
|
|
|
|
+ vertexNormals [vertexIndexA] += triangleNormal;
|
|
|
|
|
+ vertexNormals [vertexIndexB] += triangleNormal;
|
|
|
|
|
+ vertexNormals [vertexIndexC] += triangleNormal;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ int borderTriangleCount = borderTriangles.Length / 3;
|
|
|
|
|
+ for (int i = 0; i < borderTriangleCount; i++) {
|
|
|
|
|
+ int normalTriangleIndex = i * 3;
|
|
|
|
|
+ int vertexIndexA = borderTriangles [normalTriangleIndex];
|
|
|
|
|
+ int vertexIndexB = borderTriangles [normalTriangleIndex + 1];
|
|
|
|
|
+ int vertexIndexC = borderTriangles [normalTriangleIndex + 2];
|
|
|
|
|
+
|
|
|
|
|
+ Vector3 triangleNormal = SurfaceNormalFromIndices (vertexIndexA, vertexIndexB, vertexIndexC);
|
|
|
|
|
+ if (vertexIndexA >= 0) {
|
|
|
|
|
+ vertexNormals [vertexIndexA] += triangleNormal;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (vertexIndexB >= 0) {
|
|
|
|
|
+ vertexNormals [vertexIndexB] += triangleNormal;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (vertexIndexC >= 0) {
|
|
|
|
|
+ vertexNormals [vertexIndexC] += triangleNormal;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ for (int i = 0; i < vertexNormals.Length; i++) {
|
|
|
|
|
+ vertexNormals [i].Normalize ();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return vertexNormals;
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Vector3 SurfaceNormalFromIndices(int indexA, int indexB, int indexC) {
|
|
|
|
|
+ Vector3 pointA = (indexA < 0)?borderVertices[-indexA-1] : vertices [indexA];
|
|
|
|
|
+ Vector3 pointB = (indexB < 0)?borderVertices[-indexB-1] : vertices [indexB];
|
|
|
|
|
+ Vector3 pointC = (indexC < 0)?borderVertices[-indexC-1] : vertices [indexC];
|
|
|
|
|
+
|
|
|
|
|
+ Vector3 sideAB = pointB - pointA;
|
|
|
|
|
+ Vector3 sideAC = pointC - pointA;
|
|
|
|
|
+ return Vector3.Cross (sideAB, sideAC).normalized;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void ProcessMesh() {
|
|
|
|
|
+ if (useFlatShading) {
|
|
|
|
|
+ FlatShading ();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ BakeNormals ();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void BakeNormals() {
|
|
|
|
|
+ bakedNormals = CalculateNormals ();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void FlatShading() {
|
|
|
|
|
+ Vector3[] flatShadedVertices = new Vector3[triangles.Length];
|
|
|
|
|
+ Vector2[] flatShadedUvs = new Vector2[triangles.Length];
|
|
|
|
|
+
|
|
|
|
|
+ for (int i = 0; i < triangles.Length; i++) {
|
|
|
|
|
+ flatShadedVertices [i] = vertices [triangles [i]];
|
|
|
|
|
+ flatShadedUvs [i] = uvs [triangles [i]];
|
|
|
|
|
+ triangles [i] = i;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ vertices = flatShadedVertices;
|
|
|
|
|
+ uvs = flatShadedUvs;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public Mesh CreateMesh() {
|
|
|
|
|
+ Mesh mesh = new Mesh ();
|
|
|
|
|
+ mesh.vertices = vertices;
|
|
|
|
|
+ mesh.triangles = triangles;
|
|
|
|
|
+ mesh.uv = uvs;
|
|
|
|
|
+ if (useFlatShading) {
|
|
|
|
|
+ mesh.RecalculateNormals ();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ mesh.normals = bakedNormals;
|
|
|
|
|
+ }
|
|
|
|
|
+ return mesh;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+}
|