MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
PhysicsOperator.hpp
Go to the documentation of this file.
1#pragma once
4
7
9
10/**
11 * @enum PhysicsParameter
12 * @brief Identifiers for physics parameters that can be set via parameter mapping
13 */
27
28/**
29 * @struct PhysicsState
30 * @brief Physics-specific data parallel to PointVertex array
31 *
32 * Stored separately to avoid polluting vertex types with
33 * physics data. Indexed in parallel with PointCollectionNode's
34 * internal vertex array.
35 */
37 glm::vec3 velocity { 0.0F };
38 glm::vec3 force { 0.0F };
39 float mass { 1.0F };
40};
41
42/**
43 * @class PhysicsOperator
44 * @brief N-body physics simulation with point rendering
45 *
46 * Delegates rendering to PointCollectionNode. Physics state
47 * (velocity, force, mass) stored in parallel array. Each frame:
48 * 1. Apply forces
49 * 2. Integrate motion
50 * 3. Update PointCollectionNode vertices
51 * 4. PointCollectionNode handles GPU upload
52 */
53class MAYAFLUX_API PhysicsOperator : public GraphicsOperator {
54public:
56 std::shared_ptr<GpuSync::PointCollectionNode> collection;
57 std::vector<PhysicsState> physics_state;
58 };
59
60 /**
61 * @enum BoundsMode
62 * @brief How particles behave at spatial bounds
63 */
64 enum class BoundsMode : uint8_t {
65 NONE, ///< No bounds checking
66 BOUNCE, ///< Reflect off boundaries with damping
67 WRAP, ///< Teleport to opposite side
68 CLAMP ///< Stop at boundary
69 };
70
72
73 ~PhysicsOperator() override { m_shutdown.store(true, std::memory_order_release); }
74
75 /**
76 * @brief Initialize with a single physics collection
77 * @param vertices PointVertex array with position, color, size
78 */
79 void initialize(const std::vector<PointVertex>& vertices);
80
81 /**
82 * @brief Initialize multiple physics collections
83 * @param collections Vector of PointVertex vectors (one per collection)
84 */
85 void initialize_collections(
86 const std::vector<std::vector<PointVertex>>& collections);
87
88 /**
89 * @brief Add a single physics collection
90 * @param vertices PointVertex array with position, color, size
91 * @param mass_multiplier Mass multiplier for all particles in this collection
92 */
93 void add_collection(
94 const std::vector<PointVertex>& vertices,
95 float mass_multiplier = 1.0F);
96
97 void process(float dt) override;
98
99 [[nodiscard]] std::span<const uint8_t> get_vertex_data_for_collection(uint32_t idx) const override;
100 [[nodiscard]] std::span<const uint8_t> get_vertex_data() const override;
101 [[nodiscard]] Kakshya::VertexLayout get_vertex_layout() const override;
102 [[nodiscard]] size_t get_vertex_count() const override;
103 [[nodiscard]] bool is_vertex_data_dirty() const override;
104 void mark_vertex_data_clean() override;
105
106 /**
107 * @brief Extract current vertex data as PointVertex array
108 * @return Vector of PointVertex with current positions, colors, sizes
109 */
110 [[nodiscard]] std::vector<PointVertex> extract_vertices() const;
111
112 void set_parameter(std::string_view param, double value) override;
113 [[nodiscard]] std::optional<double> query_state(std::string_view query) const override;
114 [[nodiscard]] std::string_view get_type_name() const override { return "Physics"; }
115 [[nodiscard]] size_t get_point_count() const override;
116
117 /**
118 * @brief Set the gravity vector.
119 * @param gravity Gravity vector.
120 */
121 void set_gravity(const glm::vec3& gravity) { m_gravity = gravity; }
122
123 /**
124 * @brief Set the drag coefficient.
125 * @param drag Drag value.
126 */
127 void set_drag(float drag) { m_drag = drag; }
128
129 /**
130 * @brief Set the interaction radius for physics calculations.
131 * @param radius Interaction radius.
132 */
133 void set_interaction_radius(float radius) { m_interaction_radius = radius; }
134
135 /**
136 * @brief Set the spring stiffness for interactions.
137 * @param stiffness Spring stiffness value.
138 */
139 void set_spring_stiffness(float stiffness) { m_spring_stiffness = stiffness; }
140
141 /**
142 * @brief Set the simulation bounds.
143 * @param min Minimum bounds.
144 * @param max Maximum bounds.
145 */
146 void set_bounds(const glm::vec3& min, const glm::vec3& max);
147
148 /**
149 * @brief Set the rendered point size.
150 * @param size Point size.
151 */
152 void set_point_size(float size) { m_point_size = size; }
153
154 /**
155 * @brief Set the current bounds mode.
156 * @param mode Bounds mode to set.
157 */
158 void set_bounds_mode(BoundsMode mode) { m_bounds_mode = mode; }
159
160 /**
161 * @brief Enable or disable spatial interactions between particles.
162 * @param enable True to enable, false to disable.
163 */
164 void enable_spatial_interactions(bool enable) { m_spatial_interactions_enabled = enable; }
165
166 /**
167 * @brief Set the strength of repulsion between particles when spatial interactions are enabled.
168 * @param strength Repulsion strength value.
169 */
170 void set_repulsion_strength(float strength) { m_repulsion_strength = strength; }
171
172 /**
173 * @brief Set the strength of attraction towards the attraction point.
174 * @param strength Attraction strength value.
175 */
176 void set_attraction_strength(float strength) { m_attraction_strength = strength; }
177
178 /**
179 * @brief Set the strength of attraction towards the attraction point.
180 * @param strength Attraction strength value.
181 */
182 void set_turbulence_strength(float strength) { m_turbulence_strength = strength; }
183
184 /**
185 * @brief Get velocity magnitude for specific particle
186 * @param global_index Particle index across all collections
187 */
188 [[nodiscard]] std::optional<double> get_particle_velocity(size_t global_index) const;
189
190 /**
191 * @brief Get the current gravity vector.
192 * @return Gravity vector.
193 */
194 [[nodiscard]] glm::vec3 get_gravity() const { return m_gravity; }
195
196 /**
197 * @brief Get the current drag coefficient.
198 * @return Drag value.
199 */
200 [[nodiscard]] float get_drag() const { return m_drag; }
201
202 /**
203 * @brief Get the current bounds mode.
204 * @return Current bounds mode.
205 */
206 [[nodiscard]] BoundsMode get_bounds_mode() const { return m_bounds_mode; }
207
208 /**
209 * @brief Check if spatial interactions between particles are enabled.
210 * @return True if enabled, false otherwise.
211 */
212 [[nodiscard]] bool spatial_interactions_enabled() const { return m_spatial_interactions_enabled; }
213
214 /**
215 * @brief Get the current repulsion strength for spatial interactions.
216 * @return Repulsion strength value.
217 */
218 [[nodiscard]] float get_repulsion_strength() const { return m_repulsion_strength; }
219
220 void set_attraction_point(const glm::vec3& point);
221
222 void clear_attraction_point() { m_has_attraction_point = false; }
223
224 [[nodiscard]] bool has_attraction_point() const { return m_has_attraction_point; }
225
226 [[nodiscard]] glm::vec3 get_attraction_point() const { return m_attraction_point; }
227
228 /**
229 * @brief Apply impulse to all particles
230 */
231 void apply_global_impulse(const glm::vec3& impulse);
232
233 /**
234 * @brief Apply impulse to specific particle
235 */
236 void apply_impulse(size_t index, const glm::vec3& impulse);
237
238 /**
239 * @brief Add an external force field evaluated per-particle per-frame
240 * @param field VectorField: glm::vec3 (position) -> glm::vec3 (force)
241 *
242 * Fields are evaluated additively alongside existing hardcoded forces
243 * (gravity, attraction, turbulence, spatial interactions). Evaluated
244 * after gravity, before integration.
245 */
246 void add_force_field(Kinesis::VectorField field);
247
248 /**
249 * @brief Remove all external force fields
250 */
251 void clear_force_fields();
252
253 /**
254 * @brief Fixed dt substituted when set_force_internal_dt(true).
255 * @param dt Timestep in seconds. Default 0.016F.
256 */
257 void set_internal_dt(float dt) { m_internal_dt = dt; }
258 [[nodiscard]] float get_internal_dt() const { return m_internal_dt; }
259
260 /**
261 * @brief Get number of active external force fields
262 */
263 [[nodiscard]] size_t force_field_count() const { return m_force_fields.size(); }
264
265 /**
266 * @brief Direct access to collections for advanced per-particle control
267 * @warning Only for ParticleNetwork's ONE_TO_ONE parameter mapping
268 */
269 std::vector<CollectionGroup>& get_collections() { return m_collections; }
270
271 /**
272 * @brief Apply ONE_TO_ONE parameter for physics-specific properties
273 *
274 * Supports:
275 * - "force_x/y/z": Per-particle force application
276 * - "mass": Per-particle mass
277 * - "color": Per-particle color (delegated to base)
278 * - "size": Per-particle size (delegated to base)
279 */
280 void apply_one_to_one(
281 std::string_view param,
282 const std::shared_ptr<NodeNetwork>& source) override;
283
284 /**
285 * @brief Seed physics state from upstream operator's vertex data
286 *
287 * Extracts positions, colors, sizes from upstream and initializes
288 * physics state (velocity = 0, mass = 1) for each particle. Supports
289 * PointVertex input; other vertex types are ignored with a warning.
290 *
291 * @param upstream Upstream operator to seed from
292 */
293 void seed_from_upstream(const GraphicsOperator* upstream) override;
294
295 const char* get_vertex_type_name() const override { return "PointVertex"; }
296
297protected:
298 void* get_data_at(size_t global_index) override;
299
300private:
301 std::vector<CollectionGroup> m_collections;
302 mutable std::vector<uint8_t> m_vertex_data_aggregate;
303 std::vector<Kinesis::VectorField> m_force_fields;
304
306
307 glm::vec3 m_gravity { 0.0F, -9.81F, 0.0F };
308 float m_drag { 0.01F };
309 float m_interaction_radius { 1.0F };
310 float m_spring_stiffness { 0.5F };
311 float m_point_size { 5.0F };
312 float m_turbulence_strength { 0.0F };
313 Kinesis::SamplerBounds m_bounds { .min = glm::vec3 { -10.0F }, .max = glm::vec3 { 10.0F } };
314 BoundsMode m_bounds_mode { BoundsMode::BOUNCE };
315 bool m_spatial_interactions_enabled {};
316 float m_repulsion_strength { 0.5F };
317
318 glm::vec3 m_attraction_point { 0.0F };
319 bool m_has_attraction_point { false };
320 float m_attraction_strength { 1.0F };
321 float m_internal_dt { 0.016F };
322
323 static std::optional<PhysicsParameter> string_to_parameter(std::string_view param);
324
325 void apply_forces();
326 void apply_spatial_interactions();
327 void apply_attraction_forces();
328 void apply_turbulence();
329 void integrate(float dt);
330 void handle_boundary_conditions();
331 void sync_to_point_collection();
332
333 void apply_per_particle_force(
334 std::string_view param,
335 const std::shared_ptr<NodeNetwork>& source);
336
337 void apply_per_particle_mass(
338 const std::shared_ptr<NodeNetwork>& source);
339
340 mutable std::atomic<uint32_t> m_access_token { 0 };
341 std::atomic<bool> m_shutdown { false };
342};
343
344} // namespace MayaFlux::Nodes::Network
Unified generative infrastructure for stochastic and procedural algorithms.
Operator that produces GPU-renderable geometry.
void set_repulsion_strength(float strength)
Set the strength of repulsion between particles when spatial interactions are enabled.
std::vector< CollectionGroup > m_collections
glm::vec3 get_gravity() const
Get the current gravity vector.
void set_turbulence_strength(float strength)
Set the strength of attraction towards the attraction point.
Kinesis::Stochastic::Stochastic m_random_generator
float get_drag() const
Get the current drag coefficient.
BoundsMode
How particles behave at spatial bounds.
void set_interaction_radius(float radius)
Set the interaction radius for physics calculations.
void set_drag(float drag)
Set the drag coefficient.
std::vector< Kinesis::VectorField > m_force_fields
std::vector< CollectionGroup > & get_collections()
Direct access to collections for advanced per-particle control.
void set_bounds_mode(BoundsMode mode)
Set the current bounds mode.
std::string_view get_type_name() const override
Type name for introspection.
size_t force_field_count() const
Get number of active external force fields.
void set_internal_dt(float dt)
Fixed dt substituted when set_force_internal_dt(true).
void set_gravity(const glm::vec3 &gravity)
Set the gravity vector.
const char * get_vertex_type_name() const override
Get human-readable vertex type name (for validation/debugging)
void enable_spatial_interactions(bool enable)
Enable or disable spatial interactions between particles.
float get_repulsion_strength() const
Get the current repulsion strength for spatial interactions.
BoundsMode get_bounds_mode() const
Get the current bounds mode.
bool spatial_interactions_enabled() const
Check if spatial interactions between particles are enabled.
void set_point_size(float size)
Set the rendered point size.
void set_spring_stiffness(float stiffness)
Set the spring stiffness for interactions.
void set_attraction_strength(float strength)
Set the strength of attraction towards the attraction point.
N-body physics simulation with point rendering.
void initialize()
Definition main.cpp:11
PhysicsParameter
Identifiers for physics parameters that can be set via parameter mapping.
Complete description of vertex data layout in a buffer.
Spatial domain for vertex generation.
Typed, composable, stateless callable from domain D to range R.
Definition Tendency.hpp:22
std::shared_ptr< GpuSync::PointCollectionNode > collection
Physics-specific data parallel to PointVertex array.