Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using UnityEngine;
- using Unity.Mathematics;
- using Unity.Collections;
- using Unity.Jobs;
- using Unity.VisualScripting;
- using Unity.Burst;
- //TODO: Jobify CreateVoxelGrid()
- public class MeshGenerator : MonoBehaviour
- {
- public static Vector3Int chunkDimensions = new Vector3Int(32, 128, 32);
- public Material material;
- public int brushSize;
- public float brushStrength;
- public int lod;
- public int maxLod;
- public float surfaceLevel;
- public bool hideMeshOnPlay;
- [Header("Noise Settings")]
- public float heightMultiplier;
- public AnimationCurve heightCurve;
- public float frequency;
- public float lacunarity;
- public float persistance;
- public int octaves;
- public float density;
- public float warpingStrength;
- public float warpingFrequency;
- public float mountainHeightOffset;
- public Vector2 offset;
- [Header("")]
- public bool autoUpdate;
- public string executionTime;
- int[] caseToNumpolys;
- int[][] triTable;
- public static Vector3Int[] cornerOffsets;
- Camera cam;
- Noise noise;
- public GameObject ChunkObject(Vector2 position)
- {
- GameObject chunk = new GameObject("Chunk");
- chunk.AddComponent<MeshFilter>().mesh = ChunkMesh(position, 0);
- chunk.AddComponent<MeshRenderer>().material = material;
- chunk.GetComponent<MeshRenderer>().receiveShadows = false;
- chunk.GetComponent<MeshRenderer>().shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
- return chunk;
- }
- public Mesh ChunkMesh(Vector2 position, int lod)
- {
- List<Vector3> vertices = new();
- Dictionary<Vector3, int> vertDictionary = new();
- List<int> indices = new();
- lod = lod == 0 ? 1 : lod * 2;
- float[] voxelGrid = new float[chunkDimensions.x * chunkDimensions.y * chunkDimensions.z / (lod * lod * lod) * 8];
- MeshData meshData = new MeshData
- {
- vertices = vertices,
- indices = indices,
- vertDictionary = vertDictionary,
- voxelGrid = voxelGrid,
- lod = lod
- };
- VoxelGridData gridData = new VoxelGridData
- {
- voxelGrid = voxelGrid,
- noiseMap2D = noise.FractalNoiseMap(position, lod),
- noiseMap3D = noise.Fractal3DNoiseMap(position, lod),
- lod = lod
- };
- CreateVoxelGrid(gridData);
- for (int z = 0, i = 0; z < chunkDimensions.z; z += lod)
- {
- for (int y = 0; y < chunkDimensions.y; y += lod)
- {
- for (int x = 0; x < chunkDimensions.x; x += lod, i++)
- {
- AddVertices(i, new Vector3Int(x, y, z), meshData);
- }
- }
- }
- gridData.noiseMap2D.Dispose();
- gridData.noiseMap3D.Dispose();
- Mesh mesh = new Mesh();
- mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
- mesh.vertices = vertices.ToArray();
- mesh.triangles = indices.ToArray();
- mesh.RecalculateNormals();
- return mesh;
- }
- public void EditorMesh()
- {
- Initialize();
- float startTime = Time.realtimeSinceStartup;
- Mesh mesh = ChunkMesh(offset/10, lod);
- executionTime = ((Time.realtimeSinceStartup - startTime) * 1000f) + "ms";
- if (GameObject.Find("Mesh") == null)
- {
- GameObject obj = new GameObject("Mesh");
- obj.transform.parent = transform;
- obj.AddComponent<MeshFilter>().mesh = mesh;
- obj.AddComponent<MeshRenderer>().material = material;
- obj.AddComponent<MeshCollider>();
- }
- else
- {
- var mf = GameObject.Find("Mesh").GetComponent<MeshFilter>();
- var collider = GameObject.Find("Mesh").GetComponent<MeshCollider>();
- mf.mesh = mesh;
- collider.sharedMesh = null;
- collider.sharedMesh = mesh;
- }
- }
- private void Start()
- {
- Initialize();
- if (GameObject.Find("Mesh") != null)
- {
- GameObject.Find("Mesh").SetActive(!hideMeshOnPlay);
- }
- }
- private void Update()
- {
- if (Input.GetKeyDown(KeyCode.Space))
- {
- EditorMesh();
- }
- //if (Input.GetMouseButton(1))
- //{
- // Ray ray = cam.ScreenPointToRay(Input.mousePosition);
- // if (Physics.Raycast(ray, out RaycastHit hit))
- // {
- // ModifyTerrain(new Vector3Int((int)hit.point.x, (int)hit.point.y, (int)hit.point.z), true, hit.collider.gameObject);
- // }
- //}
- //if (Input.GetMouseButton(0))
- //{
- // Ray ray = cam.ScreenPointToRay(Input.mousePosition);
- // if (Physics.Raycast(ray, out RaycastHit hit))
- // {
- // ModifyTerrain(new Vector3Int((int)hit.point.x, (int)hit.point.y, (int)hit.point.z), false, hit.collider.gameObject);
- // }
- //}
- }
- void Initialize()
- {
- caseToNumpolys = Tables.caseToNumPolys;
- triTable = Tables.triTable;
- cam = Camera.main;
- cornerOffsets = new Vector3Int[]
- {
- new Vector3Int(0, 0, 0),
- new Vector3Int(0, 1, 0),
- new Vector3Int(1, 1, 0),
- new Vector3Int(1, 0, 0),
- new Vector3Int(0, 0, 1),
- new Vector3Int(0, 1, 1),
- new Vector3Int(1, 1, 1),
- new Vector3Int(1, 0, 1),
- };
- noise = new Noise(frequency, persistance, lacunarity, warpingStrength, warpingFrequency, mountainHeightOffset, octaves);
- }
- void AddVertices(int index, Vector3Int pos, MeshData md)
- {
- float[] voxelData = new float[8];
- for (int i = 0; i < 8; i++)
- {
- voxelData[i] = md.voxelGrid[(index * 8) + i];
- }
- int triCase = Utils.CalculateCase(voxelData);
- int[] edges = triTable[triCase];
- for (int j = 0, i = 0; j < caseToNumpolys[triCase]; j++, i += 3)
- {
- for (int h = 0; h < 3; h++)
- {
- Vector3 vertex = GetEdgePosition(edges[i + (2 - h)], voxelData, md.lod, pos);
- if (md.vertDictionary.ContainsKey(vertex))
- {
- md.indices.Add(md.vertDictionary[vertex]);
- }
- else
- {
- md.vertices.Add(vertex);
- md.indices.Add(md.vertices.Count - 1);
- md.vertDictionary.Add(vertex, md.vertices.Count - 1);
- }
- }
- }
- }
- Vector3 GetEdgePosition(int edge, float[] voxelData, int lod, Vector3Int pos)
- {
- int x = pos.x;
- int y = pos.y;
- int z = pos.z;
- switch (edge)
- {
- case 0: return Utils.GetInterpolatedEdgePosition(x, y, z, voxelData[0], voxelData[1], 0, 1, 0);
- case 1: return Utils.GetInterpolatedEdgePosition(x, y + (1 * lod), z, voxelData[1], voxelData[2], 1, 0, 0);
- case 2: return Utils.GetInterpolatedEdgePosition(x + (1 * lod), y, z, voxelData[3], voxelData[2], 0, 1, 0);
- case 3: return Utils.GetInterpolatedEdgePosition(x, y, z, voxelData[0], voxelData[3], 1, 0, 0);
- case 4: return Utils.GetInterpolatedEdgePosition(x, y, z + (1 * lod), voxelData[4], voxelData[5], 0, 1, 0);
- case 5: return Utils.GetInterpolatedEdgePosition(x, y + (1 * lod), z + (1 * lod), voxelData[5], voxelData[6], 1, 0, 0);
- case 6: return Utils.GetInterpolatedEdgePosition(x + (1 * lod), y, z + (1 * lod), voxelData[7], voxelData[6], 0, 1, 0);
- case 7: return Utils.GetInterpolatedEdgePosition(x, y, z + (1 * lod), voxelData[4], voxelData[7], 1, 0, 0);
- case 8: return Utils.GetInterpolatedEdgePosition(x, y, z, voxelData[0], voxelData[4], 0, 0, 1);
- case 9: return Utils.GetInterpolatedEdgePosition(x, y + (1 * lod), z, voxelData[1], voxelData[5], 0, 0, 1);
- case 10: return Utils.GetInterpolatedEdgePosition(x + (1 * lod), y + (1 * lod), z, voxelData[2], voxelData[6], 0, 0, 1);
- case 11: return Utils.GetInterpolatedEdgePosition(x + (1 * lod), y, z, voxelData[3], voxelData[7], 0, 0, 1);
- default: throw new ArgumentOutOfRangeException(nameof(edge), "Invalid edge index: " + edge);
- }
- }
- //private void ModifyTerrain(Vector3Int vertex, bool addTerrain, GameObject chunk)
- //{
- // for (int zOffset = -brushSize; zOffset <= brushSize; zOffset++)
- // {
- // for (int yOffset = -brushSize; yOffset <= brushSize; yOffset++)
- // {
- // for (int xOffset = -brushSize; xOffset <= brushSize; xOffset++)
- // {
- // bool xOutOfRange = vertex.x + xOffset < 0 || vertex.x + xOffset > chunkDimensions.x - 1;
- // bool yOutOfRange = vertex.y + yOffset < 0 || vertex.y + yOffset > chunkDimensions.y - 1;
- // bool zOutOfRange = vertex.z + zOffset < 0 || vertex.z + zOffset > chunkDimensions.z - 1;
- // if (xOutOfRange || yOutOfRange || zOutOfRange)
- // {
- // continue;
- // }
- // float[] voxel = voxelGrid[Utils.VoxelIndex(vertex.x + xOffset, vertex.y + yOffset, vertex.z + zOffset)];
- // for (int i = 0; i < 8; i++)
- // {
- // int x = vertex.x + xOffset + cornerOffsets[i].x;
- // int y = vertex.y + yOffset + cornerOffsets[i].y;
- // int z = vertex.z + zOffset + cornerOffsets[i].z;
- // float dist = Vector3.Distance(vertex, new Vector3(x, y, z));
- // if (dist < brushSize)
- // {
- // voxel[i] = addTerrain ? voxel[i] + brushStrength : voxel[i] - brushStrength;
- // }
- // }
- // }
- // }
- // }
- // chunk.GetComponent<MeshFilter>().mesh = ChunkMesh(new Vector2Int((int)chunk.transform.position.x, (int)chunk.transform.position.z));
- //}
- void CreateVoxelGrid(VoxelGridData gd)
- {
- int length = chunkDimensions.x / gd.lod * chunkDimensions.y / gd.lod * chunkDimensions.z / gd.lod;
- for (int i = 0; i < length; i++)
- {
- int z = i / (chunkDimensions.x / gd.lod * chunkDimensions.y / gd.lod) * gd.lod;
- int y = (i / (chunkDimensions.x / gd.lod) * gd.lod) - z / gd.lod * chunkDimensions.y;
- int x = i % (chunkDimensions.x / gd.lod) * gd.lod;
- CreateVoxel(new Vector3Int(x, y, z), i, gd);
- }
- }
- void CreateVoxel(Vector3Int pos, int index, VoxelGridData gd)
- {
- int noise2DIndex = ((pos.x / gd.lod) + ((pos.z / gd.lod) * chunkDimensions.x)) * 8;
- for (int i = 0; i < 8; i++)
- {
- Vector3Int cornerPos = pos + cornerOffsets[i] * gd.lod;
- float noise2D = gd.noiseMap2D[noise2DIndex + i];
- gd.voxelGrid[(index * 8) + i] = (-cornerPos.y + surfaceLevel + (noise2D * heightMultiplier * heightCurve.Evaluate(noise2D))) * density + gd.noiseMap3D[(index * 8) + i];
- }
- }
- struct MeshData
- {
- public List<Vector3> vertices;
- public List<int> indices;
- public Dictionary<Vector3, int> vertDictionary;
- public float[] voxelGrid;
- public int lod;
- }
- struct VoxelGridData
- {
- public float[] voxelGrid;
- public NativeArray<float> noiseMap2D;
- public NativeArray<float> noiseMap3D;
- public int lod;
- }
- [BurstCompile]
- struct VoxelGridJob : IJobParallelFor
- {
- [WriteOnly] public NativeArray<float> voxelGrid;
- [ReadOnly] public NativeArray<float> noiseMap2D;
- [ReadOnly] public NativeArray<float> noiseMap3D;
- [ReadOnly] public NativeArray<int3> cornerOffsets;
- [ReadOnly] public NativeArray<float> heightCurve;
- [ReadOnly] public int3 chunkDimensions;
- [ReadOnly] public int lod;
- [ReadOnly] public float surfaceLevel;
- [ReadOnly] public float heightMultiplier;
- [ReadOnly] public float density;
- public void Execute(int i)
- {
- int z = i / (chunkDimensions.x / lod * chunkDimensions.y / lod) * lod;
- int y = (i / (chunkDimensions.x / lod) * lod) - z / lod * chunkDimensions.y;
- int x = i % (chunkDimensions.x / lod) * lod;
- CreateVoxel(new int3(x, y, z), i);
- }
- void CreateVoxel(int3 pos, int index)
- {
- int noise2DIndex = ((pos.x / lod) + ((pos.z / lod) * chunkDimensions.x)) * 8;
- for (int i = 0; i < 8; i++)
- {
- int3 cornerPos = pos + cornerOffsets[i] * lod;
- float noise2D = noiseMap2D[noise2DIndex + i];
- voxelGrid[(index * 8) + i] = (-cornerPos.y + surfaceLevel + noise2D * heightMultiplier) * density + noiseMap3D[(index * 8) + i];
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement