Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System.Collections.Generic;
- using UnityEngine;
- using Voxels;
- using UnityEngine.Profiling;
- namespace MarchingCubesAlgorithm
- {
- public static class MarchingCubes
- {
- public static Mesh GenerateMesh(VoxelGrid voxelGrid)
- {
- Mesh mesh = new Mesh();
- mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
- List<Vector3> vertices = new();
- List<int> indices = new();
- Dictionary<Vector3, int> vertexToIndex = new();
- for (int z = 0, i = 0; z < voxelGrid.lengthZ - 1; z++)
- {
- for (int y = 0; y < voxelGrid.lengthY - 1; y++)
- {
- for (int x = 0; x < voxelGrid.lengthX - 1; x++, i++)
- {
- MarchCube(x, y, z, voxelGrid, vertices, indices, vertexToIndex);
- }
- }
- }
- Profiler.BeginSample("Mesh Assigning");
- mesh.vertices = vertices.ToArray();
- mesh.triangles = indices.ToArray();
- mesh.RecalculateNormals();
- mesh.RecalculateBounds();
- Profiler.EndSample();
- return mesh;
- }
- private static void MarchCube(int x, int y, int z, VoxelGrid voxelGrid, List<Vector3> vertices, List<int> indices, Dictionary<Vector3, int> vertexToIndex)
- {
- Profiler.BeginSample("Generate Case");
- int voxelCase = GenerateCase(x, y, z, voxelGrid);
- Profiler.EndSample();
- int numTris = LookupTables.caseToNumTris[voxelCase];
- int startIndex = voxelCase * 15;
- Vector3Int[] tris = LookupTables.caseToTriEdges[voxelCase];
- for (int i = 0; i < numTris; i++)
- {
- Vector3Int triEdges = tris[i];
- Profiler.BeginSample("Calculating Vertex Positions");
- Vector3 vertexPosition0 = InterpolateVertex(triEdges.x, x, y, z, voxelGrid);
- Vector3 vertexPosition1 = InterpolateVertex(triEdges.y, x, y, z, voxelGrid);
- Vector3 vertexPosition2 = InterpolateVertex(triEdges.z, x, y, z, voxelGrid);
- Profiler.EndSample();
- Profiler.BeginSample("Adding vertices and indices");
- AddOrReuseVertex(vertexPosition0, vertices, indices, vertexToIndex);
- AddOrReuseVertex(vertexPosition1, vertices, indices, vertexToIndex);
- AddOrReuseVertex(vertexPosition2, vertices, indices, vertexToIndex);
- Profiler.EndSample();
- }
- }
- // Adds a new vertex only if it does not already exist in the list, otherwise just add index to that vertex
- private static void AddOrReuseVertex(Vector3 vertexPosition, List<Vector3> vertices, List<int> indices, Dictionary<Vector3, int> vertexToIndex)
- {
- if (vertexToIndex.TryGetValue(vertexPosition, out int index))
- {
- indices.Add(index);
- }
- else
- {
- vertices.Add(vertexPosition);
- int newIndex = vertices.Count - 1;
- vertexToIndex[vertexPosition] = newIndex;
- indices.Add(newIndex);
- }
- }
- private static int GenerateCase(int x, int y, int z, VoxelGrid voxelGrid)
- {
- Profiler.BeginSample("Voxel Grid Get");
- float[] corners = GetCubeCornerValues(x, y, z, voxelGrid);
- Profiler.EndSample();
- int caseByte = 0;
- Profiler.BeginSample("Creating Byte");
- // a |= b shorthand for a = a | b with | the bitwise OR operator.
- // 1 << i bitshifts the number 1 (0b_0000_0001) i bits to the left
- for (int i = 0; i < 8; i++)
- if (corners[i] > 0) { caseByte |= 1 << i; }
- Profiler.EndSample();
- return caseByte;
- }
- // X, Y, Z is the bottom left corner
- private static float[] GetCubeCornerValues(int x, int y, int z, VoxelGrid voxelGrid)
- {
- return new float[8]
- {
- voxelGrid.Get(x, y, z),
- voxelGrid.Get(x, y + 1, z),
- voxelGrid.Get(x + 1, y + 1, z),
- voxelGrid.Get(x + 1, y, z),
- voxelGrid.Get(x, y, z + 1),
- voxelGrid.Get(x, y + 1, z + 1),
- voxelGrid.Get(x + 1, y + 1, z + 1),
- voxelGrid.Get(x + 1, y, z + 1)
- };
- }
- private static Vector3 InterpolateVertex(int edge, int x, int y, int z, VoxelGrid voxelGrid)
- {
- Vector3Int[] edgeCorners = LookupTables.edgeToCorners[edge];
- Vector3Int p0 = edgeCorners[0];
- Vector3Int p1 = edgeCorners[1];
- float v0 = voxelGrid.Get(x + p0.x, y + p0.y, z + p0.z);
- float v1 = voxelGrid.Get(x + p1.x, y + p1.y, z + p1.z);
- float isolevel = 0f;
- float t = (isolevel - v0) / (v1 - v0);
- Vector3 vertexPosition = new Vector3(x + p0.x, y + p0.y, z + p0.z) + t * new Vector3(p1.x - p0.x, p1.y - p0.y, p1.z - p0.z);
- return vertexPosition;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement