VisuTwin Canvas
C++ 3D Engine — Metal Backend
Loading...
Searching...
No Matches
metalMarchingCubesPass.h
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2025-2026 Arnis Lektauers
3//
4// Metal compute pass for GPU Marching Cubes isosurface extraction.
5//
6// Two-pass atomic pipeline:
7// Pass 1 (classifyCells): Each thread classifies one cell, computes its cube
8// index from the 3D volume texture, counts vertices via the triangle table,
9// and atomically adds to a global vertex counter.
10// Pass 2 (generateVertices): Each thread reprocesses its cell, atomically
11// allocates space in the output buffer, and writes full 56-byte VertexData
12// (position, normal, UV, tangent) matching the engine's common.metal layout.
13//
14// Follows the MetalParticleComputePass pattern:
15// - Embedded MSL source as string literal
16// - Lazy resource creation
17// - Friend access to MetalGraphicsDevice for command queue
18//
19// Custom shader -- no upstream GLSL equivalent exists for GPU
20// Marching Cubes isosurface extraction.
21//
22#pragma once
23
24#include <cstdint>
25#include <vector>
26#include <Metal/Metal.hpp>
27
28namespace visutwin::canvas
29{
31 class Texture;
32
35 struct alignas(16) MCComputeParams
36 {
37 uint32_t dimsX, dimsY, dimsZ;
38 float isovalue;
40 float _pad0;
42 float _pad1;
44 uint32_t maxVertices;
45 uint32_t flipNormals;
46 float _pad2[3];
47 };
48 static_assert(sizeof(MCComputeParams) == 80,
49 "MCComputeParams must be 80 bytes to match MSL layout");
50
55 {
56 MTL::Buffer* vertexBuffer = nullptr;
57 uint32_t vertexCount = 0;
58 bool success = false;
59 };
60
63 {
64 struct Layer {
65 MTL::Buffer* vertexBuffer = nullptr;
66 uint32_t vertexCount = 0;
67 };
68 std::vector<Layer> layers;
69 bool success = false;
70 };
71
82 {
83 public:
86
87 // Non-copyable
90
97 MCExtractResult extract(Texture* volumeTexture, const MCComputeParams& params);
98
107 MCBatchResult extractBatch(Texture* volumeTexture,
108 const MCComputeParams& baseParams,
109 const std::vector<float>& isovalues,
110 const std::vector<bool>& flipNormals = {});
111
113 [[nodiscard]] bool isReady() const { return resourcesReady_; }
114
115 private:
116 void ensureResources();
117
120 MTL::Buffer* allocateVertexBuffer(uint32_t vertexCount);
121
122 MetalGraphicsDevice* device_;
123
124 // Compute pipelines
125 MTL::ComputePipelineState* classifyPipeline_ = nullptr;
126 MTL::ComputePipelineState* generatePipeline_ = nullptr;
127
128 // Lookup table buffers (constant, created once)
129 MTL::Buffer* edgeTableBuffer_ = nullptr; // 256 x uint16_t = 512 bytes
130 MTL::Buffer* triTableBuffer_ = nullptr; // 256 x 16 x int8_t = 4096 bytes
131
132 // Shared buffers (reused across extractions)
133 MTL::Buffer* counterBuffer_ = nullptr; // single atomic_uint (StorageModeShared)
134 MTL::Buffer* uniformBuffer_ = nullptr; // MCComputeParams (80 bytes)
135
136 // Sampler for volume texture
137 MTL::SamplerState* fieldSampler_ = nullptr;
138
139 bool resourcesReady_ = false;
140 };
141
142} // namespace visutwin::canvas
MetalMarchingCubesPass & operator=(const MetalMarchingCubesPass &)=delete
MetalMarchingCubesPass(const MetalMarchingCubesPass &)=delete
MCBatchResult extractBatch(Texture *volumeTexture, const MCComputeParams &baseParams, const std::vector< float > &isovalues, const std::vector< bool > &flipNormals={})
MCExtractResult extract(Texture *volumeTexture, const MCComputeParams &params)
bool isReady() const
True once ensureResources() has succeeded.
GPU texture resource supporting 2D, cubemap, volume, and array formats with mipmap management.
Definition texture.h:57
MTL::Buffer * vertexBuffer
Caller takes ownership.
Result of a multi-isovalue batch extraction.
uint32_t maxVertices
Safety cap for output buffer.
uint32_t dimsZ
Volume dimensions in voxels.
uint32_t flipNormals
0 = outward (low-to-high), 1 = inward.
uint32_t vertexCount
Number of vertices (triangles*3).
MTL::Buffer * vertexBuffer
56-byte VertexData per vertex. Caller owns.