using System; using System.Collections.Generic; using System.Collections; using UnityEngine; using System.Runtime.CompilerServices; [RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))] public class CubesMarching : MonoBehaviour { public ChunkManager chunkManager; public bool useChunkManager; public int width = 10; public int height = 10; [Range(0, 1)] public float heightThreshold = .5f; [Range(.001f, .2f)] public float noiseFrequency = .1f; public float noiseAmplitude = 1.5f; public int noiseSeed; public float baseHeight; public bool interpolate; private float[,,] heights; private List<Vector3> vertices = new List<Vector3>(); private List<int> triangles = new List<int>(); private float lastHeight; private float lastHeightThreshold; public MeshFilter meshFilter; private FastNoiseLite fastNoise; private int incrementIdk; void Awake() { if (useChunkManager) { width = chunkManager.width; height = chunkManager.height; heightThreshold = chunkManager.heightThreshold; noiseAmplitude = chunkManager.noiseAmplitude; noiseFrequency = chunkManager.noiseFrequency; noiseSeed = chunkManager.noiseSeed; fastNoise = chunkManager.fastNoise; } else { fastNoise = new FastNoiseLite(); } GetComponent<MeshCollider>().sharedMesh = meshFilter.mesh; } [ContextMenu("Generate Mesh")] public void GenerateMesh() { fastNoise = new FastNoiseLite(); meshFilter = GetComponent<MeshFilter>(); fastNoise.SetNoiseType(FastNoiseLite.NoiseType.OpenSimplex2); fastNoise.SetFrequency(noiseFrequency / 10); fastNoise.SetFractalType(FastNoiseLite.FractalType.FBm); SetHeights(); MarchCubes(); SetMesh(); //StartCoroutine(UpdateChanged()); GetComponent<MeshCollider>().sharedMesh = meshFilter.sharedMesh; } [ContextMenu("Regenerate Mesh")] public void RegenerateMesh() { ClearMesh(); GenerateMesh(); } [ContextMenu("Clear Mesh")] public void ClearMesh() { vertices.Clear(); triangles.Clear(); meshFilter.mesh = null; } public IEnumerator UpdateChanged() { yield return new WaitForSeconds(UnityEngine.Random.Range(0f, 1f)); while (true) { if (noiseFrequency / 10 != fastNoise.GetFrequency() || noiseSeed != fastNoise.GetSeed() || height != lastHeight || heightThreshold != lastHeightThreshold) { SetHeights(); MarchCubes(); SetMesh(); lastHeight = height; lastHeightThreshold = heightThreshold; yield return new WaitForSeconds(1); } yield return null; } } private void SetHeights() { heights = new float[width + 1, height + 1, width + 1]; for (int x = 0; x < width + 1; x++) { for (int y = 0; y < height + 1; y++) { for (int z = 0; z < width + 1; z++) { float currentHeight = baseHeight + GetDensity(x, z); float newHeight; if (y > currentHeight) { newHeight = y - currentHeight; } else { newHeight = currentHeight - y; } heights[x, y, z] = newHeight; } } } } private float GetDensity(float x, float z) { return noiseAmplitude * fastNoise.GetNoise(x + transform.position.x, z + transform.position.z) / 2; } private IEnumerator MarchCubes() { vertices.Clear(); triangles.Clear(); vertices.Capacity = width * width * height * 5 * 3; triangles.Capacity = width * width * height * 5 * 3; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { for (int z = 0; z < width; z++) { float[] cubeCorners = new float[8]; for (int i = 0; i < 8; i++) { Vector3Int corner = new Vector3Int(x, y, z) + MarchingTable.Corners[i]; cubeCorners[i] = heights[corner.x, corner.y, corner.z]; incrementIdk++; } MarchCube(new Vector3(x, y, z), GetConfigurationIndex(cubeCorners)); } if (incrementIdk == 1000) { yield return null; } } } } private void MarchCube(Vector3 position, int configIndex) { if (configIndex == 0 || configIndex == 255) { return; } int edgeIndex = 0; for (int t = 0; t < 5; t++) { for (int v = 0; v < 3; v++) { int triTableValue = MarchingTable.Triangles[configIndex, edgeIndex]; if (triTableValue == -1) { return; } Vector3 edgeStart = position + MarchingTable.Edges[triTableValue, 0]; Vector3 edgeEnd = position + MarchingTable.Edges[triTableValue, 1]; Vector3 vertex; float value1 = heights[Mathf.RoundToInt(edgeStart.x), Mathf.RoundToInt(edgeStart.y), Mathf.RoundToInt(edgeStart.z)]; float value2 = heights[Mathf.RoundToInt(edgeEnd.x), Mathf.RoundToInt(edgeEnd.y), Mathf.RoundToInt(edgeEnd.z)]; if (interpolate) vertex = edgeStart + (heightThreshold - value1) / (value2 - value1) * (edgeEnd - edgeStart); else vertex = (edgeStart + edgeEnd) / 2f; // p = p1 + (t-v1)/(v2-v1) * (p2-p1) vertices.Add(vertex); triangles.Add(vertices.Count - 1); edgeIndex++; } } } private int GetConfigurationIndex(float[] cubeCorners) { int configIndex = 0; for (int i = 0; i < 8; i++) { if (cubeCorners[i] > heightThreshold) { configIndex |= 1 << i; } } return configIndex; } private void SetMesh() { Mesh mesh = new Mesh(); mesh.SetVertices(vertices); mesh.SetTriangles(triangles, 0); mesh.RecalculateNormals(); meshFilter.mesh = mesh; } }