Toast Engine
Loading...
Searching...
No Matches
simulator.hpp
Go to the documentation of this file.
1
7
8#pragma once
9
10#include "body.hpp"
11#include "broad_phase.hpp"
12#include "constraint.hpp"
13#include "damage_command.hpp"
14#include "debris.hpp"
16#include "manifold.hpp"
17#include "narrow_phase.hpp"
18#include "physics_material.hpp"
19#include "shape.hpp"
20#include "shape_query.hpp"
22#include "voxel_render.hpp"
23#include "voxel_shape_data.hpp"
24
25#include <atomic>
26#include <cstdint>
27#include <deque>
28#include <functional>
29#include <glm/glm.hpp>
30#include <mutex>
31#include <optional>
32#include <span>
33#include <thread>
34#include <toast/events/listener.hpp>
35#include <toast/export.hpp>
36#include <toast/log.hpp>
39#include <toast/world/box.hpp>
40#include <toml++/impl/preprocessor.hpp>
41#include <unordered_map>
42#include <vector>
43
44namespace physics {
45class Trigger;
46
47class Rigidbody;
49class Collider;
50struct SmashVolume;
51struct SmashPieces;
52
53}
54
55namespace physics {
56
57class TOAST_API Simulator {
58 friend class Collider;
59 friend class Rigidbody;
60 friend class DynamicRigidbody;
61 friend class toast::VoxelNode;
62
63public:
65 ShapeID shape;
66 glm::ivec3 brick {};
67 };
68
70 ShapeID shape;
71 voxel::Connectivity connectivity;
72 };
73
74 Simulator();
75 ~Simulator();
76 Simulator(const Simulator&) = delete;
77 auto operator=(const Simulator&) -> Simulator& = delete;
78 Simulator(Simulator&&) = delete;
79 auto operator=(Simulator&&) -> Simulator& = delete;
80
81 void tick();
82 void integrate(float dt);
83
84 [[nodiscard]]
85 auto createBody(const BodyDescriptor& descriptor) -> BodyID;
86 void destroyBody(BodyID body);
87
89 static auto raycast(
90 glm::vec3 origin, glm::vec3 direction, float max_distance = -1.0f, BodyID ignored = {}, uint32_t layers = k_all_layers
91 ) -> std::optional<RayHit>;
92 static auto raymulticast(
93 glm::vec3 origin, glm::vec3 direction, float max_distance = -1.0f, int max_hits = -1, BodyID ignored = {},
94 uint32_t layers = k_all_layers
95 ) -> std::vector<RayHit>;
96 static auto linecast(glm::vec3 from, glm::vec3 to, int max_hits = -1, BodyID ignored = {}, uint32_t layers = k_all_layers)
97 -> std::vector<RayHit>;
98
99 [[nodiscard]]
100 static auto bodyFor(const toast::Node& node) -> BodyID;
101
102 [[nodiscard]]
103 auto valid(BodyID body) const -> bool;
104 [[nodiscard]]
105 auto state(BodyID body) const -> std::optional<BodyState>;
106
107 auto setTransform(BodyID body, const glm::vec3& position, const glm::quat& rotation) -> bool;
108 auto setLinearVelocity(BodyID body, const glm::vec3& velocity) -> bool;
109
110 void recordDamage(DamageCommand&& command);
111 void applyDamageCommands();
112 void applyDamageCommand(const DamageCommand& c);
113 void damageArea(const AreaDamage& damage);
114 auto explode(const ExplosionDamage& explosion) -> uint32_t;
115
116 auto shootVoxel(
117 const glm::vec3& origin, const glm::vec3& direction, float max_distance, float energy_density, float fracture_radius,
118 const std::optional<FragmentPush>& push = std::nullopt, Hardness max_hardness = k_hardest
119 ) -> bool;
120
121 auto smashCapsule(
122 const CapsuleShape& capsule, const glm::vec3& position, const glm::quat& rotation, const glm::vec3& sweep,
123 const CapsuleSmash& smash
124 ) -> uint32_t;
125
126 auto cutVoxel(
127 const glm::vec3& origin, const glm::vec3& direction, float max_distance, float energy_density, float radius, float depth,
128 Hardness max_hardness = k_hardest
129 ) -> uint32_t;
130
131 [[nodiscard]]
132 auto runConnectivityAnalysis() -> std::vector<ConnectivityResult>;
133
134 [[nodiscard]]
135 auto debugDirtyBricks() const -> std::span<const DebugDirtyBrick> {
136 return m_debug_dirty_bricks;
137 }
138
141 std::array<size_t, static_cast<size_t>(NarrowPhasePairType::count)> narrow_pair_candidates = {};
142 std::array<double, static_cast<size_t>(NarrowPhasePairType::count)> narrow_pair_time_ms = {};
143 size_t narrow_jobs = 0;
144 size_t narrow_candidates = 0;
147 size_t voxel_voxel_split_pairs = 0;
150 size_t voxel_voxel_nondegenerate_pairs = 0;
153 size_t voxel_voxel_max_estimated_voxels = 0;
156 size_t narrow_collisions = 0;
157 size_t sleeping_pairs_skipped = 0;
158 size_t rejected_manifolds = 0;
159 size_t contact_points = 0;
160 size_t bodies_woken = 0;
161 size_t bodies_slept = 0;
164 size_t woken_by_racing = 0;
165 size_t woken_by_contact_end = 0;
166 size_t woken_by_support_loss = 0;
167 size_t contact_begins = 0;
168 size_t contact_persists = 0;
169 size_t contact_ends = 0;
170 size_t reused_cached_contacts = 0;
171 size_t cold_cached_contacts = 0;
172 size_t constraints = 0;
173 size_t rejected_constraints = 0;
174 size_t warm_started_constraints = 0;
175 size_t island_jobs = 0;
176 size_t invalid_constraints = 0;
177 size_t position_corrections = 0;
178
179 double tick_ms = 0.0;
180 double damage_apply_ms = 0.0;
181 double connectivity_ms = 0.0;
182 double character_step_ms = 0.0;
183 double narrow_phase_ms = 0.0;
184 double solve_ms = 0.0;
185
188 size_t character_overlap_calls = 0;
189
191 double cache_update_ms = 0.0;
192 double wake_groups_ms = 0.0;
193 double prepare_constraints_ms = 0.0;
194 double build_islands_ms = 0.0;
195 double island_solve_ms = 0.0;
196 double sleep_update_ms = 0.0;
197
198 size_t body_count = 0;
199 size_t awake_body_count = 0;
200 size_t voxel_shape_count = 0;
201 size_t manifold_count = 0;
202
203 size_t damage_commands = 0;
204 size_t dirty_bricks = 0;
205 size_t surface_bricks_repaired = 0;
206
207 size_t connectivity_jobs = 0;
208 size_t connectivity_jobs_dispatched = 0;
209 size_t connectivity_jobs_stale = 0;
210 size_t connectivity_shapes_waiting = 0;
211
212 size_t fragments_spawned = 0;
213 size_t fragment_spawn_failures = 0;
214 size_t fragments_pending = 0;
215 size_t fragments_active = 0;
216 size_t fragments_sleep_locked = 0;
217 size_t fragments_despawned = 0;
218 size_t fragments_evicted = 0;
219 size_t static_splits_spawned = 0;
220
221 uint32_t brick_pool_allocated = 0;
222 uint32_t brick_pool_capacity = 0;
223
226
229
232 };
233
235 [[nodiscard]]
236 static auto stepProfile() -> const PhysicsStepProfile&;
237
239 static void recordTickBurst(size_t steps, bool time_budget_reached);
240
242 static void recordInterpolationAlpha(double alpha);
243 [[nodiscard]]
244 static auto interpolationAlpha() -> float;
245
247 [[nodiscard]]
248 static auto renderPoseDelta(BodyID id) -> glm::mat4;
249 [[nodiscard]]
250 static auto renderPoseDelta(const toast::VoxelNode& node) -> glm::mat4;
251
253 [[nodiscard]]
254 static auto renderPoseDeltaFor(const toast::Node& node) -> glm::mat4;
255
257 static void syncRenderPoses();
258
259 [[nodiscard]]
260 static auto shapeWorldBounds(ShapeID shape) -> std::optional<AABB>;
261
263 [[nodiscard]]
264 static auto nodeFor(BodyID body) -> toast::Box<toast::Node>;
265
266 static void callTick();
267
268 static void bindToThisThread() noexcept;
269
270 [[nodiscard]]
271 static auto onSimulatorThread() noexcept -> bool;
272
276 [[nodiscard]]
277 static auto pendingRequests() noexcept -> size_t;
278
280 static void runPendingRequests();
281
283 static void requestSleep(BodyID id);
284 static void requestWake(BodyID id);
285 static void registerRigidbody(Rigidbody& node);
286 static void unregisterRigidbody(Rigidbody& node);
287 static void registerVoxelNode(toast::VoxelNode& node);
288 static void unregisterVoxelNode(toast::VoxelNode& node);
289 static void registerTrigger(Trigger& node);
290 static void unregisterTrigger(Trigger& node);
291
292 [[nodiscard]]
293 auto overlapCapsule(
294 BodyID ignored, const CapsuleShape& capsule, const glm::vec3& position, const glm::quat& rotation, float min_penetration,
295 std::vector<QueryContact>& contacts
296 ) const -> bool;
298 [[nodiscard]]
299 auto overlapSphere(
300 const SphereShape& sphere, const glm::vec3& position, float min_penetration, std::vector<QueryContact>& contacts
301 ) const -> bool;
303 [[nodiscard]]
304 auto overlapAABB(const AABB& bounds) const -> bool;
307 [[nodiscard]]
308 auto sweepCapsule(
309 BodyID ignored, const CapsuleShape& capsule, const glm::quat& rotation, const glm::vec3& from, const glm::vec3& to,
310 float skin, bool refine = true
311 ) const -> SweepHit;
313 auto setCapsuleShape(BodyID body, const CapsuleShape& capsule) -> bool;
314 void moveKinematicBody(BodyID id, const glm::vec3& position, const glm::quat& rotation, const glm::vec3& velocity);
316 void pushBody(BodyID id, const glm::vec3& point, const glm::vec3& direction, float speed, float max_impulse);
317
318 [[nodiscard]]
319 auto takeDebrisSpawns() -> std::vector<DebrisSpawn>;
320
322 [[nodiscard]]
323 static auto current() -> Simulator*;
324
325 [[nodiscard]]
326 static auto voxelFragmentRecords() -> std::span<const VoxelRenderRecord>;
327
328 static void setWind(const glm::vec3& wind);
329 [[nodiscard]]
330 static auto wind() -> glm::vec3;
331 static void resetWind();
332
333private:
334 enum class SimulationPhase : uint8_t {
335 idle,
336 mutation,
337 worker_execution,
338 };
339
340 class PhaseScope {
341 public:
342 PhaseScope(Simulator& simulator, SimulationPhase expected, SimulationPhase next);
343 ~PhaseScope();
344 PhaseScope(const PhaseScope&) = delete;
345 auto operator=(const PhaseScope&) -> PhaseScope& = delete;
346
347 private:
348 Simulator& m_simulator;
349 SimulationPhase m_previous;
350 SimulationPhase m_active;
351 };
352
353 struct ColliderBinding {
354 ShapeID shape;
356 };
357
358 struct NodeBinding {
359 BodyID body;
360 toast::Box<Rigidbody> node;
361 std::vector<ColliderBinding> colliders;
362 };
363
364 struct VoxelNodeBinding {
365 BodyID body;
366 ShapeID shape;
367 toast::Box<toast::VoxelNode> node;
368 uint32_t source_revision = 0;
369 uint64_t source_model = 0;
370 uint64_t source_palette = 0;
371 };
372
373 struct SimulationIsland {
374 BodyID sort_key;
375 std::vector<BodyID> dynamic_bodies;
376 std::vector<Constraint> constraints;
377 std::vector<size_t> manifold_indices;
378
381 std::vector<size_t> batch_offsets;
382 };
383
384 struct FragmentRecord {
385 BodyID body;
386 ShapeID shape;
387 uint64_t sequence = 0;
388 float rest_seconds = 0.0f;
389 glm::vec3 rest_center = {};
390 glm::quat rest_rotation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f);
391 };
392
393 struct PendingFragments {
394 ShapeID shape;
395 std::vector<DetachedComponent> components;
396 size_t cursor = 0;
397 std::optional<FragmentPush> push;
398 };
399
400 struct RayQuery {
401 glm::vec3 origin = {};
402 glm::vec3 direction = {}; // normalized
403 float max_distance = std::numeric_limits<float>::infinity(); // inf for no end
404 BodyID ignored;
405 uint32_t layers = k_all_layers; // bodies including none of these are not hit
406 bool voxels_only = false;
407 bool hit_passable = false; // passable materials count as solid
408 };
409
410 struct RayContact {
411 ShapeID shape;
412 BodyID body;
413 float distance = 0.0f;
414 glm::vec3 normal = {};
415 uint8_t palette_index = 0;
416 };
417
418 template<typename OnContact>
419 auto castRay(const RayQuery& query, OnContact&& on_contact) const -> uint32_t;
420
422 [[nodiscard]]
423 auto windBlocked(const glm::vec3& position, const glm::vec3& toward, float distance, BodyID ignored) const -> bool;
424
425 [[nodiscard]]
426 static auto makeRayQuery(glm::vec3 origin, glm::vec3 direction, float max_distance, BodyID ignored, uint32_t layers)
427 -> std::optional<RayQuery>;
428
429 [[nodiscard]]
430 static auto makeRayHit(const RayQuery& query, const RayContact& contact, toast::Box<toast::Node> node) -> RayHit;
431
432 struct VoxelRayHit {
433 ShapeID shape;
434 float distance = 0.0f;
435 };
436
437 [[nodiscard]]
438 static auto colliderFor(BodyID body, ShapeID shape) -> toast::Box<toast::Node>;
439 [[nodiscard]]
440 auto mainThreadMutationAllowed() const -> bool;
441
443 static void request(std::move_only_function<void()> work);
444
445 void dropRigidbodyBinding(const toast::Box<Rigidbody>& node);
446 void dropVoxelBinding(const toast::Box<toast::VoxelNode>& node);
447
448 [[nodiscard]]
449 auto createSphere(BodyID owner, const SphereShape& sphere, PhysicsMaterial material) -> ShapeID;
450 [[nodiscard]]
451 auto createBox(BodyID owner, const BoxShape& box, PhysicsMaterial material) -> ShapeID;
452 [[nodiscard]]
453 auto createCapsule(BodyID owner, const CapsuleShape& capsule, PhysicsMaterial material) -> ShapeID;
454 [[nodiscard]]
455 auto createVoxelShape(
456 BodyID owner, const VoxelShape& shape, voxel::Volume& volume, const voxel::Palette& palette,
457 const voxel::MaterialLibrary& materials
458 ) -> ShapeID;
459 [[nodiscard]]
460 auto createVoxelShape(
461 BodyID owner, const VoxelShape& shape, voxel::Volume&& volume, const voxel::Palette& palette,
462 const voxel::MaterialLibrary& materials
463 ) -> ShapeID;
464 [[nodiscard]]
465 auto createVoxelShape(BodyID owner, toast::VoxelNode& node) -> ShapeID;
466
467 void destroyShape(ShapeID shape);
468 [[nodiscard]]
469 auto valid(ShapeID shape) const -> bool;
470 [[nodiscard]]
471 auto tryGetShape(ShapeID shape) -> Shape*;
472 [[nodiscard]]
473 auto tryGetShape(ShapeID shape) const -> const Shape*;
474 [[nodiscard]]
475 auto valid(VoxelDataID data) const -> bool;
476
477public:
478 [[nodiscard]]
479 static auto tryGetVoxelData(VoxelDataID data) -> VoxelShapeData*;
480
481 [[nodiscard]]
482 static auto tryGetVoxelDataConst(VoxelDataID data) -> const VoxelShapeData*;
483
484private:
485 void destroyVoxelData(VoxelDataID data);
486
487 void rebuildMassProperties(BodyID id);
488
489 [[nodiscard]]
490 auto tryGetBody(BodyID body) -> Body*;
491 [[nodiscard]]
492 auto tryGetBody(BodyID body) const -> const Body*;
493
494 static void integrateBody(BodyID id, Body& body, const glm::vec3& gravity, float air_density, const glm::vec3& wind, float dt);
495 static void setBodyEnabled(BodyID body, bool enabled);
496
497 static void setBodyTransform(BodyID body, const glm::vec3& position, const glm::quat& rotation);
498 static void setBodyLayers(BodyID body, LayerFilter layers);
499 static auto setBodyLinearVelocity(BodyID body, const glm::vec3& velocity) -> bool;
500
501 static void setShapeEnabled(ShapeID shape, bool enabled);
502 void syncEnabledState();
503
504 [[nodiscard]]
505 auto queryCandidates(BodyID ignored, const AABB& bounds, std::optional<LayerFilter> layers = std::nullopt) const
506 -> std::vector<ShapeID>;
507 [[nodiscard]]
508 auto layersOf(BodyID body) const -> std::optional<LayerFilter>;
509 void collideCapsuleProbe(
510 const Body& probe_body, const Shape& probe_shape, std::span<const ShapeID> candidates, std::vector<QueryContact>& contacts
511 ) const;
512 void collideSphereProbe(
513 const Body& probe_body, const Shape& probe_shape, std::span<const ShapeID> candidates, std::vector<QueryContact>& contacts
514 ) const;
515
516 static void wakeBody(BodyID id);
517 static void sleepBody(BodyID id);
519 void releaseSleeper(BodyID sleeper, BodyID other, const glm::vec3& normal_to_other);
520 void wakeBodiesTouching(BodyID id);
521 void wakeBodiesTouching(ShapeID id);
522 void wakeBodiesInBounds(const AABB& bounds);
523 void convertImpulsesToDamage(std::span<const SimulationIsland> islands);
524 void wakeDisturbedSleepers(float dt);
525 void unlockDisturbedFragments();
526 void markSupportedBodies();
527 [[nodiscard]]
528 auto isStill(const Body& body, float scale) const -> bool;
529 [[nodiscard]]
530 auto sleepScale(size_t slot) const -> float;
531 [[nodiscard]]
532 auto sleeperIsHeldUp(BodyID id) const -> bool;
533 void updateSleeping(float dt);
534 [[nodiscard]]
535 auto shouldSolve(const Manifold& manifold) const -> bool;
536 [[nodiscard]]
537 auto pairNeedsNarrowPhase(CollisionWorldView world, const BroadPhasePair& pair) const -> bool;
538
539 [[nodiscard]]
540 auto generateManifoldsAsync(CollisionWorldView world, std::span<const BroadPhasePair> candidates) -> std::vector<Manifold>;
541
542 [[nodiscard]]
543 auto prepareConstraints(const std::vector<Manifold>& manifolds) -> std::vector<Constraint>;
544 [[nodiscard]]
545 auto prepareConstraint(const Manifold& manifold, const ContactPoint& contact) const -> std::optional<Constraint>;
546 [[nodiscard]]
547 auto buildIslands(std::span<const Manifold> manifolds, const std::vector<Constraint>& constraints)
548 -> std::vector<SimulationIsland>;
549 void updateCache(std::span<const Manifold> manifolds);
550 [[nodiscard]]
551 auto findCachedContact(const BroadPhasePair& pair, uint8_t normal_index, ContactFeatureID feature_a, ContactFeatureID feature_b)
552 -> CachedContact*;
553 [[nodiscard]]
554 auto findCachedContact(
555 const BroadPhasePair& pair, uint8_t normal_index, ContactFeatureID feature_a, ContactFeatureID feature_b
556 ) const -> const CachedContact*;
557 void warmStartConstraints(std::span<Constraint> constraints);
558 void storeConstraintImpulses(std::span<const Constraint> constraints);
559 [[nodiscard]]
560 auto shapeRevision(ShapeID shape) const -> uint32_t;
561 void incrementShapeRevision(ShapeID shape);
562 void solveIslands(std::vector<SimulationIsland>& islands);
563 [[nodiscard]]
564 auto solveConstraintBatch(std::span<Constraint> batch) -> size_t;
565 [[nodiscard]]
566 auto solveConstraint(Constraint& constraint) -> bool;
567 void publishTransforms();
568 [[nodiscard]]
569 auto publishTransform(NodeBinding& binding) -> bool;
570 [[nodiscard]]
571 auto publishVoxelTransform(VoxelNodeBinding& binding) -> bool;
572 void publishVoxelRenderRecords();
573 void rebuildRenderPoseLookup();
574
575 static auto velocityAtPoint(const Body& body, const glm::vec3& r) -> glm::vec3;
576 static auto effectiveMassAlong(
577 const Body& body_a, const Body& body_b, const glm::vec3& r_a, const glm::vec3& r_b, const glm::vec3& direction
578 ) -> std::optional<float>;
579 static auto angularMassAround(const Body& body_a, const Body& body_b, const glm::vec3& axis) -> float;
580 static void applyImpulse(Body& body_a, Body& body_b, const glm::vec3& r_a, const glm::vec3& r_b, const glm::vec3& impulse);
581 static void applyAngularImpulse(Body& body_a, Body& body_b, const glm::vec3& impulse);
582 static auto solveNormal(Constraint& constraint, Body& body_a, Body& body_b) -> bool;
583 static auto solveFriction(Constraint& constraint, Body& body_a, Body& body_b) -> bool;
584 static auto solveRolling(Constraint& constraint, Body& body_a, Body& body_b) -> bool;
585 [[nodiscard]]
586 auto correctPositions(std::span<const size_t> manifold_indices) -> size_t;
587 void publishProfile(std::span<const SimulationIsland> islands);
588
589 void clearFragmentFromSource(
590 ShapeID shape_id, VoxelShapeData& data, voxel::Volume& source, const DetachedComponent& component,
591 const RemovedVoxels* already_removed = nullptr
592 );
593
594 void emitDebris(
595 ShapeID shape_id, std::span<const DebrisVoxel> voxels, const DebrisBlast* blast, const FragmentPush* push, uint64_t seed
596 );
597
598 void emitComponentDebris(ShapeID shape_id, const DetachedComponent& component, const FragmentPush* push);
599
600 [[nodiscard]]
601 auto spawnFragmentBody(ShapeID source_shape_id, const DetachedComponent& component, const FragmentPush* push = nullptr) -> bool;
602 auto smashShape(ShapeID shape_id, const SmashVolume& volume, const CapsuleSmash& smash, bool chunks) -> uint32_t;
603 auto explodeShape(ShapeID shape_id, const ExplosionDamage& explosion) -> uint32_t;
604 auto breakPieces(
605 ShapeID shape_id, SmashPieces& picked, bool chunks,
606 const std::function<std::optional<FragmentPush>(const DetachedComponent&)>& push_for, const AABB& wake_bounds
607 ) -> uint32_t;
608 [[nodiscard]]
609 auto marchVoxelRay(const glm::vec3& origin, const glm::vec3& direction, float max_distance) -> std::optional<VoxelRayHit>;
610 [[nodiscard]]
611 auto spawnStaticSplitBody(ShapeID source_shape_id, const DetachedComponent& component) -> bool;
612 void despawnSettledFragments(float dt);
613 void retireVoxelBody(BodyID id);
614 void destroyFragmentsOf(BodyID origin);
615
616 [[nodiscard]]
617 auto voxelNodeFor(ShapeID shape) -> toast::VoxelNode*;
618
619 void reapFragments();
620 void destroyFragmentRecord(BodyID id);
621 void queuePendingFragments(std::span<const ConnectivityResult> results);
622 void spawnBudgetedFragments();
623 [[nodiscard]]
624 auto reconcileComponent(const voxel::Volume& volume, const DetachedComponent& component) const -> bool;
625 void enforceFragmentBudget(float dt);
626 void unlockSleep(BodyID id);
627 void recheckNeighborsOf(BodyID id);
628 void rebuildFragmentIndex();
629 void refreshPalette(uint64_t palette_uid);
630 void refreshAllPalettes();
631 auto createVoxelShapeInternal(
632 BodyID owner, const VoxelShape& shape, voxel::Volume* external, std::unique_ptr<voxel::Volume>& owned,
633 const voxel::Palette& palette, const voxel::MaterialLibrary& materials, const voxel::MassMoments* known_moments = nullptr
634 ) -> ShapeID;
635
636 void checkTriggers();
637 void overlapShape(
638 BodyID ignored, LayerFilter layers, const Shape& probe, const glm::vec3& position, const glm::quat& rotation,
639 std::vector<BodyID>& bodies
640 ) const;
641
642 inline static Simulator* instance = nullptr;
643
644 std::mutex m_wind_mutex;
645 std::optional<glm::vec3> m_level_wind;
646
647 mutable std::thread::id m_owner_thread;
648 std::atomic<SimulationPhase> m_phase = SimulationPhase::idle;
649
650 std::vector<BodySlot> m_bodies;
651 std::deque<uint32_t> m_free_body_slots;
652 std::vector<NodeBinding> m_node_bindings;
653 std::vector<VoxelNodeBinding> m_voxel_bindings;
654
656 std::vector<uint8_t> m_body_supported;
657 std::vector<uint8_t> m_sleep_ready;
658 std::vector<uint8_t> m_sleep_moving;
659 std::vector<uint8_t> m_sleep_blocked;
661 std::vector<uint8_t> m_contact_supported;
663 std::vector<glm::vec3> m_position_shift;
664
666 std::vector<size_t> m_island_parents;
667 std::vector<bool> m_island_participates;
668 std::vector<size_t> m_island_by_root;
669 std::vector<uint32_t> m_island_next_free_batch;
670 std::vector<uint32_t> m_island_constraint_batch;
671 std::vector<size_t> m_island_batch_cursor;
672 std::vector<Constraint> m_island_reordered_scratch;
673
675 std::vector<size_t> m_wave_chunk_invalid_counts;
676
677 std::vector<ShapeSlot> m_shapes;
678 std::deque<uint32_t> m_free_shape_slots;
679
680 BroadPhase m_broad_phase;
681 NarrowPhase m_narrow_phase;
682 std::vector<Manifold> m_manifolds;
683 std::vector<CachedManifold> m_cached_manifolds;
684 mutable PhysicsStepProfile m_profile;
685 PhysicsStepProfile m_published_profile;
686
687 std::vector<VoxelShapeSlot> m_voxel_shapes;
688 std::deque<uint32_t> m_free_voxel_shape_slots;
689 std::vector<VoxelRenderRecord> m_voxel_render_records;
690 std::vector<DebrisSpawn> m_debris_spawns;
691
692 std::mutex m_damage_mutex;
693 std::vector<DamageCommand> m_damage_commands;
694 std::vector<DebugDirtyBrick> m_debug_dirty_bricks;
695
696 uint64_t m_next_fragment_sequence = 1;
697 uint64_t m_tick_index = 0;
698 std::vector<FragmentRecord> m_fragments;
699 std::unordered_map<uint32_t, size_t> m_fragment_index;
700 std::vector<PendingFragments> m_pending_fragments;
701 std::vector<BodyID> m_doomed_fragments;
702
704 size_t m_connectivity_cursor = 0;
705
706 float m_interpolation_alpha = 0.0f;
707
709 std::unordered_map<uint64_t, BodyID> m_render_body_of_node;
710
711 event::Listener m_listener;
712
713 // triggers stuff
714 std::vector<toast::Box<Trigger>> m_triggers;
715};
716
717}
Body identifiers, creation data, and copied runtime state.
pseudo shared pointer for Nodes
Generates potentially colliding shape pairs.
Definition collider.hpp:18
Definition dynamic_rigidbody.hpp:14
Definition rigidbody.hpp:22
Definition simulator.hpp:57
static void syncRenderPoses()
Once per frame after the ticks so nodes below driven bodies match the tick pose the delta starts from...
Definition simulator.cpp:2272
static void runPendingRequests()
Carries out the requests other threads made, on the simulator thread.
Definition simulator.cpp:3175
static auto pendingRequests() noexcept -> size_t
How many requests from other threads are waiting for the simulator thread.
Definition simulator.cpp:3164
static auto renderPoseDelta(BodyID id) -> glm::mat4
World transform from the tick pose to the blended pose drawn this frame and identity unless dynamic a...
Definition simulator.cpp:2241
static void recordInterpolationAlpha(double alpha)
Leftover accumulator time as a fraction of one step for blending the last two poses.
Definition simulator.cpp:2231
auto overlapAABB(const AABB &bounds) const -> bool
Tests a world-space axis-aligned box against enabled physics shapes.
Definition shape_query.cpp:409
auto sweepCapsule(BodyID ignored, const CapsuleShape &capsule, const glm::quat &rotation, const glm::vec3 &from, const glm::vec3 &to, float skin, bool refine=true) const -> SweepHit
Definition shape_query.cpp:467
static auto nodeFor(BodyID body) -> toast::Box< toast::Node >
Rigidbody or VoxelNode that owns body.
Definition simulator.cpp:588
auto setCapsuleShape(BodyID body, const CapsuleShape &capsule) -> bool
Resizes the capsule collider of a body.
Definition shape_query.cpp:673
static auto stepProfile() -> const PhysicsStepProfile &
The last tick profile is safe to read from another thread between ticks.
Definition simulator.cpp:2219
auto overlapSphere(const SphereShape &sphere, const glm::vec3 &position, float min_penetration, std::vector< QueryContact > &contacts) const -> bool
Tests a world-space sphere against enabled physics shapes.
Definition shape_query.cpp:390
void pushBody(BodyID id, const glm::vec3 &point, const glm::vec3 &direction, float speed, float max_impulse)
Raises the velocity of a dynamic body along direction.
Definition shape_query.cpp:740
static void requestSleep(BodyID id)
Puts a body to sleep or wakes it, from any thread.
Definition simulator.cpp:3200
static void recordTickBurst(size_t steps, bool time_budget_reached)
Stamps how many ticks the accumulator ran once it stops catching up for this frame.
Definition simulator.cpp:2224
static auto raycast(glm::vec3 origin, glm::vec3 direction, float max_distance=-1.0f, BodyID ignored={}, uint32_t layers=k_all_layers) -> std::optional< RayHit >
Definition raycast.cpp:312
static auto renderPoseDeltaFor(const toast::Node &node) -> glm::mat4
Delta of the dynamic body a node sits below and identity when it follows none.
Definition simulator.cpp:2264
static auto current() -> Simulator *
Simulator running the current step, null outside a play session.
Definition shape_query.cpp:144
Definition trigger.hpp:22
Intrusive reference-counted handle to a Node.
Definition box.hpp:35
Definition node.hpp:81
Definition voxel_node.hpp:72
TODO: Brief description of the file's purpose.
The kinds of damage that break voxels.
Small voxel debris clusters.
@ cursor
mouse cursor position or delta
Definition keycodes.hpp:53
Public logging interface for the engine.
TODO: Brief description of the file's purpose.
Generates contact manifolds for potentially colliding pairs.
TODO: Brief description of the file's purpose.
Raycast Implmentation mostly from https://iquilezles.org/articles/intersectors/ and https://www....
Shape identifiers, geometry, and runtime records.
Definition aabb.hpp:16
Definition body.hpp:32
Definition body.hpp:20
Definition shape.hpp:141
Definition debris.hpp:38
normal points out of the obstacle toward the query shape
Definition shape_query.hpp:17
Definition shape.hpp:29
Definition simulator.hpp:69
Definition simulator.hpp:64
Counters and phase timings for one tick snapshotted at a safe point for a debug view to read.
Definition simulator.hpp:140
size_t voxel_voxel_resolved_pairs
Of resolved voxel-voxel candidates how many had a non-degenerate overlap.
Definition simulator.hpp:149
size_t max_constraint_batches
Peak constraint batch count across islands this tick.
Definition simulator.hpp:225
size_t box_voxel_max_estimated_voxels
Largest estimated_voxels seen this tick regardless of threshold.
Definition simulator.hpp:152
size_t ticks_this_frame
How many ticks the fixed step accumulator ran this frame since tick_ms above is only the last one.
Definition simulator.hpp:228
size_t woken_by_approach
Of bodies_woken what woke each sleeper.
Definition simulator.hpp:163
size_t box_voxel_split_pairs
Of narrow_pair_candidates box_voxel/voxel_voxel how many crossed the split threshold.
Definition simulator.hpp:146
float box_voxel_max_extent_meters
World-space longest axis metres behind box_voxel_max_estimated_voxels.
Definition simulator.hpp:155
double cache_update_ms
solve_ms broken down island_solve_ms is solveIslands itself the rest is bookkeeping around it
Definition simulator.hpp:191
bool ticks_capped_by_time_budget
The accumulator cut this frame catch up burst short on time rather than running out of work.
Definition simulator.hpp:231
size_t character_sweep_calls
Call counts this tick not character count a movement tick calls trace/fits several times.
Definition simulator.hpp:187
Definition voxel_smash.hpp:98
Definition voxel_smash.hpp:49
Definition shape.hpp:130
Definition shape_query.hpp:25
Definition voxel_render.hpp:19
Labels are deterministic with pieces in brick order and components by first appearance.
Definition connectivity.hpp:65
Frontend for a Voxel node.
Read-only voxel render records.
Voxel data structures for physics system.