MayaFlux 0.5.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
SDFMeshProcessor.cpp
Go to the documentation of this file.
2
4
6
11
12namespace MayaFlux::Buffers {
13
14// ============================================================================
15// Construction
16// ============================================================================
17
20 const glm::vec3& bounds_min,
21 const glm::vec3& bounds_max,
22 uint32_t res_x,
23 uint32_t res_y,
24 uint32_t res_z,
25 float iso_level)
26 : ComputeProcessor("mc_emit.comp.spv", 64)
27 , m_field(std::move(field))
28 , m_bounds_min(bounds_min)
29 , m_bounds_max(bounds_max)
30 , m_res_x(std::max(res_x, 1U))
31 , m_res_y(std::max(res_y, 1U))
32 , m_res_z(std::max(res_z, 1U))
33 , m_iso_level(iso_level)
34{
36
37 m_config.bindings["sdf_grid"] = ShaderBinding(0, 0, vk::DescriptorType::eStorageBuffer);
38 m_config.bindings["edge_table"] = ShaderBinding(0, 1, vk::DescriptorType::eStorageBuffer);
39 m_config.bindings["tri_table"] = ShaderBinding(0, 2, vk::DescriptorType::eStorageBuffer);
40 m_config.bindings["vertices"] = ShaderBinding(0, 3, vk::DescriptorType::eStorageBuffer);
41 m_config.bindings["counter"] = ShaderBinding(0, 4, vk::DescriptorType::eStorageBuffer);
42
44}
45
47 std::shared_ptr<VKBuffer> grid_buf,
48 std::shared_ptr<VKBuffer> counter_buf,
49 const glm::vec3& bounds_min,
50 const glm::vec3& bounds_max,
51 uint32_t res_x,
52 uint32_t res_y,
53 uint32_t res_z,
54 float iso_level)
55 : ComputeProcessor("mc_emit.comp.spv", 64)
56 , m_bounds_min(bounds_min)
57 , m_bounds_max(bounds_max)
58 , m_res_x(std::max(res_x, 1U))
59 , m_res_y(std::max(res_y, 1U))
60 , m_res_z(std::max(res_z, 1U))
61 , m_iso_level(iso_level)
62 , m_grid_buf(std::move(grid_buf))
63 , m_counter_buf(std::move(counter_buf))
64 , m_owns_buffers(false)
65{
67
68 m_config.bindings["sdf_grid"] = ShaderBinding(0, 0, vk::DescriptorType::eStorageBuffer);
69 m_config.bindings["edge_table"] = ShaderBinding(0, 1, vk::DescriptorType::eStorageBuffer);
70 m_config.bindings["tri_table"] = ShaderBinding(0, 2, vk::DescriptorType::eStorageBuffer);
71 m_config.bindings["vertices"] = ShaderBinding(0, 3, vk::DescriptorType::eStorageBuffer);
72 m_config.bindings["counter"] = ShaderBinding(0, 4, vk::DescriptorType::eStorageBuffer);
73
75
77}
78
79// ============================================================================
80// Setters
81// ============================================================================
82
84{
85 m_field = std::move(field);
86 m_dirty = true;
87}
88
89void SDFMeshProcessor::set_bounds(const glm::vec3& bounds_min, const glm::vec3& bounds_max)
90{
91 m_bounds_min = bounds_min;
92 m_bounds_max = bounds_max;
93 m_dirty = true;
94}
95
96void SDFMeshProcessor::set_resolution(uint32_t res_x, uint32_t res_y, uint32_t res_z)
97{
98 m_res_x = std::max(res_x, 1U);
99 m_res_y = std::max(res_y, 1U);
100 m_res_z = std::max(res_z, 1U);
103 m_dirty = true;
104}
105
107{
108 m_iso_level = iso_level;
109 m_dirty = true;
110}
111
112void SDFMeshProcessor::set_axis_palette(const glm::vec3& x, const glm::vec3& y, const glm::vec3& z)
113{
114 m_palette = { x, y, z };
115 m_dirty = true;
116}
117
118// ============================================================================
119// ShaderProcessor hooks
120// ============================================================================
121
122void SDFMeshProcessor::on_attach(const std::shared_ptr<Buffer>& buffer)
123{
125
126 auto vk_buf = std::dynamic_pointer_cast<VKBuffer>(buffer);
127 if (!vk_buf) {
129 "SDFMeshProcessor requires a VKBuffer");
130 return;
131 }
132
133 if (m_owns_buffers)
135
136 bind_buffer("sdf_grid", m_grid_buf);
137 bind_buffer("edge_table", m_edge_buf);
138 bind_buffer("tri_table", m_tri_buf);
139 bind_buffer("vertices", vk_buf);
140 bind_buffer("counter", m_counter_buf);
141}
142
144{
145 std::vector<uint32_t> edge_flat(256);
146 for (size_t i = 0; i < 256; ++i)
147 edge_flat[i] = static_cast<uint32_t>(Kinesis::k_edge_table[i]);
148
149 std::vector<int32_t> tri_flat(static_cast<long>(256) * 16);
150 for (size_t i = 0; i < 256; ++i) {
151 for (size_t j = 0; j < 16; ++j)
152 tri_flat[i * 16 + j] = static_cast<int32_t>(Kinesis::k_tri_table[i][j]);
153 }
154
155 std::memcpy(m_edge_buf->get_mapped_ptr(), edge_flat.data(),
156 edge_flat.size() * sizeof(uint32_t));
157 std::memcpy(m_tri_buf->get_mapped_ptr(), tri_flat.data(),
158 tri_flat.size() * sizeof(int32_t));
159}
160
163 const std::shared_ptr<VKBuffer>& /*buffer*/)
164{
165 if (!m_dirty)
166 return false;
167
168 if (m_owns_buffers)
170
171 std::memset(m_counter_buf->get_mapped_ptr(), 0, sizeof(uint32_t));
172
173 const glm::vec3 extent = m_bounds_max - m_bounds_min;
174 const McPC pc {
176 .iso_level = m_iso_level,
177 .step = {
178 extent.x / static_cast<float>(m_res_x),
179 extent.y / static_cast<float>(m_res_y),
180 extent.z / static_cast<float>(m_res_z),
181 },
182 .res_x = m_res_x,
183 .res_y = m_res_y,
184 .res_z = m_res_z,
185 ._pad = 0,
186 .palette = {
187 glm::vec4(m_palette[0], 1.0F),
188 glm::vec4(m_palette[1], 1.0F),
189 glm::vec4(m_palette[2], 1.0F),
190 },
191 };
193
194 const uint32_t groups = (voxel_count() + 63U) / 64U;
195 set_manual_dispatch(groups, 1, 1);
196
197 return true;
198}
199
202 const std::shared_ptr<VKBuffer>& buffer)
203{
204 const auto n = *static_cast<const uint32_t*>(m_counter_buf->get_mapped_ptr());
205
206 if (auto rp = buffer->get_render_processor()) {
207 buffer->get_render_processor()->set_vertex_range(0, n);
208 } else {
210 "SDFMeshProcessor: no render processor attached to buffer, cannot set vertex count");
211 return;
212 }
213
214 m_dirty = false;
215
217 "SDFMeshProcessor: {} vertices extracted", n);
218}
219
220// ============================================================================
221// Private
222// ============================================================================
223
225{
228
229 m_grid_buf = std::make_shared<VKBuffer>(
230 corner_count() * sizeof(float),
231 VKBuffer::Usage::HOST_STORAGE,
233 svc->initialize_buffer(m_grid_buf);
234
235 m_edge_buf = std::make_shared<VKBuffer>(
236 256 * sizeof(uint32_t),
237 VKBuffer::Usage::HOST_STORAGE,
239 svc->initialize_buffer(m_edge_buf);
240
241 m_tri_buf = std::make_shared<VKBuffer>(
242 static_cast<long>(256) * 16 * sizeof(int32_t),
243 VKBuffer::Usage::HOST_STORAGE,
245 svc->initialize_buffer(m_tri_buf);
246
247 m_counter_buf = std::make_shared<VKBuffer>(
248 sizeof(uint32_t),
249 VKBuffer::Usage::HOST_STORAGE,
251 svc->initialize_buffer(m_counter_buf);
252}
253
255{
256 const uint32_t nx = m_res_x + 1;
257 const uint32_t ny = m_res_y + 1;
258 const uint32_t nz = m_res_z + 1;
259 const size_t total = static_cast<size_t>(nx) * ny * nz;
260
261 const glm::vec3 extent = m_bounds_max - m_bounds_min;
262 const glm::vec3 step {
263 extent.x / static_cast<float>(m_res_x),
264 extent.y / static_cast<float>(m_res_y),
265 extent.z / static_cast<float>(m_res_z),
266 };
267
268 auto* grid = static_cast<float*>(m_grid_buf->get_mapped_ptr());
269
270 MayaFlux::Parallel::for_each(std::execution::par_unseq,
271 std::views::iota(0UZ, total).begin(),
272 std::views::iota(0UZ, total).end(),
273 [&](size_t idx) {
274 const uint32_t gix = idx % nx;
275 const uint32_t giy = (idx / nx) % ny;
276 const uint32_t giz = idx / (static_cast<size_t>(nx) * ny);
277 grid[idx] = m_field(glm::vec3(
278 m_bounds_min.x + static_cast<float>(gix) * step.x,
279 m_bounds_min.y + static_cast<float>(giy) * step.y,
280 m_bounds_min.z + static_cast<float>(giz) * step.z));
281 });
282}
283
285{
288
289 m_edge_buf = std::make_shared<VKBuffer>(
290 256 * sizeof(uint32_t),
291 VKBuffer::Usage::HOST_STORAGE,
293 svc->initialize_buffer(m_edge_buf);
294
295 m_tri_buf = std::make_shared<VKBuffer>(
296 static_cast<long>(256) * 16 * sizeof(int32_t),
297 VKBuffer::Usage::HOST_STORAGE,
299 svc->initialize_buffer(m_tri_buf);
300}
301
302} // namespace MayaFlux::Buffers
#define MF_ERROR(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
virtual void on_attach(const std::shared_ptr< Buffer > &)
Called when this processor is attached to a buffer.
void set_dispatch_mode(ShaderDispatchConfig::DispatchMode mode)
Set dispatch mode.
void set_manual_dispatch(uint32_t x, uint32_t y=1, uint32_t z=1)
Set manual dispatch group counts.
Specialized ShaderProcessor for Compute Pipelines.
void set_axis_palette(const glm::vec3 &x, const glm::vec3 &y, const glm::vec3 &z)
Color each triangle by the dominant axis of its surface normal.
void set_bounds(const glm::vec3 &bounds_min, const glm::vec3 &bounds_max)
Replace the evaluation volume and mark dirty.
std::shared_ptr< VKBuffer > m_grid_buf
bool on_before_execute(Portal::Graphics::CommandBufferID cmd_id, const std::shared_ptr< VKBuffer > &buffer) override
Called before each process callback.
bool m_owns_buffers
false in GPU-field mode; buffers owned by SdfPrepProcessor.
void set_field(Kinesis::SpatialField field)
Replace the scalar field and mark dirty.
uint32_t corner_count() const noexcept
void on_descriptors_created() override
Called after descriptor sets are created.
std::shared_ptr< VKBuffer > m_tri_buf
SDFMeshProcessor(Kinesis::SpatialField field, const glm::vec3 &bounds_min, const glm::vec3 &bounds_max, uint32_t res_x, uint32_t res_y, uint32_t res_z, float iso_level)
std::shared_ptr< VKBuffer > m_counter_buf
std::array< glm::vec3, 3 > m_palette
uint32_t voxel_count() const noexcept
std::shared_ptr< VKBuffer > m_edge_buf
void on_attach(const std::shared_ptr< Buffer > &buffer) override
Called when this processor is attached to a buffer.
void on_after_execute(Portal::Graphics::CommandBufferID cmd_id, const std::shared_ptr< VKBuffer > &buffer) override
Called after each process callback.
void set_resolution(uint32_t res_x, uint32_t res_y, uint32_t res_z)
Replace the grid resolution and mark dirty.
void set_iso_level(float iso_level)
Replace the iso_level threshold and mark dirty.
void set_push_constant_data(const T &data)
Update push constant data (type-safe)
void bind_buffer(const std::string &descriptor_name, const std::shared_ptr< VKBuffer > &buffer)
Bind a VKBuffer to a named shader descriptor.
Interface * get_service()
Query for a backend service.
static BackendRegistry & instance()
Get the global registry instance.
@ BufferProcessing
Buffer processing (Buffers::BufferManager, processing chains)
@ Buffers
Buffers, Managers, processors and processing chains.
@ UNKNOWN
Unknown or undefined modality.
constexpr std::array< uint16_t, 256 > k_edge_table
constexpr std::array< std::array< int8_t, 16 >, 256 > k_tri_table
Describes how a VKBuffer binds to a shader descriptor.
std::unordered_map< std::string, ShaderBinding > bindings
Typed, composable, stateless callable from domain D to range R.
Definition Tendency.hpp:22
Backend buffer management service interface.