MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
ComputeMeshBuffer.hpp
Go to the documentation of this file.
1#pragma once
2
7
8namespace MayaFlux::Buffers {
9
10class RenderProcessor;
11class SDFPrepProcessor;
12class SDFFieldProcessor;
13class SDFMeshProcessor;
14
15/**
16 * @class ComputeMeshBuffer
17 * @brief VKBuffer that evaluates a SpatialField isosurface via marching cubes
18 * on the GPU and renders directly without CPU readback.
19 *
20 * SDFMeshProcessor dispatches mc_emit.comp into this buffer each dirty frame.
21 * RenderProcessor draws from the same VKBuffer. No CPU-GPU round-trip occurs
22 * after the initial lookup table upload.
23 *
24 * Config::source picks where the field is evaluated. A SpatialField is
25 * evaluated on the CPU into the grid whenever the buffer is dirty. A path
26 * names a field compute shader, and an MF_FIELD, MF_FIELD_T or MF_FIELD_P
27 * field is lowered to one; both fill the grid on the GPU and are driven
28 * through get_field_processor(). The surface is re-extracted only when dirty.
29 *
30 * One MF_FIELD serves both evaluators: pass the field itself for the GPU, or
31 * its cpu member for the CPU. A temporal field reads the processor's time,
32 * and a parametric field also reads its parameter block, set with set_params.
33 *
34 * Usage:
35 * @code
36 * auto buf = std::make_shared<ComputeMeshBuffer>(ComputeMeshBuffer::Config {
37 * .source = make_field(),
38 * .bounds_min = glm::vec3(-1.6F),
39 * .bounds_max = glm::vec3(1.6F),
40 * .resolution_x = 40,
41 * .resolution_y = 40,
42 * .resolution_z = 40,
43 * }) | Graphics;
44 * buf->setup_rendering({ .target_window = window });
45 *
46 * schedule_metro(1.0 / 60.0, [buf, make_field]() {
47 * buf->set_field(make_field());
48 * buf->set_dirty();
49 * }, "sdf_anim", Vruta::ProcessingToken::FRAME_ACCURATE);
50 * @endcode
51 */
52class MAYAFLUX_API ComputeMeshBuffer : public VKBuffer {
53public:
54 using FieldSource = std::variant<
56 std::filesystem::path,
60
61 struct Config {
63 glm::vec3 bounds_min { -1.0F };
64 glm::vec3 bounds_max { 1.0F };
65 uint32_t resolution_x { 32 };
66 uint32_t resolution_y { 32 };
67 uint32_t resolution_z { 32 };
68 float iso_level { 0.0F };
69 };
70
71 explicit ComputeMeshBuffer(Config config);
72
73 /** @brief Access the field processor to drive time or bounds from a metro. */
74 [[nodiscard]] std::shared_ptr<SDFFieldProcessor> get_field_processor() const
75 {
76 return m_field_processor;
77 }
78
79 /**
80 * @brief The marching-cubes stage, valid after setup_processors().
81 *
82 * Holds the atomic vertex counter buffer (SDFMeshProcessor::counter_buf())
83 * a readback needs to size itself correctly, since this buffer's own
84 * get_size_bytes() reflects worst-case allocated capacity, not the live
85 * count from the most recent dispatch.
86 */
87 [[nodiscard]] std::shared_ptr<SDFMeshProcessor> get_mesh_processor() const
88 {
89 return m_sdf_processor;
90 }
91
92 /**
93 * @brief The live vertex count from the most recent dispatch.
94 *
95 * get_size_bytes() and the vertex layout describe worst-case capacity; this
96 * is the count a readback must be sized to.
97 *
98 * @return The count, or nullopt before setup_processors() or when the counter is not mapped.
99 */
100 [[nodiscard]] std::optional<uint32_t> get_live_vertex_count() const;
101
102 ~ComputeMeshBuffer() override = default;
103
104 void setup_processors(ProcessingToken token) override;
105
106 /**
107 * @brief Create the RenderProcessor and attach it to the processing chain.
108 * @param config At minimum, supply target_window. Shader paths default to
109 * triangle.vert.spv / triangle.frag.spv (or mesh_textured.frag.spv
110 * when a texture has been set).
111 */
112 void setup_rendering(const RenderConfig& config);
113
114 // -------------------------------------------------------------------------
115 // Field and geometry control
116 // -------------------------------------------------------------------------
117
118 /** @brief Replace the scalar field and mark dirty. */
119 void set_field(Kinesis::SpatialField field);
120
121 /** @brief Replace the evaluation volume and mark dirty. */
122 void set_bounds(const glm::vec3& bounds_min, const glm::vec3& bounds_max);
123
124 /**
125 * @brief Replace the grid resolution.
126 *
127 * Resizes the internal grid and counter buffers. Marks dirty.
128 */
129 void set_resolution(uint32_t res_x, uint32_t res_y, uint32_t res_z);
130
131 /** @brief Replace the iso_level threshold and mark dirty. */
132 void set_iso_level(float iso_level);
133
134 /** @brief Request a re-dispatch on the next graphics frame. */
135 void set_dirty();
136
137 // -------------------------------------------------------------------------
138 // Texture
139 // -------------------------------------------------------------------------
140
141 /**
142 * @brief Bind a diffuse texture sampled in the fragment shader.
143 * @param image GPU image (nullptr clears the binding).
144 * @param binding Descriptor name (default: "diffuseTex").
145 *
146 * Selects mesh_textured.frag.spv when setup_rendering is called after this.
147 * Calling after setup_rendering forwards the binding to RenderProcessor directly.
148 */
149 void set_texture(
150 std::shared_ptr<Core::VKImage> image,
151 std::string binding = "diffuseTex");
152
153 /** @brief Check if a diffuse texture is bound. */
154 [[nodiscard]] bool has_diffuse_texture() const noexcept { return m_diffuse_texture != nullptr; }
155
156 /** @brief Diffuse texture is optional, so may return nullptr. */
157 [[nodiscard]] std::shared_ptr<Core::VKImage> get_diffuse_texture() const noexcept { return m_diffuse_texture; }
158
159private:
160 uint32_t m_res_x;
161 uint32_t m_res_y;
162 uint32_t m_res_z;
163
164 std::shared_ptr<SDFMeshProcessor> m_sdf_processor;
165
166 std::shared_ptr<Core::VKImage> m_diffuse_texture;
167 std::string m_diffuse_binding { "diffuseTex" };
168
169 bool m_gpu_field {};
170 std::shared_ptr<SDFPrepProcessor> m_prep_processor;
171 std::shared_ptr<SDFFieldProcessor> m_field_processor;
172
173 std::string m_field_shader;
174 std::optional<Kinesis::FieldSource> m_field_expression;
175
176 // Field parameters held until m_sdf_processor is constructed.
178 glm::vec3 m_bounds_min;
179 glm::vec3 m_bounds_max;
181
182 [[nodiscard]] static size_t worst_case_bytes(
183 uint32_t res_x, uint32_t res_y, uint32_t res_z) noexcept
184 {
185 return static_cast<size_t>(res_x) * res_y * res_z * 15U * sizeof(Kakshya::MeshVertex);
186 }
187};
188
189} // namespace MayaFlux::Buffers
IO::ImageData image
Definition Decoder.cpp:47
std::shared_ptr< SDFFieldProcessor > get_field_processor() const
Access the field processor to drive time or bounds from a metro.
std::shared_ptr< SDFMeshProcessor > m_sdf_processor
std::shared_ptr< SDFFieldProcessor > m_field_processor
std::shared_ptr< SDFMeshProcessor > get_mesh_processor() const
The marching-cubes stage, valid after setup_processors().
static size_t worst_case_bytes(uint32_t res_x, uint32_t res_y, uint32_t res_z) noexcept
std::shared_ptr< Core::VKImage > get_diffuse_texture() const noexcept
Diffuse texture is optional, so may return nullptr.
std::variant< Kinesis::SpatialField, std::filesystem::path, Kinesis::DualSpatialField, Kinesis::TemporalSpatialField, Kinesis::ParametricSpatialField > FieldSource
std::shared_ptr< Core::VKImage > m_diffuse_texture
std::shared_ptr< SDFPrepProcessor > m_prep_processor
bool has_diffuse_texture() const noexcept
Check if a diffuse texture is bound.
std::optional< Kinesis::FieldSource > m_field_expression
VKBuffer that evaluates a SpatialField isosurface via marching cubes on the GPU and renders directly ...
Vulkan-backed buffer wrapper used in processing chains.
Definition VKBuffer.hpp:76
ProcessingToken
Bitfield enum defining processing characteristics and backend requirements for buffer operations.
Vertex type for indexed triangle mesh primitives (TRIANGLE_LIST topology)
One authored expression carried as both a host callable and shader text.
Definition DualField.hpp:77
An authored expression of position, time and a parameter block, shader-only.
An authored expression of position and time, shader-only.
Typed, composable, stateless callable from domain D to range R.
Definition Tendency.hpp:22
Unified rendering configuration for graphics buffers.