Advertisement
JontePonte

GPU Marching Cubes

Jul 12th, 2025
71
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 6.62 KB | None | 0 0
  1. using System;
  2. using UnityEngine;
  3. using UnityEngine.Rendering;
  4. using Object = UnityEngine.Object;
  5.  
  6. namespace MarchingCubesAlgorithm
  7. {
  8.     public static class GPUMarchingCubes
  9.     {
  10.         private static ComputeShader marchingCubesCompute;
  11.        
  12.         private static ComputeBuffer caseToNumTrisBuf;
  13.         private static ComputeBuffer caseToTriEdgesBuf;
  14.         private static ComputeBuffer edgeToCornersBuf;
  15.        
  16.         private static GraphicsBuffer verticesBuf;
  17.         private static GraphicsBuffer indicesBuf;
  18.         private static ComputeBuffer vertexCounterBuf;
  19.         private static ComputeBuffer debugBuf;
  20.  
  21.         private static Mesh mesh;
  22.        
  23.         private static readonly int VOXEL_GRID = Shader.PropertyToID("voxelGrid");
  24.         private static readonly int DEBUG_BUFFER = Shader.PropertyToID("debugBuffer");
  25.         private static readonly int GRID_SIZE = Shader.PropertyToID("gridSize");
  26.         private static readonly int STEP_SIZE = Shader.PropertyToID("stepSize");
  27.         private static readonly int CASE_TO_NUM_TRIS = Shader.PropertyToID("caseToNumTris");
  28.         private static readonly int CASE_TO_TRI_EDGES = Shader.PropertyToID("caseToTriEdges");
  29.         private static readonly int EDGE_TO_CORNERS = Shader.PropertyToID("edgeToCorners");
  30.         private static readonly int VERTICES = Shader.PropertyToID("vertexBuffer");
  31.         private static readonly int INDICES = Shader.PropertyToID("indexBuffer");
  32.         private static readonly int VERTEX_COUNTER = Shader.PropertyToID("triangleCounter");
  33.  
  34.         public static void Initialize(ComputeShader marchingCubesCompute, Vector3Int voxelGridSize)
  35.         {
  36.             GPUMarchingCubes.marchingCubesCompute = marchingCubesCompute;
  37.  
  38.             Dispose();
  39.            
  40.             caseToNumTrisBuf = new ComputeBuffer(256, sizeof(int));
  41.             caseToTriEdgesBuf = new ComputeBuffer(3840, sizeof(int));
  42.             edgeToCornersBuf = new ComputeBuffer(24, sizeof(int) * 3);
  43.            
  44.             caseToNumTrisBuf.SetData(LookupTables.caseToNumTris);
  45.             caseToTriEdgesBuf.SetData(LookupTables.caseToTriEdges1D);
  46.             edgeToCornersBuf.SetData(LookupTables.nativeEdgeToCorners);
  47.            
  48.             marchingCubesCompute.SetBuffer(0, CASE_TO_NUM_TRIS, caseToNumTrisBuf);
  49.             marchingCubesCompute.SetBuffer(0, CASE_TO_TRI_EDGES, caseToTriEdgesBuf);
  50.             marchingCubesCompute.SetBuffer(0, EDGE_TO_CORNERS, edgeToCornersBuf);
  51.            
  52.             int numVoxels = voxelGridSize.x * voxelGridSize.y * voxelGridSize.z;
  53.             int maxVertexCount = numVoxels * 5 * 3;
  54.             AllocateMesh(maxVertexCount);
  55.            
  56.             vertexCounterBuf = new ComputeBuffer(1, sizeof(uint), ComputeBufferType.Counter);
  57.             vertexCounterBuf.SetCounterValue(0);
  58.             marchingCubesCompute.SetBuffer(0, VERTEX_COUNTER, vertexCounterBuf);
  59.  
  60.             debugBuf = new ComputeBuffer(numVoxels, sizeof(float) * 3);
  61.             marchingCubesCompute.SetBuffer(0, DEBUG_BUFFER, debugBuf);
  62.         }
  63.        
  64.         public static Mesh GenerateMesh(ComputeBuffer voxelGridBuf, Vector3Int voxelGridSize, int stepSize)
  65.         {
  66.             if (!marchingCubesCompute)
  67.                 throw new ArgumentException(
  68.                     "ComputeShader has not been initialized. You should call Initialize() before GenerateMesh()");
  69.            
  70.             vertexCounterBuf.SetCounterValue(0);
  71.            
  72.             marchingCubesCompute.SetBuffer(0, VERTICES, verticesBuf);
  73.             marchingCubesCompute.SetBuffer(0, INDICES, indicesBuf);
  74.             marchingCubesCompute.SetBuffer(0, VOXEL_GRID, voxelGridBuf);
  75.             marchingCubesCompute.SetInts(GRID_SIZE, voxelGridSize.x, voxelGridSize.y, voxelGridSize.z);
  76.             marchingCubesCompute.SetInt(STEP_SIZE, stepSize);
  77.            
  78.             int threadGroupsX = Mathf.FloorToInt(voxelGridSize.x / 8);
  79.             int threadGroupsY = Mathf.FloorToInt(voxelGridSize.y / 8);
  80.             int threadGroupsZ = Mathf.FloorToInt(voxelGridSize.z / 8);
  81.             marchingCubesCompute.Dispatch(0, threadGroupsX, threadGroupsY, threadGroupsZ);
  82.            
  83.             voxelGridBuf.Dispose();
  84.            
  85.             Debug.Log("Num vertices: " + GetAppendBufferCount(vertexCounterBuf));
  86.            
  87.             int numVoxels = voxelGridSize.x * voxelGridSize.y * voxelGridSize.z;
  88.             int maxVertexCount = numVoxels * 5 * 3;
  89.            
  90.             int[] cpuIndices = new int[maxVertexCount];
  91.             indicesBuf.GetData(cpuIndices);
  92.  
  93.             bool allZero = true;
  94.             for (int i = 0; i < cpuIndices.Length; i++)
  95.             {
  96.                 if (cpuIndices[i] != 0)
  97.                 {
  98.                     allZero = false;
  99.                     break;
  100.                 }
  101.             }
  102.             Debug.Log(allZero);
  103.  
  104.             mesh.bounds = new Bounds(Vector3.zero, voxelGridSize);
  105.             return Object.Instantiate(mesh);
  106.         }
  107.        
  108.         public static void Dispose()
  109.         {
  110.             caseToNumTrisBuf?.Dispose();
  111.             caseToTriEdgesBuf?.Dispose();
  112.             edgeToCornersBuf?.Dispose();
  113.              verticesBuf?.Dispose();
  114.              indicesBuf?.Dispose();
  115.              vertexCounterBuf?.Dispose();
  116.              Object.Destroy(mesh);
  117.         }
  118.  
  119.         private static void AllocateMesh(int vertexCount)
  120.         {
  121.             mesh = new Mesh();
  122.  
  123.             // We want GraphicsBuffer access as Raw (ByteAddress) buffers.
  124.             mesh.indexBufferTarget |= GraphicsBuffer.Target.Raw;
  125.             mesh.vertexBufferTarget |= GraphicsBuffer.Target.Raw;
  126.  
  127.             // Vertex position
  128.             VertexAttributeDescriptor vp = new(VertexAttribute.Position);
  129.  
  130.             // Vertex/index buffer formats
  131.             mesh.SetVertexBufferParams(vertexCount, vp);
  132.             mesh.SetIndexBufferParams(vertexCount, IndexFormat.UInt32);
  133.  
  134.             // Submesh initialization
  135.             mesh.SetSubMesh(0, new SubMeshDescriptor(0, vertexCount),
  136.                 MeshUpdateFlags.DontRecalculateBounds);
  137.  
  138.             // GraphicsBuffer references
  139.             verticesBuf = mesh.GetVertexBuffer(0);
  140.             indicesBuf = mesh.GetIndexBuffer();
  141.         }
  142.        
  143.         private static int GetAppendBufferCount(ComputeBuffer appendBuffer)
  144.         {
  145.             ComputeBuffer countBuffer = new(1, sizeof(int), ComputeBufferType.IndirectArguments);
  146.             ComputeBuffer.CopyCount(appendBuffer, countBuffer, 0);
  147.  
  148.             int[] countArray = { 0 };
  149.             countBuffer.GetData(countArray);
  150.             countBuffer.Release();
  151.  
  152.             return countArray[0];
  153.         }
  154.     }
  155. }
  156.  
  157.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement