MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
ComputeMeshBuffer.hpp
Go to the documentation of this file.
1#pragma once
2
6
7namespace MayaFlux::Buffers {
8
9class RenderProcessor;
10class SDFPrepProcessor;
11class SDFFieldProcessor;
12class SDFMeshProcessor;
13
14/**
15 * @class ComputeMeshBuffer
16 * @brief VKBuffer that evaluates a SpatialField isosurface via marching cubes
17 * on the GPU and renders directly without CPU readback.
18 *
19 * SDFMeshProcessor dispatches mc_emit.comp into this buffer each dirty frame.
20 * RenderProcessor draws from the same VKBuffer. No CPU-GPU round-trip occurs
21 * after the initial lookup table upload.
22 *
23 * Usage:
24 * @code
25 * auto buf = std::make_shared<ComputeMeshBuffer>(
26 * make_field(), glm::vec3(-1.6F), glm::vec3(1.6F), 40, 40, 40)
27 * | Graphics;
28 * buf->setup_rendering({ .target_window = window });
29 *
30 * schedule_metro(1.0 / 60.0, [buf, make_field]() {
31 * buf->set_field(make_field());
32 * buf->set_dirty();
33 * }, "sdf_anim", Vruta::ProcessingToken::FRAME_ACCURATE);
34 * @endcode
35 */
36class MAYAFLUX_API ComputeMeshBuffer : public VKBuffer {
37public:
38 /**
39 * @param field SpatialField evaluated on CPU each dirty frame.
40 * @param bounds_min World-space minimum corner.
41 * @param bounds_max World-space maximum corner.
42 * @param res_x Cell count along X (minimum 1).
43 * @param res_y Cell count along Y (minimum 1).
44 * @param res_z Cell count along Z (minimum 1).
45 * @param iso_level Isosurface threshold (default 0.0).
46 */
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 = 0.0F);
55
56 /**
57 * @brief Construct in GPU-field mode.
58 *
59 * No SpatialField is evaluated on CPU. sdf_field.comp evaluates the field
60 * entirely on the GPU each dirty frame. Animate by calling
61 * get_field_processor()->set_time(t) from a metro callback.
62 *
63 * Chain order:
64 * default — SdfPrepProcessor (allocates + zeroes grid/counter)
65 * pre — SdfFieldProcessor (dispatches sdf_field.comp → grid)
66 * flat[0] — SDFMeshProcessor (mc_emit → vertices)
67 * final — RenderProcessor
68 *
69 * @param bounds_min World-space minimum corner.
70 * @param bounds_max World-space maximum corner.
71 * @param res_x Cell count along X (minimum 1).
72 * @param res_y Cell count along Y (minimum 1).
73 * @param res_z Cell count along Z (minimum 1).
74 * @param iso_level Isosurface threshold (default 0.0).
75 * @param field_shader Optional compute shader for field evaluation (default "sdf_field.comp").
76 */
78 const glm::vec3& bounds_min,
79 const glm::vec3& bounds_max,
80 uint32_t res_x,
81 uint32_t res_y,
82 uint32_t res_z,
83 float iso_level = 0.0F,
84 std::string field_shader = "sdf_field_gyroid.comp");
85
86 /** @brief Access the field processor to drive time or bounds from a metro. */
87 [[nodiscard]] std::shared_ptr<SDFFieldProcessor> get_field_processor() const
88 {
89 return m_field_processor;
90 }
91
92 ~ComputeMeshBuffer() override = default;
93
94 void setup_processors(ProcessingToken token) override;
95
96 /**
97 * @brief Create the RenderProcessor and attach it to the processing chain.
98 * @param config At minimum, supply target_window. Shader paths default to
99 * triangle.vert.spv / triangle.frag.spv (or mesh_textured.frag.spv
100 * when a texture has been set).
101 */
102 void setup_rendering(const RenderConfig& config);
103
104 // -------------------------------------------------------------------------
105 // Field and geometry control
106 // -------------------------------------------------------------------------
107
108 /** @brief Replace the scalar field and mark dirty. */
109 void set_field(Kinesis::SpatialField field);
110
111 /** @brief Replace the evaluation volume and mark dirty. */
112 void set_bounds(const glm::vec3& bounds_min, const glm::vec3& bounds_max);
113
114 /**
115 * @brief Replace the grid resolution.
116 *
117 * Resizes the internal grid and counter buffers. Marks dirty.
118 */
119 void set_resolution(uint32_t res_x, uint32_t res_y, uint32_t res_z);
120
121 /** @brief Replace the iso_level threshold and mark dirty. */
122 void set_iso_level(float iso_level);
123
124 /** @brief Request a re-dispatch on the next graphics frame. */
125 void set_dirty();
126
127 // -------------------------------------------------------------------------
128 // Texture
129 // -------------------------------------------------------------------------
130
131 /**
132 * @brief Bind a diffuse texture sampled in the fragment shader.
133 * @param image GPU image (nullptr clears the binding).
134 * @param binding Descriptor name (default: "diffuseTex").
135 *
136 * Selects mesh_textured.frag.spv when setup_rendering is called after this.
137 * Calling after setup_rendering forwards the binding to RenderProcessor directly.
138 */
139 void set_texture(
140 std::shared_ptr<Core::VKImage> image,
141 std::string binding = "diffuseTex");
142
143private:
144 uint32_t m_res_x;
145 uint32_t m_res_y;
146 uint32_t m_res_z;
147
148 std::shared_ptr<SDFMeshProcessor> m_sdf_processor;
149
150 std::shared_ptr<Core::VKImage> m_diffuse_texture;
151 std::string m_diffuse_binding { "diffuseTex" };
152
153 bool m_gpu_field {};
154 std::shared_ptr<SDFPrepProcessor> m_prep_processor;
155 std::shared_ptr<SDFFieldProcessor> m_field_processor;
156
157 std::string m_field_shader;
158
159 // Field parameters held until m_sdf_processor is constructed.
161 glm::vec3 m_bounds_min;
162 glm::vec3 m_bounds_max;
164
165 [[nodiscard]] static size_t worst_case_bytes(
166 uint32_t res_x, uint32_t res_y, uint32_t res_z) noexcept
167 {
168 return static_cast<size_t>(res_x) * res_y * res_z * 15U * sizeof(Kakshya::MeshVertex);
169 }
170};
171
172} // namespace MayaFlux::Buffers
IO::ImageData image
Definition Decoder.cpp:57
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
static size_t worst_case_bytes(uint32_t res_x, uint32_t res_y, uint32_t res_z) noexcept
std::shared_ptr< Core::VKImage > m_diffuse_texture
std::shared_ptr< SDFPrepProcessor > m_prep_processor
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:67
ProcessingToken
Bitfield enum defining processing characteristics and backend requirements for buffer operations.
Vertex type for indexed triangle mesh primitives (TRIANGLE_LIST topology)
Typed, composable, stateless callable from domain D to range R.
Definition Tendency.hpp:22
Unified rendering configuration for graphics buffers.