MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
SDFNode.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "MeshWriterNode.hpp"
4
6
8
9/**
10 * @class SDFNode
11 * @brief MeshWriterNode that extracts a TRIANGLE_LIST isosurface from a
12 * Kinesis::SpatialField each frame via marching cubes.
13 *
14 * The field is any glm::vec3 -> float callable wrapped in a SpatialField.
15 * Kinesis::TendencyFactories and composition operators (combine, chain,
16 * select) provide the full vocabulary without any new types.
17 *
18 * The grid is re-evaluated and a new mesh extracted only when the node is
19 * marked dirty by a setter call. compute_frame() is otherwise a no-op,
20 * making the node safe to tick at VISUAL_RATE for static fields.
21 *
22 * Usage:
23 * @code
24 * auto node = std::make_shared<SDFNode>(
25 * Kinesis::SpatialField { .fn = [](const glm::vec3& p) {
26 * return glm::length(p) - 1.0F; // unit sphere
27 * }},
28 * glm::vec3(-1.5F), glm::vec3(1.5F),
29 * 32, 32, 32);
30 *
31 * auto buf = vega.GeometryBuffer(node) | Graphics;
32 * buf->setup_rendering({ .target_window = window });
33 * @endcode
34 *
35 * Audio-reactive deformation:
36 * @code
37 * auto radius = make_persistent_shared<std::atomic<float>>(1.0F);
38 *
39 * node->set_field(Kinesis::SpatialField { .fn = [radius](const glm::vec3& p) {
40 * return glm::length(p) - radius->load(std::memory_order_relaxed);
41 * }});
42 *
43 * // Audio metro writes radius, graphics metro marks node dirty.
44 * @endcode
45 */
46class MAYAFLUX_API SDFNode : public MeshWriterNode {
47public:
48 /**
49 * @brief Construct and evaluate the initial isosurface.
50 *
51 * @param field SpatialField: glm::vec3 -> float.
52 * @param bounds_min World-space minimum corner of the evaluation volume.
53 * @param bounds_max World-space maximum corner of the evaluation volume.
54 * @param res_x Cell count along X. Clamped to minimum 1.
55 * @param res_y Cell count along Y. Clamped to minimum 1.
56 * @param res_z Cell count along Z. Clamped to minimum 1.
57 * @param iso_level Isosurface threshold. Default 0.0.
58 */
59 SDFNode(
61 const glm::vec3& bounds_min,
62 const glm::vec3& bounds_max,
63 uint32_t res_x,
64 uint32_t res_y,
65 uint32_t res_z,
66 float iso_level = 0.0F);
67
68 ~SDFNode() override = default;
69
70 /**
71 * @brief Replace the scalar field and mark dirty.
72 * @param field New SpatialField.
73 */
74 void set_field(Kinesis::SpatialField field);
75
76 /**
77 * @brief Replace the evaluation volume and mark dirty.
78 * @param bounds_min New minimum corner.
79 * @param bounds_max New maximum corner.
80 */
81 void set_bounds(const glm::vec3& bounds_min, const glm::vec3& bounds_max);
82
83 /**
84 * @brief Replace the grid resolution and mark dirty.
85 * @param res_x Cell count along X. Clamped to minimum 1.
86 * @param res_y Cell count along Y. Clamped to minimum 1.
87 * @param res_z Cell count along Z. Clamped to minimum 1.
88 */
89 void set_resolution(uint32_t res_x, uint32_t res_y, uint32_t res_z);
90
91 /**
92 * @brief Replace the iso_level threshold and mark dirty.
93 * @param iso_level New threshold value.
94 */
95 void set_iso_level(float iso_level);
96
97 /**
98 * @brief Re-extract the isosurface if dirty, then upload via parent.
99 */
100 void compute_frame() override;
101
102private:
104 glm::vec3 m_bounds_min;
105 glm::vec3 m_bounds_max;
106 uint32_t m_res_x;
107 uint32_t m_res_y;
108 uint32_t m_res_z;
110 bool m_dirty { false };
111
112 void rebuild();
113};
114
115} // namespace MayaFlux::Nodes::GpuSync
Indexed triangle mesh for static or infrequently-updated geometry.
Kinesis::SpatialField m_field
Definition SDFNode.hpp:103
MeshWriterNode that extracts a TRIANGLE_LIST isosurface from a Kinesis::SpatialField each frame via m...
Definition SDFNode.hpp:46
Typed, composable, stateless callable from domain D to range R.
Definition Tendency.hpp:22