MayaFlux 0.2.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
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 [[nodiscard]] std::vector<ParticleNode>& get_particles()
169 {
170 return m_particles;
171 }
172
173 /**
174 * @brief Get specific particle
175 */
176 [[nodiscard]] const ParticleNode& get_particle(size_t index) const
177 {
178 return m_particles.at(index);
179 }
180
181 /**
182 * @brief Get mutable particle (for custom manipulation)
183 */
184 [[nodiscard]] ParticleNode& get_particle_mut(size_t index)
185 {
186 return m_particles.at(index);
187 }
188
189 //-------------------------------------------------------------------------
190 // Physics Configuration
191 //-------------------------------------------------------------------------
192
193 /**
194 * @brief Set global gravity vector
195 */
196 void set_gravity(const glm::vec3& gravity) { m_gravity = gravity; }
197
198 /**
199 * @brief Get current gravity
200 */
201 [[nodiscard]] glm::vec3 get_gravity() const { return m_gravity; }
202
203 /**
204 * @brief Set drag coefficient (0.0 = no drag, 1.0 = full drag)
205 */
206 void set_drag(float drag) { m_drag = glm::clamp(drag, 0.0F, 1.0F); }
207
208 /**
209 * @brief Get current drag
210 */
211 [[nodiscard]] float get_drag() const { return m_drag; }
212
213 /**
214 * @brief Set spatial bounds
215 */
216 void set_bounds(const glm::vec3& min, const glm::vec3& max)
217 {
218 m_bounds_min = min;
219 m_bounds_max = max;
220 }
221
222 /**
223 * @brief Set bounds behavior
224 */
225 void set_bounds_mode(BoundsMode mode) { m_bounds_mode = mode; }
226
227 /**
228 * @brief Set interaction radius (for SPATIAL topology)
229 */
230 void set_interaction_radius(float radius)
231 {
232 m_interaction_radius = radius;
233 m_neighbor_map_dirty = true;
234 }
235
236 /**
237 * @brief Set spring stiffness (for SPATIAL/GRID topologies)
238 */
239 void set_spring_stiffness(float stiffness)
240 {
241 m_spring_stiffness = stiffness;
242 }
243
244 /**
245 * @brief Set repulsion strength (for SPATIAL topology)
246 */
247 void set_repulsion_strength(float strength)
248 {
249 m_repulsion_strength = strength;
250 }
251
252 /**
253 * @brief Set attraction point (particles pulled toward this point)
254 */
255 void set_attraction_point(const glm::vec3& point)
256 {
257 m_attraction_point = point;
258 m_has_attraction_point = true;
259 }
260
261 /**
262 * @brief Disable attraction point
263 */
265 {
266 m_has_attraction_point = false;
267 }
268
269 /**
270 * @brief Set time step for physics integration
271 */
272 void set_timestep(float dt) { m_timestep = dt; }
273
274 //-------------------------------------------------------------------------
275 // Particle Control
276 //-------------------------------------------------------------------------
277
278 /**
279 * @brief Apply impulse to all particles
280 */
281 void apply_global_impulse(const glm::vec3& impulse);
282
283 /**
284 * @brief Apply impulse to specific particle
285 */
286 void apply_impulse(size_t index, const glm::vec3& impulse);
287
288 /**
289 * @brief Reinitialize all particle positions
290 */
291 void reinitialize_positions(InitializationMode mode);
292
293 /**
294 * @brief Reset all velocities to zero
295 */
296 void reset_velocities();
297
298private:
299 //-------------------------------------------------------------------------
300 // Internal State
301 //-------------------------------------------------------------------------
302
303 std::vector<ParticleNode> m_particles;
304
305 // Physics parameters
306 glm::vec3 m_gravity { 0.0F, -9.8F, 0.0F };
307 float m_drag = 0.01F;
308 float m_timestep = 0.016F; // ~60Fps default
309
310 // Spatial bounds
311 glm::vec3 m_bounds_min { -10.0F };
312 glm::vec3 m_bounds_max { 10.0F };
313 BoundsMode m_bounds_mode = BoundsMode::BOUNCE;
314
315 // Interaction parameters
316 float m_interaction_radius = 2.0F;
317 float m_spring_stiffness = 0.1F;
318 float m_repulsion_strength = 0.5F;
319
320 // Attraction point
321 glm::vec3 m_attraction_point { 0.0F };
322 bool m_has_attraction_point = false;
323 float m_attraction_strength = 1.0F;
324
325 // Initialization
327
328 // Neighbor tracking (for SPATIAL topology)
329 std::unordered_map<size_t, std::vector<size_t>> m_neighbor_map;
330 bool m_neighbor_map_dirty = true;
331
332 //-------------------------------------------------------------------------
333 // Physics Simulation
334 //-------------------------------------------------------------------------
335
336 /**
337 * @brief Clear accumulated forces
338 */
339 void clear_forces();
340
341 /**
342 * @brief Apply gravity to all particles
343 */
344 void apply_gravity();
345
346 /**
347 * @brief Apply drag forces
348 */
349 void apply_drag();
350
351 /**
352 * @brief Apply interaction forces based on topology
353 */
354 void apply_interaction_forces();
355
356 /**
357 * @brief Apply attraction point force
358 */
359 void apply_attraction_force();
360
361 /**
362 * @brief Integrate forces → velocities → positions
363 */
364 void integrate(float dt);
365
366 /**
367 * @brief Handle boundary conditions
368 */
369 void handle_bounds();
370
371 /**
372 * @brief Update PointNode states from physics
373 */
374 void update_point_nodes();
375
376 //-------------------------------------------------------------------------
377 // Topology Management
378 //-------------------------------------------------------------------------
379
380 /**
381 * @brief Rebuild neighbor map for SPATIAL topology
382 */
383 void rebuild_spatial_neighbors();
384
385 /**
386 * @brief Get neighbors for a particle based on current topology
387 */
388 [[nodiscard]] std::vector<size_t> get_neighbors(size_t index) const;
389
390 //-------------------------------------------------------------------------
391 // Initialization Helpers
392 //-------------------------------------------------------------------------
393
394 /**
395 * @brief Initialize particles based on mode
396 */
397 void initialize_particle_positions(InitializationMode mode);
398
399 /**
400 * @brief Random position in bounds volume
401 */
402 [[nodiscard]] glm::vec3 random_position_volume() const;
403
404 /**
405 * @brief Random position on bounds surface
406 */
407 [[nodiscard]] glm::vec3 random_position_surface() const;
408
409 /**
410 * @brief Random position in sphere
411 */
412 [[nodiscard]] glm::vec3 random_position_sphere(float radius) const;
413
414 /**
415 * @brief Random position on sphere surface
416 */
417 [[nodiscard]] glm::vec3 random_position_sphere_surface(float radius) const;
418
419 //-------------------------------------------------------------------------
420 // Parameter Mapping Helpers
421 //-------------------------------------------------------------------------
422
423 /**
424 * @brief Update mapped parameters before physics step
425 */
426 void update_mapped_parameters();
427
428 /**
429 * @brief Apply broadcast parameter to all particles
430 */
431 void apply_broadcast_parameter(const std::string& param, double value);
432
433 /**
434 * @brief Apply one-to-one parameter from another network
435 */
436 void apply_one_to_one_parameter(
437 const std::string& param,
438 const std::shared_ptr<NodeNetwork>& source);
439};
440
441} // namespace MayaFlux::Nodes::Network
Abstract base class for structured collections of nodes with defined relationships.
InitializationMode
Particle spawn distribution.
void set_attraction_point(const glm::vec3 &point)
Set attraction point (particles pulled toward this point)
const ParticleNode & get_particle(size_t index) const
Get specific particle.
std::unordered_map< size_t, std::vector< size_t > > m_neighbor_map
void set_bounds_mode(BoundsMode mode)
Set bounds behavior.
void set_interaction_radius(float radius)
Set interaction radius (for SPATIAL topology)
void set_repulsion_strength(float strength)
Set repulsion strength (for SPATIAL topology)
const std::vector< ParticleNode > & get_particles() const
Get all particles (read-only for NetworkGeometryBuffer)
void set_timestep(float dt)
Set time step for physics integration.
void set_drag(float drag)
Set drag coefficient (0.0 = no drag, 1.0 = full drag)
std::vector< ParticleNode > & get_particles()
void set_gravity(const glm::vec3 &gravity)
Set global gravity vector.
float get_drag() const
Get current drag.
BoundsMode
How particles behave at spatial bounds.
ParticleNode & get_particle_mut(size_t index)
Get mutable particle (for custom manipulation)
void set_spring_stiffness(float stiffness)
Set spring stiffness (for SPATIAL/GRID topologies)
void disable_attraction_point()
Disable attraction point.
void set_bounds(const glm::vec3 &min, const glm::vec3 &max)
Set spatial bounds.
glm::vec3 get_gravity() const
Get current gravity.
size_t get_node_count() const override
Get the number of nodes in the network.
Network of particles with physics simulation.
void initialize()
Definition main.cpp:11
std::shared_ptr< GpuSync::PointNode > point
Actual GeometryWriterNode.