Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.Experimental.AI;
- public class MeshGenerator : MonoBehaviour
- {
- public Vector3Int chunkDimensions;
- public Material material;
- public int brushSize;
- [Header("Noise Settings")]
- public float frequency;
- float[,,][] voxelGrid;
- List<Vector3> vertices;
- int[] caseToNumpolys;
- int[][] triTable;
- Vector3[] voxelCornerOffsets;
- RaycastHit hit;
- Camera cam;
- private void Start()
- {
- caseToNumpolys = Tables.caseToNumPolys;
- triTable = Tables.triTable;
- cam = Camera.main;
- voxelCornerOffsets = new Vector3[]
- {
- new Vector3(0, 0, 0),
- new Vector3(0, 1, 0),
- new Vector3(1, 1, 0),
- new Vector3(1, 0, 0),
- new Vector3(0, 0, 1),
- new Vector3(0, 1, 1),
- new Vector3(1, 1, 1),
- new Vector3(1, 0, 1),
- };
- CreateVoxelGrid();
- GenerateMesh();
- }
- private void Update()
- {
- if (Input.GetMouseButton(1))
- {
- if(Physics.Raycast(cam.transform.position, cam.transform.forward, out hit))
- {
- ModifyTerrain(new Vector3Int((int)hit.point.x, (int)hit.point.y, (int)hit.point.z), true);
- }
- }
- if (Input.GetMouseButton(0))
- {
- if (Physics.Raycast(cam.transform.position, cam.transform.forward, out hit))
- {
- ModifyTerrain(new Vector3Int((int)hit.point.x, (int)hit.point.y, (int)hit.point.z), false);
- }
- }
- }
- void GenerateMesh()
- {
- vertices = new();
- for (int z = 0; z < chunkDimensions.z; z++)
- {
- for (int y = 0; y < chunkDimensions.y; y++)
- {
- for (int x = 0; x < chunkDimensions.x; x++)
- {
- AddVertices(x, y, z);
- }
- }
- }
- int[] indices = new int[vertices.Count];
- for (int i = 0; i < vertices.Count; i++)
- {
- indices[i] = i;
- }
- Mesh mesh = new Mesh();
- mesh.vertices = vertices.ToArray();
- mesh.triangles = indices;
- mesh.RecalculateNormals();
- if(GameObject.Find("Mesh") == null)
- {
- GameObject obj = new GameObject("Mesh");
- 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;
- }
- }
- void AddVertices(int x, int y, int z)
- {
- int triCase = CalculateCase(voxelGrid[x, y, z]);
- int[] edges = triTable[triCase];
- for (int j = 0, i = 0; j < caseToNumpolys[triCase]; j++, i += 3)
- {
- vertices.AddRange(new List<Vector3>
- {
- GetEdgePosition(edges[i + 2], x, y, z),
- GetEdgePosition(edges[i + 1], x, y, z),
- GetEdgePosition(edges[i], x, y, z)
- });
- }
- }
- Vector3 GetEdgePosition(int edge, int x, int y, int z)
- {
- float[] voxelData = voxelGrid[x, y, z];
- switch (edge)
- {
- case 0: return GetInterpolatedEdgePosition(x, y, z, voxelData[0], voxelData[1], 0, 1, 0);
- case 1: return GetInterpolatedEdgePosition(x, y + 1, z, voxelData[1], voxelData[2], 1, 0, 0);
- case 2: return GetInterpolatedEdgePosition(x + 1, y, z, voxelData[3], voxelData[2], 0, 1, 0);
- case 3: return GetInterpolatedEdgePosition(x, y, z, voxelData[0], voxelData[3], 1, 0, 0);
- case 4: return GetInterpolatedEdgePosition(x, y, z + 1, voxelData[4], voxelData[5], 0, 1, 0);
- case 5: return GetInterpolatedEdgePosition(x, y + 1, z + 1, voxelData[5], voxelData[6], 1, 0, 0);
- case 6: return GetInterpolatedEdgePosition(x + 1, y, z + 1, voxelData[7], voxelData[6], 0, 1, 0);
- case 7: return GetInterpolatedEdgePosition(x, y, z + 1, voxelData[4], voxelData[7], 1, 0, 0);
- case 8: return GetInterpolatedEdgePosition(x, y, z, voxelData[0], voxelData[4], 0, 0, 1);
- case 9: return GetInterpolatedEdgePosition(x, y + 1, z, voxelData[1], voxelData[5], 0, 0, 1);
- case 10: return GetInterpolatedEdgePosition(x + 1, y + 1, z, voxelData[2], voxelData[6], 0, 0, 1);
- case 11: return GetInterpolatedEdgePosition(x + 1, y, z, voxelData[3], voxelData[7], 0, 0, 1);
- default: throw new ArgumentOutOfRangeException(nameof(edge), "Invalid edge index: " + edge);
- }
- }
- // Helper method to calculate interpolated edge positions
- Vector3 GetInterpolatedEdgePosition(int x, int y, int z, float voxelA, float voxelB, int offsetX, int offsetY, int offsetZ)
- {
- float interpolation = Interpolate(voxelA, voxelB);
- return new Vector3(x + offsetX * interpolation, y + offsetY * interpolation, z + offsetZ * interpolation);
- }
- float Interpolate(float a, float b)
- {
- return (0 - a) / (b - a);
- }
- int CalculateCase(float[] voxelData)
- {
- int triCase = 0;
- for (int i = 0; i < 8; i++)
- {
- int bit = voxelData[i] < 0 ? 1 : 0;
- triCase |= bit << i;
- }
- return triCase;
- }
- private void ModifyTerrain(Vector3Int vertex, bool addTerrain)
- {
- 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 <= 1 || vertex.x + xOffset >= chunkDimensions.x - 2;
- bool yOutOfRange = vertex.y + yOffset <= 1 || vertex.y + yOffset >= chunkDimensions.y - 2;
- bool zOutOfRange = vertex.z + zOffset <= 1 || vertex.z + zOffset >= chunkDimensions.z - 2;
- if(xOutOfRange || yOutOfRange || zOutOfRange)
- {
- continue;
- }
- float[] voxel = voxelGrid[vertex.x + xOffset, vertex.y + yOffset, vertex.z + zOffset];
- for (int i = 0; i < 8; i++)
- {
- int x = (int)(vertex.x + xOffset + voxelCornerOffsets[i].x);
- int y = (int)(vertex.y + yOffset + voxelCornerOffsets[i].y);
- int z = (int)(vertex.z + zOffset + voxelCornerOffsets[i].z);
- float dist = Vector3.Distance(vertex, new Vector3(x, y, z));
- if (dist < brushSize)
- {
- voxel[i] = addTerrain ? voxel[i] + .01f : voxel[i] - .01f;
- }
- }
- }
- }
- }
- GenerateMesh();
- }
- public void CreateVoxelGrid()
- {
- voxelGrid = new float[chunkDimensions.x, chunkDimensions.y, chunkDimensions.z][];
- for (int z = 0; z < chunkDimensions.z; z++)
- {
- for (int y = 0; y < chunkDimensions.y; y++)
- {
- for (int x = 0; x < chunkDimensions.x; x++)
- {
- CreateVoxel(x, y, z);
- }
- }
- }
- }
- public void CreateVoxel(int x, int y, int z)
- {
- voxelGrid[x, y, z] = new float[8];
- for (int i = 0; i < 8; i++)
- {
- voxelGrid[x, y, z][i] = Perlin.Noise((x + voxelCornerOffsets[i].x) * frequency, (y + voxelCornerOffsets[i].y) * frequency, (z + voxelCornerOffsets[i].z) * frequency);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement