Advertisement
JontePonte

marchin cubes

Jun 26th, 2025 (edited)
24
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 5.20 KB | None | 0 0
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using Voxels;
  4. using UnityEngine.Profiling;
  5.  
  6. namespace MarchingCubesAlgorithm
  7. {
  8.     public static class MarchingCubes
  9.     {
  10.         public static Mesh GenerateMesh(VoxelGrid voxelGrid)
  11.         {
  12.             Mesh mesh = new Mesh();
  13.             mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
  14.             List<Vector3> vertices = new();
  15.             List<int> indices = new();
  16.             Dictionary<Vector3, int> vertexToIndex = new();
  17.  
  18.             for (int z = 0, i = 0; z < voxelGrid.lengthZ - 1; z++)
  19.             {
  20.                 for (int y = 0; y < voxelGrid.lengthY - 1; y++)
  21.                 {
  22.                     for (int x = 0; x < voxelGrid.lengthX - 1; x++, i++)
  23.                     {
  24.                         MarchCube(x, y, z, voxelGrid, vertices, indices, vertexToIndex);
  25.                     }
  26.                 }
  27.             }
  28.  
  29.             Profiler.BeginSample("Mesh Assigning");
  30.             mesh.vertices = vertices.ToArray();
  31.             mesh.triangles = indices.ToArray();
  32.             mesh.RecalculateNormals();
  33.             mesh.RecalculateBounds();
  34.             Profiler.EndSample();
  35.  
  36.             return mesh;
  37.         }
  38.  
  39.         private static void MarchCube(int x, int y, int z, VoxelGrid voxelGrid, List<Vector3> vertices, List<int> indices, Dictionary<Vector3, int> vertexToIndex)
  40.         {
  41.             Profiler.BeginSample("Generate Case");
  42.             int voxelCase = GenerateCase(x, y, z, voxelGrid);
  43.             Profiler.EndSample();
  44.  
  45.             int numTris = LookupTables.caseToNumTris[voxelCase];
  46.  
  47.             int startIndex = voxelCase * 15;
  48.             Vector3Int[] tris = LookupTables.caseToTriEdges[voxelCase];
  49.  
  50.             for (int i = 0; i < numTris; i++)
  51.             {
  52.                 Vector3Int triEdges = tris[i];
  53.  
  54.                 Profiler.BeginSample("Calculating Vertex Positions");
  55.                 Vector3 vertexPosition0 = InterpolateVertex(triEdges.x, x, y, z, voxelGrid);
  56.                 Vector3 vertexPosition1 = InterpolateVertex(triEdges.y, x, y, z, voxelGrid);
  57.                 Vector3 vertexPosition2 = InterpolateVertex(triEdges.z, x, y, z, voxelGrid);
  58.                 Profiler.EndSample();
  59.  
  60.                 Profiler.BeginSample("Adding vertices and indices");
  61.                 AddOrReuseVertex(vertexPosition0, vertices, indices, vertexToIndex);
  62.                 AddOrReuseVertex(vertexPosition1, vertices, indices, vertexToIndex);
  63.                 AddOrReuseVertex(vertexPosition2, vertices, indices, vertexToIndex);
  64.                 Profiler.EndSample();
  65.             }
  66.         }
  67.  
  68.         // Adds a new vertex only if it does not already exist in the list, otherwise just add index to that vertex
  69.         private static void AddOrReuseVertex(Vector3 vertexPosition, List<Vector3> vertices, List<int> indices, Dictionary<Vector3, int> vertexToIndex)
  70.         {
  71.             if (vertexToIndex.TryGetValue(vertexPosition, out int index))
  72.             {
  73.                 indices.Add(index);
  74.             }
  75.             else
  76.             {
  77.                 vertices.Add(vertexPosition);
  78.                 int newIndex = vertices.Count - 1;
  79.                 vertexToIndex[vertexPosition] = newIndex;
  80.                 indices.Add(newIndex);
  81.             }
  82.         }
  83.  
  84.         private static int GenerateCase(int x, int y, int z, VoxelGrid voxelGrid)
  85.         {
  86.             Profiler.BeginSample("Voxel Grid Get");
  87.             float[] corners = GetCubeCornerValues(x, y, z, voxelGrid);
  88.             Profiler.EndSample();
  89.             int caseByte = 0;
  90.  
  91.             Profiler.BeginSample("Creating Byte");
  92.             // a |= b shorthand for a = a | b with | the bitwise OR operator.
  93.             // 1 << i bitshifts the number 1 (0b_0000_0001) i bits to the left
  94.             for (int i = 0; i < 8; i++)
  95.                 if (corners[i] > 0) { caseByte |= 1 << i; }
  96.             Profiler.EndSample();
  97.  
  98.             return caseByte;
  99.         }
  100.  
  101.         // X, Y, Z is the bottom left corner
  102.         private static float[] GetCubeCornerValues(int x, int y, int z, VoxelGrid voxelGrid)
  103.         {
  104.             return new float[8]
  105.             {
  106.                 voxelGrid.Get(x, y, z),
  107.                 voxelGrid.Get(x, y + 1, z),
  108.                 voxelGrid.Get(x + 1, y + 1, z),
  109.                 voxelGrid.Get(x + 1, y, z),
  110.                 voxelGrid.Get(x, y, z + 1),
  111.                 voxelGrid.Get(x, y + 1, z + 1),
  112.                 voxelGrid.Get(x + 1, y + 1, z + 1),
  113.                 voxelGrid.Get(x + 1, y, z + 1)
  114.             };
  115.         }
  116.  
  117.         private static Vector3 InterpolateVertex(int edge, int x, int y, int z, VoxelGrid voxelGrid)
  118.         {
  119.             Vector3Int[] edgeCorners = LookupTables.edgeToCorners[edge];
  120.  
  121.             Vector3Int p0 = edgeCorners[0];
  122.             Vector3Int p1 = edgeCorners[1];
  123.  
  124.             float v0 = voxelGrid.Get(x + p0.x, y + p0.y, z + p0.z);
  125.             float v1 = voxelGrid.Get(x + p1.x, y + p1.y, z + p1.z);
  126.  
  127.             float isolevel = 0f;
  128.             float t = (isolevel - v0) / (v1 - v0);
  129.  
  130.             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);
  131.             return vertexPosition;
  132.         }
  133.     }
  134. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement