MayaFlux 0.5.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
102 /**
103 * @brief Color each triangle by the dominant axis of its surface normal.
104 * @param x Color for surfaces facing along X.
105 * @param y Color for surfaces facing along Y.
106 * @param z Color for surfaces facing along Z.
107 *
108 * Selection is a hard choice rather than a blend, so the surface
109 * resolves into flat regions that switch as the geometry turns.
110 * Three identical colors give a flat surface, which is what the
111 * default reproduces. Takes effect next cycle.
112 */
113 void set_axis_palette(const glm::vec3& x, const glm::vec3& y, const glm::vec3& z);
114
115 /** @brief The three axis colors currently written into vertex color. */
116 [[nodiscard]] const std::array<glm::vec3, 3>& get_axis_palette() const { return m_palette; }
117
118protected:
119 void on_attach(const std::shared_ptr<Buffer>& buffer) override;
120 void on_descriptors_created() override;
121 bool on_before_execute(
123 const std::shared_ptr<VKBuffer>& buffer) override;
124 void on_after_execute(
126 const std::shared_ptr<VKBuffer>& buffer) override;
127
128private:
130 glm::vec3 m_bounds_min;
131 glm::vec3 m_bounds_max;
132 uint32_t m_res_x;
133 uint32_t m_res_y;
134 uint32_t m_res_z;
136 bool m_dirty { true };
137 bool m_owns_buffers { true }; ///< false in GPU-field mode; buffers owned by SdfPrepProcessor.
138 std::array<glm::vec3, 3> m_palette { glm::vec3(1.0F), glm::vec3(1.0F), glm::vec3(1.0F) };
139
140 std::shared_ptr<VKBuffer> m_grid_buf;
141 std::shared_ptr<VKBuffer> m_edge_buf;
142 std::shared_ptr<VKBuffer> m_tri_buf;
143 std::shared_ptr<VKBuffer> m_counter_buf;
144
145 struct McPC {
146 glm::vec3 bounds_min;
148 glm::vec3 step;
149 uint32_t res_x;
150 uint32_t res_y;
151 uint32_t res_z;
152 uint32_t _pad {};
153 alignas(16) glm::vec4 palette[3] {}; ///< Axis-selected vertex colors, X then Y then Z.
154 };
155 static_assert(sizeof(McPC) % 16 == 0);
156
157 void rebuild_owned_buffers();
158 void evaluate_grid();
159 void rebuild_lookup_buffers();
160
161 [[nodiscard]] uint32_t corner_count() const noexcept
162 {
163 return (m_res_x + 1) * (m_res_y + 1) * (m_res_z + 1);
164 }
165
166 [[nodiscard]] uint32_t voxel_count() const noexcept
167 {
168 return m_res_x * m_res_y * m_res_z;
169 }
170
171 [[nodiscard]] uint32_t worst_case_vertices() const noexcept
172 {
173 return voxel_count() * 15U;
174 }
175};
176
177} // namespace MayaFlux::Buffers
Specialized ShaderProcessor for Compute Pipelines.
const std::array< glm::vec3, 3 > & get_axis_palette() const
The three axis colors currently written into vertex color.
~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