Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using TriangleNet.Geometry;
- using TriangleNet.Meshing;
- using TriangleNet.Topology;
- using UnityEngine;
- [RequireComponent(typeof(MeshRenderer), typeof(MeshFilter), typeof(MeshCollider))]
- public class TerrainGenerator : MonoBehaviour
- {
- public Gradient heightGradient = new Gradient()
- {
- colorKeys = new GradientColorKey[] {
- new GradientColorKey(new Color(0.03f, 0.2f , 0.9f), 0.0f),
- new GradientColorKey(new Color(0.055f, 0.53f , 0.9f), 0.35f),
- new GradientColorKey(new Color(0.135f, 0.95f, 0.95f), 0.42f),
- new GradientColorKey(new Color(0.75f, 0.75f, 0.47f), 0.55f),
- new GradientColorKey(new Color(0.27f, 0.50f, 0.135f), 0.60f),
- new GradientColorKey(new Color(0.05f, 0.19f, 0.02f), 0.85f),
- new GradientColorKey(new Color(0.42f, 0.41f, 0.4f), 0.95f),
- new GradientColorKey(new Color(1, 1, 1), 1.0f)
- },
- alphaKeys = new GradientAlphaKey[2] {
- new GradientAlphaKey(1, 0),
- new GradientAlphaKey(1, 1)
- }
- };
- [Header("Scale")]
- public Vector2 dimensions = Vector2.one * 5;
- public float minDistanceBetweenVerts = 0.2f;
- [Header("Noise")]
- public int octaves = 2;
- public float scale = 2f;
- public long seed;
- public Vector2 offset;
- [Header("Features")]
- [Range(0f, 2f)] public float persistance = 0.2f;
- [Range(0f, 10f)] public float lacunarity = 2f;
- [Header("Height")]
- public float heightScale = 2;
- public float dampening = 1f;
- public float waterFlatteningFactor = 10f;
- private MeshFilter meshFilter;
- private MeshCollider meshCollider;
- private Polygon polygon;
- private TriangleNet.Mesh tMesh;
- private UnityEngine.Mesh mesh;
- private float[] heights;
- private float minNoiseHeight;
- private float maxNoiseHeight;
- private float seedConst;
- #region It's here for fun purposes. Unusable in realtime.
- public float scrollSpeed = 0.0f;
- private void Update()
- {
- if (scrollSpeed > 0f)
- {
- offset += scrollSpeed * Time.deltaTime * Vector2.one;
- GenerateTerrain();
- }
- }
- #endregion
- private void OnValidate()
- {
- seedConst = minDistanceBetweenVerts * 1337;
- if (heightScale == 0)
- heightScale = 0.001f;
- GenerateTerrain();
- }
- public void GenerateTerrain()
- {
- GeneratePoints();
- GenerateHeights();
- GenerateMesh();
- meshFilter = GetComponent<MeshFilter>();
- meshFilter.mesh = mesh;
- meshCollider = GetComponent<MeshCollider>();
- meshCollider.sharedMesh = mesh;
- }
- private void GeneratePoints()
- {
- polygon = new Polygon();
- List<Vector2> points = PoissonDiscSampling.GeneratePoints(minDistanceBetweenVerts, dimensions);
- points.ForEach(p => polygon.Add(new Vertex(p.x, p.y)));
- var constraint = new ConstraintOptions
- {
- ConformingDelaunay = true
- };
- tMesh = (TriangleNet.Mesh)polygon.Triangulate(constraint);
- }
- private void GenerateHeights()
- {
- minNoiseHeight = float.PositiveInfinity;
- maxNoiseHeight = float.NegativeInfinity;
- heights = new float[tMesh.vertices.Count];
- for (int i = 0; i < tMesh.vertices.Count; i++)
- {
- float amplitude = 1f;
- float frequency = 1f;
- float noiseHeight = 0f;
- for (int j = 0; j < octaves; j++)
- {
- float xValue = (float)tMesh.vertices[i].x / scale * frequency;
- float yValue = (float)tMesh.vertices[i].y / scale * frequency;
- float perlinValue = Mathf.PerlinNoise(xValue + offset.x + (seed * seedConst), yValue + offset.y + (seed * seedConst)) * 2 - 1;
- perlinValue *= dampening;
- noiseHeight += perlinValue * amplitude;
- amplitude *= persistance;
- frequency *= lacunarity;
- }
- maxNoiseHeight = Math.Max(noiseHeight, maxNoiseHeight);
- minNoiseHeight = Math.Min(noiseHeight, minNoiseHeight);
- noiseHeight = (noiseHeight < 0f) ? noiseHeight * heightScale / waterFlatteningFactor : noiseHeight * heightScale;
- heights[i] = noiseHeight;
- }
- }
- private void GenerateMesh()
- {
- var verts = new List<Vector3>();
- var normals = new List<Vector3>();
- var uvs = new List<Vector2>();
- var tris = new List<int>();
- var colors = new List<Color>();
- IEnumerator<Triangle> enumerator = tMesh.Triangles.GetEnumerator();
- for (int i = 0; i < tMesh.Triangles.Count; i++)
- {
- if (!enumerator.MoveNext())
- {
- break;
- }
- Triangle triangle = enumerator.Current;
- Vector3 v0 = new Vector3((float)triangle.vertices[2].x, heights[triangle.vertices[2].id], (float)triangle.vertices[2].y);
- Vector3 v1 = new Vector3((float)triangle.vertices[1].x, heights[triangle.vertices[1].id], (float)triangle.vertices[1].y);
- Vector3 v2 = new Vector3((float)triangle.vertices[0].x, heights[triangle.vertices[0].id], (float)triangle.vertices[0].y);
- tris.Add(verts.Count);
- tris.Add(verts.Count + 1);
- tris.Add(verts.Count + 2);
- verts.Add(v0);
- verts.Add(v1);
- verts.Add(v2);
- colors.Add(EvaluateColor(v0.y));
- colors.Add(EvaluateColor(v1.y));
- colors.Add(EvaluateColor(v2.y));
- Vector3 normal = Vector3.Cross(v1 - v0, v2 - v0);
- for (int j = 0; j < 3; j++)
- {
- normals.Add(normal);
- uvs.Add(new Vector2((verts[i * 3 + j].x / dimensions.x), (verts[i * 3 + j].z / dimensions.y)));
- }
- }
- // Center verts to gameObject center.
- Matrix4x4 matrix = Matrix4x4.Translate(new Vector3(-dimensions.x / 2, 0, -dimensions.y / 2));
- for (int i = 0; i < verts.Count; i++)
- {
- verts[i] = matrix.MultiplyPoint3x4(verts[i]);
- }
- if (verts.Count >= 65535)
- {
- Debug.LogWarning($"Too many vertices, terrain mesh will be deformed (verts: {verts.Count}/65535)");
- }
- mesh = new Mesh()
- {
- vertices = verts.ToArray(),
- normals = normals.ToArray(),
- uv = uvs.ToArray(),
- triangles = tris.ToArray(),
- colors = colors.ToArray()
- };
- }
- public Color EvaluateColor(Triangle triangle)
- {
- float currentHeight = (heights[triangle.vertices[0].id] + heights[triangle.vertices[1].id] + heights[triangle.vertices[2].id]) / 3f;
- currentHeight = (currentHeight < 0f) ? currentHeight / heightScale * waterFlatteningFactor : currentHeight / heightScale;
- return heightGradient.Evaluate(Mathf.InverseLerp(minNoiseHeight, maxNoiseHeight, currentHeight));
- }
- public Color EvaluateColor(float height)
- {
- height = (height < 0f) ? height / heightScale * waterFlatteningFactor : height / heightScale;
- return heightGradient.Evaluate(Mathf.InverseLerp(minNoiseHeight, maxNoiseHeight, height));
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement