MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
SDFMeshProcessor.cpp
Go to the documentation of this file.
2
4
6
11
13
14namespace MayaFlux::Buffers {
15
16// ============================================================================
17// Construction
18// ============================================================================
19
22 const glm::vec3& bounds_min,
23 const glm::vec3& bounds_max,
24 uint32_t res_x,
25 uint32_t res_y,
26 uint32_t res_z,
27 float iso_level)
28 : ComputeProcessor("mc_emit.comp.spv", 64)
29 , m_field(std::move(field))
30 , m_bounds_min(bounds_min)
31 , m_bounds_max(bounds_max)
32 , m_res_x(std::max(res_x, 1U))
33 , m_res_y(std::max(res_y, 1U))
34 , m_res_z(std::max(res_z, 1U))
35 , m_iso_level(iso_level)
36{
38
39 m_config.bindings["sdf_grid"] = ShaderBinding(0, 0, vk::DescriptorType::eStorageBuffer);
40 m_config.bindings["edge_table"] = ShaderBinding(0, 1, vk::DescriptorType::eStorageBuffer);
41 m_config.bindings["tri_table"] = ShaderBinding(0, 2, vk::DescriptorType::eStorageBuffer);
42 m_config.bindings["vertices"] = ShaderBinding(0, 3, vk::DescriptorType::eStorageBuffer);
43 m_config.bindings["counter"] = ShaderBinding(0, 4, vk::DescriptorType::eStorageBuffer);
44
46}
47
49 std::shared_ptr<VKBuffer> grid_buf,
50 std::shared_ptr<VKBuffer> counter_buf,
51 const glm::vec3& bounds_min,
52 const glm::vec3& bounds_max,
53 uint32_t res_x,
54 uint32_t res_y,
55 uint32_t res_z,
56 float iso_level)
57 : ComputeProcessor("mc_emit.comp.spv", 64)
58 , m_bounds_min(bounds_min)
59 , m_bounds_max(bounds_max)
60 , m_res_x(std::max(res_x, 1U))
61 , m_res_y(std::max(res_y, 1U))
62 , m_res_z(std::max(res_z, 1U))
63 , m_iso_level(iso_level)
64 , m_grid_buf(std::move(grid_buf))
65 , m_counter_buf(std::move(counter_buf))
66 , m_owns_buffers(false)
67{
69
70 m_config.bindings["sdf_grid"] = ShaderBinding(0, 0, vk::DescriptorType::eStorageBuffer);
71 m_config.bindings["edge_table"] = ShaderBinding(0, 1, vk::DescriptorType::eStorageBuffer);
72 m_config.bindings["tri_table"] = ShaderBinding(0, 2, vk::DescriptorType::eStorageBuffer);
73 m_config.bindings["vertices"] = ShaderBinding(0, 3, vk::DescriptorType::eStorageBuffer);
74 m_config.bindings["counter"] = ShaderBinding(0, 4, vk::DescriptorType::eStorageBuffer);
75
77
79}
80
81// ============================================================================
82// Setters
83// ============================================================================
84
86{
87 m_field = std::move(field);
88 m_dirty = true;
89}
90
91void SDFMeshProcessor::set_bounds(const glm::vec3& bounds_min, const glm::vec3& bounds_max)
92{
93 m_bounds_min = bounds_min;
94 m_bounds_max = bounds_max;
95 m_dirty = true;
96}
97
98void SDFMeshProcessor::set_resolution(uint32_t res_x, uint32_t res_y, uint32_t res_z)
99{
100 m_res_x = std::max(res_x, 1U);
101 m_res_y = std::max(res_y, 1U);
102 m_res_z = std::max(res_z, 1U);
105 m_dirty = true;
106}
107
109{
110 m_iso_level = iso_level;
111 m_dirty = true;
112}
113
114// ============================================================================
115// ShaderProcessor hooks
116// ============================================================================
117
118void SDFMeshProcessor::on_attach(const std::shared_ptr<Buffer>& buffer)
119{
121
122 auto vk_buf = std::dynamic_pointer_cast<VKBuffer>(buffer);
123 if (!vk_buf) {
125 "SDFMeshProcessor requires a VKBuffer");
126 return;
127 }
128
129 if (m_owns_buffers)
131
132 bind_buffer("sdf_grid", m_grid_buf);
133 bind_buffer("edge_table", m_edge_buf);
134 bind_buffer("tri_table", m_tri_buf);
135 bind_buffer("vertices", vk_buf);
136 bind_buffer("counter", m_counter_buf);
137}
138
140{
141 std::vector<uint32_t> edge_flat(256);
142 for (size_t i = 0; i < 256; ++i)
143 edge_flat[i] = static_cast<uint32_t>(Kinesis::k_edge_table[i]);
144
145 std::vector<int32_t> tri_flat(static_cast<long>(256) * 16);
146 for (size_t i = 0; i < 256; ++i) {
147 for (size_t j = 0; j < 16; ++j)
148 tri_flat[i * 16 + j] = static_cast<int32_t>(Kinesis::k_tri_table[i][j]);
149 }
150
151 std::memcpy(m_edge_buf->get_mapped_ptr(), edge_flat.data(),
152 edge_flat.size() * sizeof(uint32_t));
153 std::memcpy(m_tri_buf->get_mapped_ptr(), tri_flat.data(),
154 tri_flat.size() * sizeof(int32_t));
155}
156
159 const std::shared_ptr<VKBuffer>& /*buffer*/)
160{
161 if (!m_dirty)
162 return false;
163
164 if (m_owns_buffers)
166
167 std::memset(m_counter_buf->get_mapped_ptr(), 0, sizeof(uint32_t));
168
169 const glm::vec3 extent = m_bounds_max - m_bounds_min;
170 const McPC pc {
172 .iso_level = m_iso_level,
173 .step = {
174 extent.x / static_cast<float>(m_res_x),
175 extent.y / static_cast<float>(m_res_y),
176 extent.z / static_cast<float>(m_res_z),
177 },
178 .res_x = m_res_x,
179 .res_y = m_res_y,
180 .res_z = m_res_z,
181 };
183
184 const uint32_t groups = (voxel_count() + 63U) / 64U;
185 set_manual_dispatch(groups, 1, 1);
186
187 return true;
188}
189
192 const std::shared_ptr<VKBuffer>& buffer)
193{
194 const auto n = *static_cast<const uint32_t*>(m_counter_buf->get_mapped_ptr());
195
196 if (auto rp = buffer->get_render_processor()) {
197 buffer->get_render_processor()->set_vertex_range(0, n);
198 } else {
200 "SDFMeshProcessor: no render processor attached to buffer, cannot set vertex count");
201 return;
202 }
203
204 m_dirty = false;
205
207 "SDFMeshProcessor: {} vertices extracted", n);
208}
209
210// ============================================================================
211// Private
212// ============================================================================
213
215{
218
219 m_grid_buf = std::make_shared<VKBuffer>(
220 corner_count() * sizeof(float),
223 svc->initialize_buffer(m_grid_buf);
224
225 m_edge_buf = std::make_shared<VKBuffer>(
226 256 * sizeof(uint32_t),
229 svc->initialize_buffer(m_edge_buf);
230
231 m_tri_buf = std::make_shared<VKBuffer>(
232 static_cast<long>(256) * 16 * sizeof(int32_t),
235 svc->initialize_buffer(m_tri_buf);
236
237 m_counter_buf = std::make_shared<VKBuffer>(
238 sizeof(uint32_t),
241 svc->initialize_buffer(m_counter_buf);
242}
243
245{
246 const uint32_t nx = m_res_x + 1;
247 const uint32_t ny = m_res_y + 1;
248 const uint32_t nz = m_res_z + 1;
249 const size_t total = static_cast<size_t>(nx) * ny * nz;
250
251 const glm::vec3 extent = m_bounds_max - m_bounds_min;
252 const glm::vec3 step {
253 extent.x / static_cast<float>(m_res_x),
254 extent.y / static_cast<float>(m_res_y),
255 extent.z / static_cast<float>(m_res_z),
256 };
257
258 auto* grid = static_cast<float*>(m_grid_buf->get_mapped_ptr());
259
260 MayaFlux::Parallel::for_each(std::execution::par_unseq,
261 std::views::iota(0UZ, total).begin(),
262 std::views::iota(0UZ, total).end(),
263 [&](size_t idx) {
264 const uint32_t gix = idx % nx;
265 const uint32_t giy = (idx / nx) % ny;
266 const uint32_t giz = idx / (static_cast<size_t>(nx) * ny);
267 grid[idx] = m_field(glm::vec3(
268 m_bounds_min.x + static_cast<float>(gix) * step.x,
269 m_bounds_min.y + static_cast<float>(giy) * step.y,
270 m_bounds_min.z + static_cast<float>(giz) * step.z));
271 });
272}
273
275{
278
279 m_edge_buf = std::make_shared<VKBuffer>(
280 256 * sizeof(uint32_t),
283 svc->initialize_buffer(m_edge_buf);
284
285 m_tri_buf = std::make_shared<VKBuffer>(
286 static_cast<long>(256) * 16 * sizeof(int32_t),
289 svc->initialize_buffer(m_tri_buf);
290}
291
292} // 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_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
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.
@ HOST_STORAGE
Host-visible storage buffer (eStorageBuffer + eHostVisible|eHostCoherent)
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.