Advertisement
Guest User

TerrainGenerator.cs

a guest
Aug 22nd, 2021
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 7.37 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using TriangleNet.Geometry;
  4. using TriangleNet.Meshing;
  5. using TriangleNet.Topology;
  6. using UnityEngine;
  7.  
  8. [RequireComponent(typeof(MeshRenderer), typeof(MeshFilter), typeof(MeshCollider))]
  9. public class TerrainGenerator : MonoBehaviour
  10. {
  11.     public Gradient heightGradient = new Gradient()
  12.     {
  13.         colorKeys = new GradientColorKey[] {
  14.             new GradientColorKey(new Color(0.03f, 0.2f , 0.9f), 0.0f),
  15.             new GradientColorKey(new Color(0.055f, 0.53f , 0.9f), 0.35f),
  16.             new GradientColorKey(new Color(0.135f, 0.95f, 0.95f), 0.42f),
  17.             new GradientColorKey(new Color(0.75f, 0.75f, 0.47f), 0.55f),
  18.             new GradientColorKey(new Color(0.27f, 0.50f, 0.135f), 0.60f),
  19.             new GradientColorKey(new Color(0.05f, 0.19f, 0.02f), 0.85f),
  20.             new GradientColorKey(new Color(0.42f, 0.41f, 0.4f), 0.95f),
  21.             new GradientColorKey(new Color(1, 1, 1), 1.0f)
  22.         },
  23.         alphaKeys = new GradientAlphaKey[2] {
  24.             new GradientAlphaKey(1, 0),
  25.             new GradientAlphaKey(1, 1)
  26.         }
  27.     };
  28.  
  29.     [Header("Scale")]
  30.     public Vector2 dimensions = Vector2.one * 5;
  31.     public float minDistanceBetweenVerts = 0.2f;
  32.  
  33.     [Header("Noise")]
  34.     public int octaves = 2;
  35.     public float scale = 2f;
  36.     public long seed;
  37.     public Vector2 offset;
  38.  
  39.     [Header("Features")]
  40.     [Range(0f, 2f)] public float persistance = 0.2f;
  41.     [Range(0f, 10f)] public float lacunarity = 2f;
  42.  
  43.     [Header("Height")]
  44.     public float heightScale = 2;
  45.     public float dampening = 1f;
  46.     public float waterFlatteningFactor = 10f;
  47.  
  48.     private MeshFilter meshFilter;
  49.     private MeshCollider meshCollider;
  50.  
  51.     private Polygon polygon;
  52.     private TriangleNet.Mesh tMesh;
  53.     private UnityEngine.Mesh mesh;
  54.  
  55.     private float[] heights;
  56.     private float minNoiseHeight;
  57.     private float maxNoiseHeight;
  58.  
  59.     private float seedConst;
  60.  
  61.     #region It's here for fun purposes. Unusable in realtime.
  62.     public float scrollSpeed = 0.0f;
  63.  
  64.     private void Update()
  65.     {
  66.         if (scrollSpeed > 0f)
  67.         {
  68.             offset += scrollSpeed * Time.deltaTime * Vector2.one;
  69.             GenerateTerrain();
  70.         }
  71.     }
  72.     #endregion
  73.  
  74.     private void OnValidate()
  75.     {
  76.         seedConst = minDistanceBetweenVerts * 1337;
  77.         if (heightScale == 0)
  78.             heightScale = 0.001f;
  79.         GenerateTerrain();
  80.     }
  81.  
  82.     public void GenerateTerrain()
  83.     {
  84.         GeneratePoints();
  85.         GenerateHeights();
  86.         GenerateMesh();
  87.  
  88.         meshFilter = GetComponent<MeshFilter>();
  89.         meshFilter.mesh = mesh;
  90.  
  91.         meshCollider = GetComponent<MeshCollider>();
  92.         meshCollider.sharedMesh = mesh;
  93.     }
  94.  
  95.     private void GeneratePoints()
  96.     {
  97.         polygon = new Polygon();
  98.  
  99.         List<Vector2> points = PoissonDiscSampling.GeneratePoints(minDistanceBetweenVerts, dimensions);
  100.         points.ForEach(p => polygon.Add(new Vertex(p.x, p.y)));
  101.  
  102.         var constraint = new ConstraintOptions
  103.         {
  104.             ConformingDelaunay = true
  105.         };
  106.  
  107.         tMesh = (TriangleNet.Mesh)polygon.Triangulate(constraint);
  108.     }
  109.  
  110.     private void GenerateHeights()
  111.     {
  112.         minNoiseHeight = float.PositiveInfinity;
  113.         maxNoiseHeight = float.NegativeInfinity;
  114.  
  115.         heights = new float[tMesh.vertices.Count];
  116.         for (int i = 0; i < tMesh.vertices.Count; i++)
  117.         {
  118.             float amplitude = 1f;
  119.             float frequency = 1f;
  120.             float noiseHeight = 0f;
  121.  
  122.             for (int j = 0; j < octaves; j++)
  123.             {
  124.                 float xValue = (float)tMesh.vertices[i].x / scale * frequency;
  125.                 float yValue = (float)tMesh.vertices[i].y / scale * frequency;
  126.  
  127.                 float perlinValue = Mathf.PerlinNoise(xValue + offset.x + (seed * seedConst), yValue + offset.y + (seed * seedConst)) * 2 - 1;
  128.                 perlinValue *= dampening;
  129.  
  130.                 noiseHeight += perlinValue * amplitude;
  131.  
  132.                 amplitude *= persistance;
  133.                 frequency *= lacunarity;
  134.             }
  135.  
  136.             maxNoiseHeight = Math.Max(noiseHeight, maxNoiseHeight);
  137.             minNoiseHeight = Math.Min(noiseHeight, minNoiseHeight);
  138.  
  139.             noiseHeight = (noiseHeight < 0f) ? noiseHeight * heightScale / waterFlatteningFactor : noiseHeight * heightScale;
  140.  
  141.             heights[i] = noiseHeight;
  142.         }
  143.     }
  144.  
  145.     private void GenerateMesh()
  146.     {
  147.         var verts = new List<Vector3>();
  148.         var normals = new List<Vector3>();
  149.         var uvs = new List<Vector2>();
  150.         var tris = new List<int>();
  151.         var colors = new List<Color>();
  152.  
  153.         IEnumerator<Triangle> enumerator = tMesh.Triangles.GetEnumerator();
  154.  
  155.         for (int i = 0; i < tMesh.Triangles.Count; i++)
  156.         {
  157.             if (!enumerator.MoveNext())
  158.             {
  159.                 break;
  160.             }
  161.  
  162.             Triangle triangle = enumerator.Current;
  163.  
  164.             Vector3 v0 = new Vector3((float)triangle.vertices[2].x, heights[triangle.vertices[2].id], (float)triangle.vertices[2].y);
  165.             Vector3 v1 = new Vector3((float)triangle.vertices[1].x, heights[triangle.vertices[1].id], (float)triangle.vertices[1].y);
  166.             Vector3 v2 = new Vector3((float)triangle.vertices[0].x, heights[triangle.vertices[0].id], (float)triangle.vertices[0].y);
  167.  
  168.             tris.Add(verts.Count);
  169.             tris.Add(verts.Count + 1);
  170.             tris.Add(verts.Count + 2);
  171.  
  172.             verts.Add(v0);
  173.             verts.Add(v1);
  174.             verts.Add(v2);
  175.  
  176.             colors.Add(EvaluateColor(v0.y));
  177.             colors.Add(EvaluateColor(v1.y));
  178.             colors.Add(EvaluateColor(v2.y));
  179.  
  180.             Vector3 normal = Vector3.Cross(v1 - v0, v2 - v0);
  181.  
  182.             for (int j = 0; j < 3; j++)
  183.             {
  184.                 normals.Add(normal);
  185.                 uvs.Add(new Vector2((verts[i * 3 + j].x / dimensions.x), (verts[i * 3 + j].z / dimensions.y)));
  186.             }
  187.  
  188.         }
  189.  
  190.         // Center verts to gameObject center.
  191.         Matrix4x4 matrix = Matrix4x4.Translate(new Vector3(-dimensions.x / 2, 0, -dimensions.y / 2));
  192.  
  193.         for (int i = 0; i < verts.Count; i++)
  194.         {
  195.             verts[i] = matrix.MultiplyPoint3x4(verts[i]);
  196.         }
  197.  
  198.         if (verts.Count >= 65535)
  199.         {
  200.             Debug.LogWarning($"Too many vertices, terrain mesh will be deformed (verts: {verts.Count}/65535)");
  201.         }
  202.  
  203.         mesh = new Mesh()
  204.         {
  205.             vertices = verts.ToArray(),
  206.             normals = normals.ToArray(),
  207.             uv = uvs.ToArray(),
  208.             triangles = tris.ToArray(),
  209.             colors = colors.ToArray()
  210.         };
  211.     }
  212.  
  213.     public Color EvaluateColor(Triangle triangle)
  214.     {
  215.         float currentHeight = (heights[triangle.vertices[0].id] + heights[triangle.vertices[1].id] + heights[triangle.vertices[2].id]) / 3f;
  216.         currentHeight = (currentHeight < 0f) ? currentHeight / heightScale * waterFlatteningFactor : currentHeight / heightScale;
  217.  
  218.         return heightGradient.Evaluate(Mathf.InverseLerp(minNoiseHeight, maxNoiseHeight, currentHeight));
  219.     }
  220.     public Color EvaluateColor(float height)
  221.     {
  222.         height = (height < 0f) ? height / heightScale * waterFlatteningFactor : height / heightScale;
  223.         return heightGradient.Evaluate(Mathf.InverseLerp(minNoiseHeight, maxNoiseHeight, height));
  224.     }
  225. }
  226.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement