MayaFlux 0.1.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
ParticleNetwork.hpp
Go to the documentation of this file.
1#pragma once
2
4#include "NodeNetwork.hpp"
5
6namespace MayaFlux::Nodes {
7
8/**
9 * @class ParticleNetwork
10 * @brief Network of particles with physics simulation
11 *
12 * CONCEPT:
13 * ========
14 * N-body particle system where each particle is a PointNode (GeometryWriterNode).
15 * Particles can interact based on topology (spatial forces, springs, etc.)
16 * or remain independent (ballistic motion).
17 *
18 * TOPOLOGY USAGE:
19 * ===============
20 * - INDEPENDENT: No inter-particle forces (pure ballistic motion)
21 * - SPATIAL: Particles within radius interact (flocking, springs, repulsion)
22 * - GRID_2D/3D: Fixed neighbor relationships (cloth, lattice)
23 * - RING/CHAIN: Sequential connections (rope, chain simulation)
24 * - CUSTOM: User-defined force topology
25 *
26 * PARAMETER MAPPING:
27 * ==================
28 * External nodes can control particle behavior:
29 *
30 * BROADCAST (one node → all particles):
31 * - "gravity": Global gravity strength
32 * - "drag": Air resistance coefficient
33 * - "turbulence": Chaos/noise strength
34 * - "attraction": Global attraction point strength
35 *
36 * ONE_TO_ONE (network → per-particle control):
37 * - "force_x/y/z": Per-particle force application
38 * - "color": Per-particle color (from audio spectrum, etc.)
39 * - "size": Per-particle size modulation
40 * - "mass": Per-particle mass override
41 *
42 * USAGE:
43 * ======
44 * ```cpp
45 * // Create 1000 particles with spatial interaction
46 * auto particles = std::make_shared<ParticleNetwork>(
47 * 1000,
48 * glm::vec3(-10, -10, -10), // bounds min
49 * glm::vec3(10, 10, 10) // bounds max
50 * );
51 * particles->set_topology(Topology::SPATIAL);
52 * particles->set_interaction_radius(2.0F);
53 * particles->set_output_mode(OutputMode::GRAPHICS_BIND);
54 *
55 * // Audio-reactive turbulence
56 * auto mic = vega.AudioInput();
57 * auto amplitude = vega.Envelope(mic);
58 * particles->map_parameter("turbulence", amplitude, MappingMode::BROADCAST);
59 *
60 * node_graph_manager->add_network(particles, ProcessingToken::VISUAL_RATE);
61 * ```
62 */
63class MAYAFLUX_API ParticleNetwork : public NodeNetwork {
64public:
65 /**
66 * @struct ParticleNode
67 * @brief Single particle with physics state
68 */
69 struct ParticleNode {
70 std::shared_ptr<GpuSync::PointNode> point; ///< Actual GeometryWriterNode
71
72 glm::vec3 velocity { 0.0F }; ///< Current velocity
73 glm::vec3 acceleration { 0.0F }; ///< Current acceleration
74 glm::vec3 force { 0.0F }; ///< Accumulated force this frame
75
76 float mass = 1.0F; ///< Particle mass
77 size_t index; ///< Index in network
78 };
79
80 /**
81 * @enum BoundsMode
82 * @brief How particles behave at spatial bounds
83 */
84 enum class BoundsMode : uint8_t {
85 NONE, ///< No bounds checking
86 BOUNCE, ///< Reflect off boundaries
87 WRAP, ///< Teleport to opposite side
88 CLAMP, ///< Stop at boundary
89 DESTROY ///< Remove particle at boundary (respawn optional)
90 };
91
92 /**
93 * @enum InitializationMode
94 * @brief Particle spawn distribution
95 */
96 enum class InitializationMode : uint8_t {
97 RANDOM_VOLUME, ///< Random positions in bounds volume
98 RANDOM_SURFACE, ///< Random positions on bounds surface
99 GRID, ///< Regular grid distribution
100 SPHERE_VOLUME, ///< Random in sphere
101 SPHERE_SURFACE, ///< Random on sphere surface
102 CUSTOM ///< User-provided initialization function
103 };
104
105 //-------------------------------------------------------------------------
106 // Construction
107 //-------------------------------------------------------------------------
108
109 /**
110 * @brief Create particle network with spatial bounds
111 * @param num_particles Number of particles
112 * @param bounds_min Minimum spatial extent
113 * @param bounds_max Maximum spatial extent
114 * @param init_mode Initialization distribution
115 */
117 size_t num_particles,
118 const glm::vec3& bounds_min = glm::vec3(-10.0F),
119 const glm::vec3& bounds_max = glm::vec3(10.0F),
120 InitializationMode init_mode = InitializationMode::RANDOM_VOLUME);
121
122 //-------------------------------------------------------------------------
123 // NodeNetwork Interface Implementation
124 //-------------------------------------------------------------------------
125
126 void process_batch(unsigned int num_samples) override;
127
128 [[nodiscard]] size_t get_node_count() const override
129 {
130 return m_particles.size();
131 }
132
133 void initialize() override;
134 void reset() override;
135
136 [[nodiscard]] std::unordered_map<std::string, std::string>
137 get_metadata() const override;
138
139 [[nodiscard]] std::optional<double> get_node_output(size_t index) const override;
140
141 //-------------------------------------------------------------------------
142 // Parameter Mapping
143 //-------------------------------------------------------------------------
144
145 void map_parameter(
146 const std::string& param_name,
147 const std::shared_ptr<Node>& source,
148 MappingMode mode = MappingMode::BROADCAST) override;
149
150 void map_parameter(
151 const std::string& param_name,
152 const std::shared_ptr<NodeNetwork>& source_network) override;
153
154 void unmap_parameter(const std::string& param_name) override;
155
156 //-------------------------------------------------------------------------
157 // Particle Access
158 //-------------------------------------------------------------------------
159
160 /**
161 * @brief Get all particles (read-only for NetworkGeometryBuffer)
162 */
163 [[nodiscard]] const std::vector<ParticleNode>& get_particles() const
164 {
165 return m_particles;
166 }
167
168 /**
169 * @brief Get specific particle
170 */
171 [[nodiscard]] const ParticleNode& get_particle(size_t index) const
172 {
173 return m_particles.at(index);
174 }
175
176 /**
177 * @brief Get mutable particle (for custom manipulation)
178 */
179 [[nodiscard]] ParticleNode& get_particle_mut(size_t index)
180 {
181 return m_particles.at(index);
182 }
183
184 //-------------------------------------------------------------------------
185 // Physics Configuration
186 //-------------------------------------------------------------------------
187
188 /**
189 * @brief Set global gravity vector
190 */
191 void set_gravity(const glm::vec3& gravity) { m_gravity = gravity; }
192
193 /**
194 * @brief Get current gravity
195 */
196 [[nodiscard]] glm::vec3 get_gravity() const { return m_gravity; }
197
198 /**
199 * @brief Set drag coefficient (0.0 = no drag, 1.0 = full drag)
200 */
201 void set_drag(float drag) { m_drag = glm::clamp(drag, 0.0F, 1.0F); }
202
203 /**
204 * @brief Get current drag
205 */
206 [[nodiscard]] float get_drag() const { return m_drag; }
207
208 /**
209 * @brief Set spatial bounds
210 */
211 void set_bounds(const glm::vec3& min, const glm::vec3& max)
212 {
213 m_bounds_min = min;
214 m_bounds_max = max;
215 }
216
217 /**
218 * @brief Set bounds behavior
219 */
220 void set_bounds_mode(BoundsMode mode) { m_bounds_mode = mode; }
221
222 /**
223 * @brief Set interaction radius (for SPATIAL topology)
224 */
225 void set_interaction_radius(float radius)
226 {
227 m_interaction_radius = radius;
228 m_neighbor_map_dirty = true;
229 }
230
231 /**
232 * @brief Set spring stiffness (for SPATIAL/GRID topologies)
233 */
234 void set_spring_stiffness(float stiffness)
235 {
236 m_spring_stiffness = stiffness;
237 }
238
239 /**
240 * @brief Set repulsion strength (for SPATIAL topology)
241 */
242 void set_repulsion_strength(float strength)
243 {
244 m_repulsion_strength = strength;
245 }
246
247 /**
248 * @brief Set attraction point (particles pulled toward this point)
249 */
250 void set_attraction_point(const glm::vec3& point)
251 {
252 m_attraction_point = point;
253 m_has_attraction_point = true;
254 }
255
256 /**
257 * @brief Disable attraction point
258 */
260 {
261 m_has_attraction_point = false;
262 }
263
264 /**
265 * @brief Set time step for physics integration
266 */
267 void set_timestep(float dt) { m_timestep = dt; }
268
269 //-------------------------------------------------------------------------
270 // Particle Control
271 //-------------------------------------------------------------------------
272
273 /**
274 * @brief Apply impulse to all particles
275 */
276 void apply_global_impulse(const glm::vec3& impulse);
277
278 /**
279 * @brief Apply impulse to specific particle
280 */
281 void apply_impulse(size_t index, const glm::vec3& impulse);
282
283 /**
284 * @brief Reinitialize all particle positions
285 */
286 void reinitialize_positions(InitializationMode mode);
287
288 /**
289 * @brief Reset all velocities to zero
290 */
291 void reset_velocities();
292
293private:
294 //-------------------------------------------------------------------------
295 // Internal State
296 //-------------------------------------------------------------------------
297
298 std::vector<ParticleNode> m_particles;
299
300 // Physics parameters
301 glm::vec3 m_gravity { 0.0F, -9.8F, 0.0F };
302 float m_drag = 0.01F;
303 float m_timestep = 0.016F; // ~60Fps default
304
305 // Spatial bounds
306 glm::vec3 m_bounds_min { -10.0F };
307 glm::vec3 m_bounds_max { 10.0F };
308 BoundsMode m_bounds_mode = BoundsMode::BOUNCE;
309
310 // Interaction parameters
311 float m_interaction_radius = 2.0F;
312 float m_spring_stiffness = 0.1F;
313 float m_repulsion_strength = 0.5F;
314
315 // Attraction point
316 glm::vec3 m_attraction_point { 0.0F };
317 bool m_has_attraction_point = false;
318 float m_attraction_strength = 1.0F;
319
320 // Initialization
322
323 // Neighbor tracking (for SPATIAL topology)
324 std::unordered_map<size_t, std::vector<size_t>> m_neighbor_map;
325 bool m_neighbor_map_dirty = true;
326
327 //-------------------------------------------------------------------------
328 // Physics Simulation
329 //-------------------------------------------------------------------------
330
331 /**
332 * @brief Clear accumulated forces
333 */
334 void clear_forces();
335
336 /**
337 * @brief Apply gravity to all particles
338 */
339 void apply_gravity();
340
341 /**
342 * @brief Apply drag forces
343 */
344 void apply_drag();
345
346 /**
347 * @brief Apply interaction forces based on topology
348 */
349 void apply_interaction_forces();
350
351 /**
352 * @brief Apply attraction point force
353 */
354 void apply_attraction_force();
355
356 /**
357 * @brief Integrate forces → velocities → positions
358 */
359 void integrate(float dt);
360
361 /**
362 * @brief Handle boundary conditions
363 */
364 void handle_bounds();
365
366 /**
367 * @brief Update PointNode states from physics
368 */
369 void update_point_nodes();
370
371 //-------------------------------------------------------------------------
372 // Topology Management
373 //-------------------------------------------------------------------------
374
375 /**
376 * @brief Rebuild neighbor map for SPATIAL topology
377 */
378 void rebuild_spatial_neighbors();
379
380 /**
381 * @brief Get neighbors for a particle based on current topology
382 */
383 [[nodiscard]] std::vector<size_t> get_neighbors(size_t index) const;
384
385 //-------------------------------------------------------------------------
386 // Initialization Helpers
387 //-------------------------------------------------------------------------
388
389 /**
390 * @brief Initialize particles based on mode
391 */
392 void initialize_particle_positions(InitializationMode mode);
393
394 /**
395 * @brief Random position in bounds volume
396 */
397 [[nodiscard]] glm::vec3 random_position_volume() const;
398
399 /**
400 * @brief Random position on bounds surface
401 */
402 [[nodiscard]] glm::vec3 random_position_surface() const;
403
404 /**
405 * @brief Random position in sphere
406 */
407 [[nodiscard]] glm::vec3 random_position_sphere(float radius) const;
408
409 /**
410 * @brief Random position on sphere surface
411 */
412 [[nodiscard]] glm::vec3 random_position_sphere_surface(float radius) const;
413
414 //-------------------------------------------------------------------------
415 // Parameter Mapping Helpers
416 //-------------------------------------------------------------------------
417
418 /**
419 * @brief Update mapped parameters before physics step
420 */
421 void update_mapped_parameters();
422
423 /**
424 * @brief Apply broadcast parameter to all particles
425 */
426 void apply_broadcast_parameter(const std::string& param, double value);
427
428 /**
429 * @brief Apply one-to-one parameter from another network
430 */
431 void apply_one_to_one_parameter(
432 const std::string& param,
433 const std::shared_ptr<NodeNetwork>& source);
434};
435
436} // namespace MayaFlux::Nodes
Abstract base class for structured collections of nodes with defined relationships.
void set_repulsion_strength(float strength)
Set repulsion strength (for SPATIAL topology)
void disable_attraction_point()
Disable attraction point.
const std::vector< ParticleNode > & get_particles() const
Get all particles (read-only for NetworkGeometryBuffer)
ParticleNode & get_particle_mut(size_t index)
Get mutable particle (for custom manipulation)
void set_interaction_radius(float radius)
Set interaction radius (for SPATIAL topology)
glm::vec3 get_gravity() const
Get current gravity.
std::unordered_map< size_t, std::vector< size_t > > m_neighbor_map
void set_drag(float drag)
Set drag coefficient (0.0 = no drag, 1.0 = full drag)
void set_bounds_mode(BoundsMode mode)
Set bounds behavior.
float get_drag() const
Get current drag.
InitializationMode
Particle spawn distribution.
size_t get_node_count() const override
Get the number of nodes in the network.
void set_timestep(float dt)
Set time step for physics integration.
const ParticleNode & get_particle(size_t index) const
Get specific particle.
void set_spring_stiffness(float stiffness)
Set spring stiffness (for SPATIAL/GRID topologies)
void set_bounds(const glm::vec3 &min, const glm::vec3 &max)
Set spatial bounds.
BoundsMode
How particles behave at spatial bounds.
void set_gravity(const glm::vec3 &gravity)
Set global gravity vector.
std::vector< ParticleNode > m_particles
void set_attraction_point(const glm::vec3 &point)
Set attraction point (particles pulled toward this point)
Network of particles with physics simulation.
void initialize()
Definition main.cpp:11
Contains the node-based computational processing system components.
Definition Chronie.hpp:5
std::shared_ptr< GpuSync::PointNode > point
Actual GeometryWriterNode.
Single particle with physics state.