|
|
@@ -1,34 +1,69 @@
|
|
|
-using JetBrains.Annotations;
|
|
|
using UnityEngine;
|
|
|
+using System.Collections;
|
|
|
|
|
|
public static class MeshGenerator
|
|
|
{
|
|
|
+
|
|
|
public static MeshData GenerateTerrainMesh(float[,] heightMap, float heightMultiplier, AnimationCurve _heightCurve, int levelOfDetail)
|
|
|
{
|
|
|
AnimationCurve heightCurve = new AnimationCurve(_heightCurve.keys);
|
|
|
-
|
|
|
- int width = heightMap.GetLength(0);
|
|
|
- int height = heightMap.GetLength(1);
|
|
|
- float topLeftX = (width - 1) / -2f;
|
|
|
- float topLeftZ = (height - 1) / 2f;
|
|
|
|
|
|
- int meshSimplficationIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2;
|
|
|
- int verticesPerLine = (width - 1) / meshSimplficationIncrement + 1;
|
|
|
+ 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;
|
|
|
+
|
|
|
|
|
|
- MeshData meshData = new(verticesPerLine, verticesPerLine);
|
|
|
- int vertexIndex = 0;
|
|
|
+ int verticesPerLine = (meshSize - 1) / meshSimplificationIncrement + 1;
|
|
|
+
|
|
|
+ MeshData meshData = new MeshData(verticesPerLine);
|
|
|
+
|
|
|
+ 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<height; y += meshSimplficationIncrement)
|
|
|
+ for (int y = 0; y < borderedSize; y += meshSimplificationIncrement)
|
|
|
{
|
|
|
- for(int x=0; x<width; x += meshSimplficationIncrement)
|
|
|
+ for (int x = 0; x < borderedSize; x += meshSimplificationIncrement)
|
|
|
{
|
|
|
- meshData.vertices[vertexIndex] = new Vector3(topLeftX + x, heightCurve.Evaluate(heightMap[x, y]) * heightMultiplier, topLeftZ - y);
|
|
|
- meshData.uvs[vertexIndex] = new Vector2(x/(float)width, y/(float)height);
|
|
|
+ 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 < width - 1 && y < height - 1)
|
|
|
+ if (x < borderedSize - 1 && y < borderedSize - 1)
|
|
|
{
|
|
|
- meshData.AddTriangle(vertexIndex, vertexIndex + verticesPerLine + 1, vertexIndex + verticesPerLine);
|
|
|
- meshData.AddTriangle(vertexIndex + verticesPerLine + 1, vertexIndex, vertexIndex + 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++;
|
|
|
@@ -36,41 +71,133 @@ public static class MeshGenerator
|
|
|
}
|
|
|
|
|
|
return meshData;
|
|
|
+
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public class MeshData
|
|
|
{
|
|
|
- public Vector3[] vertices;
|
|
|
- public int[] triangles;
|
|
|
- public Vector2[] uvs;
|
|
|
+ Vector3[] vertices;
|
|
|
+ int[] triangles;
|
|
|
+ Vector2[] uvs;
|
|
|
+
|
|
|
+ Vector3[] borderVertices;
|
|
|
+ int[] borderTriangles;
|
|
|
|
|
|
int triangleIndex;
|
|
|
+ int borderTriangleIndex;
|
|
|
|
|
|
- public MeshData(int meshWidth, int meshHeight)
|
|
|
+ public MeshData(int verticesPerLine)
|
|
|
{
|
|
|
- vertices = new Vector3[meshWidth * meshHeight];
|
|
|
- uvs = new Vector2[meshWidth * meshHeight];
|
|
|
- triangles = new int[(meshWidth - 1) * (meshHeight - 1) * 6];
|
|
|
+ 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)
|
|
|
{
|
|
|
- triangles[triangleIndex] = a;
|
|
|
- triangles[triangleIndex+1] = b;
|
|
|
- triangles[triangleIndex+2] = 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];
|
|
|
|
|
|
- triangleIndex += 3;
|
|
|
+ Vector3 sideAB = pointB - pointA;
|
|
|
+ Vector3 sideAC = pointC - pointA;
|
|
|
+ return Vector3.Cross(sideAB, sideAC).normalized;
|
|
|
}
|
|
|
|
|
|
public Mesh CreateMesh()
|
|
|
{
|
|
|
- Mesh mesh = new();
|
|
|
+ Mesh mesh = new Mesh();
|
|
|
mesh.vertices = vertices;
|
|
|
mesh.triangles = triangles;
|
|
|
mesh.uv = uvs;
|
|
|
- mesh.RecalculateNormals();
|
|
|
-
|
|
|
+ mesh.normals = CalculateNormals();
|
|
|
return mesh;
|
|
|
}
|
|
|
-}
|
|
|
+
|
|
|
+}
|