MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
SDFMeshProcessor.hpp
Go to the documentation of this file.
1#pragma once
2
4
6
7namespace MayaFlux::Buffers {
8
9/**
10 * @class SDFMeshProcessor
11 * @brief ComputeProcessor that dispatches mc_emit.comp directly into the
12 * owning VKBuffer (Usage::VERTEX), bypassing all CPU readback.
13 *
14 * Binding layout (matches mc_emit.comp):
15 * set=0, binding=0 SDF corner grid STORAGE (host-visible, written each dirty frame)
16 * set=0, binding=1 Edge table STORAGE (uploaded once at init)
17 * set=0, binding=2 Tri table STORAGE (uploaded once at init)
18 * set=0, binding=3 Vertex output STORAGE (the VKBuffer this processor is attached to)
19 * set=0, binding=4 Atomic vertex counter STORAGE (host-visible, read back after dispatch)
20 *
21 * The SDF grid is evaluated on CPU via a parallel for_each into the grid
22 * buffer's mapped pointer each dirty frame. No staging or upload call is
23 * needed: the buffer is eHostVisible | eHostCoherent.
24 *
25 * After dispatch, the counter buffer's mapped pointer is read to obtain the
26 * actual vertex count, which is forwarded to the owner via the callback
27 * supplied at construction.
28 *
29 * Dirtiness is managed by the owner. on_before_execute returns false when
30 * not dirty, suppressing dispatch for that frame.
31 */
32class MAYAFLUX_API SDFMeshProcessor : public ComputeProcessor {
33public:
34 /**
35 * @param field SpatialField evaluated on CPU each dirty frame.
36 * @param bounds_min World-space minimum corner.
37 * @param bounds_max World-space maximum corner.
38 * @param res_x Cell count along X (minimum 1).
39 * @param res_y Cell count along Y (minimum 1).
40 * @param res_z Cell count along Z (minimum 1).
41 * @param iso_level Isosurface threshold.
42 */
45 const glm::vec3& bounds_min,
46 const glm::vec3& bounds_max,
47 uint32_t res_x,
48 uint32_t res_y,
49 uint32_t res_z,
50 float iso_level);
51
52 /**
53 * @brief Construct in GPU-field mode with externally owned buffers.
54 *
55 * @p grid_buf and @p counter_buf are owned by SdfPrepProcessor and
56 * pre-zeroed before this processor runs. evaluate_grid() is never
57 * called in this mode.
58 *
59 * @param grid_buf Corner grid buffer written by SdfFieldProcessor.
60 * @param counter_buf Atomic vertex counter buffer, zeroed by SdfPrepProcessor.
61 * @param bounds_min World-space minimum corner.
62 * @param bounds_max World-space maximum corner.
63 * @param res_x Cell count along X.
64 * @param res_y Cell count along Y.
65 * @param res_z Cell count along Z.
66 * @param iso_level Isosurface threshold.
67 */
69 std::shared_ptr<VKBuffer> grid_buf,
70 std::shared_ptr<VKBuffer> counter_buf,
71 const glm::vec3& bounds_min,
72 const glm::vec3& bounds_max,
73 uint32_t res_x,
74 uint32_t res_y,
75 uint32_t res_z,
76 float iso_level);
77
78 ~SDFMeshProcessor() override = default;
79
80 /** @brief Replace the scalar field and mark dirty. */
81 void set_field(Kinesis::SpatialField field);
82
83 /** @brief Replace the evaluation volume and mark dirty. */
84 void set_bounds(const glm::vec3& bounds_min, const glm::vec3& bounds_max);
85
86 /**
87 * @brief Replace the grid resolution and mark dirty.
88 *
89 * Triggers recreation of the grid and counter buffers on the next attach
90 * or dirty frame. Descriptor rebuild is forced.
91 */
92 void set_resolution(uint32_t res_x, uint32_t res_y, uint32_t res_z);
93
94 /** @brief Replace the iso_level threshold and mark dirty. */
95 void set_iso_level(float iso_level);
96
97 /** @brief Force a re-dispatch on the next frame. */
98 void set_dirty() { m_dirty = true; }
99
100 [[nodiscard]] bool is_dirty() const { return m_dirty; }
101
102protected:
103 void on_attach(const std::shared_ptr<Buffer>& buffer) override;
104 void on_descriptors_created() override;
105 bool on_before_execute(
107 const std::shared_ptr<VKBuffer>& buffer) override;
108 void on_after_execute(
110 const std::shared_ptr<VKBuffer>& buffer) override;
111
112private:
114 glm::vec3 m_bounds_min;
115 glm::vec3 m_bounds_max;
116 uint32_t m_res_x;
117 uint32_t m_res_y;
118 uint32_t m_res_z;
120 bool m_dirty { true };
121 bool m_owns_buffers { true }; ///< false in GPU-field mode; buffers owned by SdfPrepProcessor.
122
123 std::shared_ptr<VKBuffer> m_grid_buf;
124 std::shared_ptr<VKBuffer> m_edge_buf;
125 std::shared_ptr<VKBuffer> m_tri_buf;
126 std::shared_ptr<VKBuffer> m_counter_buf;
127
128 struct McPC {
129 glm::vec3 bounds_min;
131 glm::vec3 step;
132 uint32_t res_x;
133 uint32_t res_y;
134 uint32_t res_z;
135 uint32_t _pad[2] {};
136 };
137 static_assert(sizeof(McPC) % 16 == 0);
138
139 void rebuild_owned_buffers();
140 void evaluate_grid();
141 void rebuild_lookup_buffers();
142
143 [[nodiscard]] uint32_t corner_count() const noexcept
144 {
145 return (m_res_x + 1) * (m_res_y + 1) * (m_res_z + 1);
146 }
147
148 [[nodiscard]] uint32_t voxel_count() const noexcept
149 {
150 return m_res_x * m_res_y * m_res_z;
151 }
152
153 [[nodiscard]] uint32_t worst_case_vertices() const noexcept
154 {
155 return voxel_count() * 15U;
156 }
157};
158
159} // namespace MayaFlux::Buffers
Specialized ShaderProcessor for Compute Pipelines.
~SDFMeshProcessor() override=default
std::shared_ptr< VKBuffer > m_grid_buf
void set_dirty()
Force a re-dispatch on the next frame.
uint32_t corner_count() const noexcept
std::shared_ptr< VKBuffer > m_tri_buf
std::shared_ptr< VKBuffer > m_counter_buf
uint32_t worst_case_vertices() const noexcept
uint32_t voxel_count() const noexcept
std::shared_ptr< VKBuffer > m_edge_buf
ComputeProcessor that dispatches mc_emit.comp directly into the owning VKBuffer (Usage::VERTEX),...
Typed, composable, stateless callable from domain D to range R.
Definition Tendency.hpp:22