|
group2 0.1.0
CSE 125 Group 2
|
Pure physics math — no ECS types, no registry. More...
Namespaces | |
| namespace | broadphase |
| namespace | events |
| namespace | cook |
| namespace | debug |
| namespace | diag |
| namespace | forces |
| namespace | inertia |
| namespace | perf |
| namespace | simd |
| namespace | detail |
| Active world (runtime-switchable). | |
Classes | |
| class | ContactCache |
| struct | ContactFeatureId |
| Identifier built from "which feature of A" and "which feature of
B" met at this contact. More... | |
| struct | ContactPoint |
| One sub-contact in a multi-point manifold. More... | |
| struct | ContactManifold |
| A contact manifold between exactly two entities. More... | |
| struct | PointJoint |
| Spherical/ball joint — locks the world-space anchor points of two bodies together while permitting arbitrary rotation. More... | |
| struct | HingeJoint |
| Single-axis hinge — locks the bodies' anchors together AND constrains their relative rotation to a single axis. More... | |
| struct | ConeTwistJoint |
| Cone-twist joint — locks anchors AND constrains relative rotation to a swing-cone + twist-limit. More... | |
| struct | Joint6DOF |
| Generic 6-DOF joint — per-axis lock / limit / free + optional motor and spring on each axis. More... | |
| struct | KccFrameResult |
| Collision-owned result for one player KCC step. More... | |
| struct | MapCollisionData |
| Collision data. More... | |
| struct | MapLoadOptions |
| Load options. More... | |
| struct | RagdollPbdJoint |
| One articulated joint in a PBD ragdoll skeleton. More... | |
| struct | HitscanHit |
| Result of a hitscan raycast. More... | |
| struct | HitboxHit |
| Skeleton-driven hitbox raycast (capsule-based). More... | |
| struct | SleepConfig |
| struct | SolverConfig |
| struct | Plane |
| An infinite plane dividing free space from solid geometry. More... | |
| struct | WorldAABB |
| An axis-aligned box in world space, used as static collision geometry. More... | |
| struct | WorldBrush |
| A convex volume defined by bounding planes (for ramps, angled walls, etc.). More... | |
| struct | WorldCylinder |
| A vertical (Y-axis) cylinder in world space. More... | |
| struct | WorldSphere |
| A sphere in world space. More... | |
| struct | BVHNode |
| A single BVH node for spatial acceleration of triangle meshes. More... | |
| struct | WorldTriMesh |
| A triangle mesh with BVH acceleration for collision queries. More... | |
| struct | StaticWorldBroadphase |
| Immutable world-level BVH over WorldTriMesh bounds. More... | |
| struct | WorldGeometry |
| All world collision geometry for one tick. More... | |
| struct | CapsuleShape |
| Capsule shape input for swept-collision queries. More... | |
| struct | HitResult |
| Result of a swept AABB collision query. More... | |
| struct | ClearanceResult |
| Result of a shape-vs-geometry closest-point clearance query. More... | |
| struct | GroundProbeResult |
| Result of a downward ground probe — what's directly under a character's feet, classified for walkability. More... | |
| struct | DepenContact |
| Single deepest contact from a capsule against a primitive or the world. More... | |
| struct | DepenetrationOptions |
| struct | DepenetrationResult |
| struct | SphereHitResult |
| Result of a sphere-cast query (includes world-space hit point). More... | |
| struct | TriMeshValidationReport |
| Map-cooking validation counters for authored collision triangle meshes. More... | |
| struct | TriMeshValidationTotals |
| Aggregate validation counters across a whole authored collision set. More... | |
| struct | TriMeshCookStats |
| Runtime/cook summary for authored static collision triangle meshes. More... | |
| struct | ClosestPointOnMeshResult |
| Result of a closest-point-on-mesh query. More... | |
| struct | WallDetectionResult |
| Results of wall detection probes. More... | |
| struct | WallAttachmentResult |
| Stable wallrun attachment target on authored triangle meshes. More... | |
Enumerations | |
| enum class | TriRegion : uint8_t { Face = 0 , Edge0 = 1 , Edge1 = 2 , Edge2 = 3 , Vert0 = 4 , Vert1 = 5 , Vert2 = 6 } |
| Voronoi region of a triangle. More... | |
Functions | |
| void | solveJoints (Registry ®istry, const SolverConfig &cfg, float dt) |
| Solve every joint in the registry using sequential impulses. | |
| void | clampVelocities (Registry ®istry, float maxAngular=30.0f, float maxLinear=1500.0f) |
| Clamp every dynamic body's angular and linear velocity to a safe upper bound. | |
| bool | loadMapCollision (const std::string &path, MapCollisionData &out, const MapLoadOptions &opts={}) |
| API. | |
| bool | loadPropCollision (const std::string &path, MapCollisionData &out, glm::vec3 position, float scale, bool decomposeNonConvex=false) |
| Load collision for a standalone prop GLB and append to existing collision data. | |
| glm::vec3 | applyGravity (glm::vec3 vel, float dt, bool flipped=false) |
| Apply gravity for one tick. | |
| glm::vec3 | applyPlayerGravity (glm::vec3 vel, float dt, bool flipped=false) |
| Apply the player's gravity for one tick (k_playerGravity). | |
| glm::vec3 | applyGroundFriction (glm::vec3 vel, float dt) |
| Apply Quake-style ground friction to horizontal (XZ) velocity. | |
| glm::vec3 | accelerate (glm::vec3 vel, glm::vec3 wishDir, float wishSpeed, float accel, float dt) |
| Quake PM_Accelerate: accelerate toward wishDir up to wishSpeed. | |
| float | airWishSpeedForHorizSpeed (float currentHorizSpeed) |
| Compute the air wish-speed for the player's current horizontal speed. | |
| glm::vec3 | clipVelocity (glm::vec3 vel, glm::vec3 normal, float overbounce) |
| Project velocity onto a collision surface to slide along it. | |
| glm::vec3 | computeWishDir (float yaw, bool forward, bool back, bool left, bool right) |
| Compute the horizontal wish direction from yaw angle and WASD key state. | |
| void | enforceRagdollConnectivity (Registry ®istry, float dt, int iterations=8) |
| Enforce ragdoll connectivity + angular limits via N PBD iterations. | |
| bool | raycastAABB (glm::vec3 origin, glm::vec3 direction, const WorldAABB &box, float maxDistance, float &outDistance, glm::vec3 &outNormal) |
| Ray vs axis-aligned box intersection (slab method). | |
| bool | raycastCylinder (glm::vec3 origin, glm::vec3 direction, const WorldCylinder &cyl, float maxDistance, float &outDistance, glm::vec3 &outNormal) |
| Ray vs vertical cylinder intersection. | |
| bool | raycastSphere (glm::vec3 origin, glm::vec3 direction, const WorldSphere &sph, float maxDistance, float &outDistance, glm::vec3 &outNormal) |
| Ray vs sphere intersection. | |
| bool | raycastTriMeshIndexed (glm::vec3 origin, glm::vec3 direction, const WorldTriMesh &mesh, float maxDistance, float &outDistance, glm::vec3 &outNormal, uint32_t &outTriIdx) |
| Raycast against a triangle mesh using BVH-accelerated Möller-Trumbore. | |
| bool | raycastTriMesh (glm::vec3 origin, glm::vec3 direction, const WorldTriMesh &mesh, float maxDistance, float &outDistance, glm::vec3 &outNormal) |
| Convenience wrapper for callers that don't care which triangle was hit. | |
| bool | raycastBrush (glm::vec3 origin, glm::vec3 direction, const WorldBrush &brush, float maxDistance, float &outDistance, glm::vec3 &outNormal) |
| Ray vs convex brush intersection (generalised slab method). | |
| HitscanHit | raycastWorld (glm::vec3 origin, glm::vec3 direction, const WorldGeometry &world) |
| Raycast against all static world geometry (planes + boxes + cylinders + spheres). | |
| HitscanHit | raycastPlayers (Registry ®istry, entt::entity shooter, glm::vec3 origin, glm::vec3 direction, float maxDistance) |
| Raycast against all player hitboxes (axis-aligned capsule approximation). | |
| HitscanHit | resolveHitscan (Registry ®istry, entt::entity shooter, glm::vec3 origin, glm::vec3 direction) |
| Full hitscan resolution: world geometry first, then players (closest wins). | |
| bool | raycastCapsule (glm::vec3 origin, glm::vec3 dir, glm::vec3 A, glm::vec3 B, float r, float maxDist, float &outDist, glm::vec3 &outNormal) |
| Ray vs capsule intersection. | |
| HitboxHit | raycastPlayerHitboxes (Registry ®istry, entt::entity shooter, glm::vec3 origin, glm::vec3 direction, float maxDistance, float bulletRadius=0.0f) |
| Raycast against all player hitbox capsules (skeleton-driven). | |
| HitboxHit | resolveHitscanHitbox (Registry ®istry, entt::entity shooter, glm::vec3 origin, glm::vec3 direction, float bulletRadius=0.0f) |
| Full hitscan with skeleton-driven hitboxes. | |
| void | updateSleep (Registry ®istry, const SleepConfig &cfg) |
| Update each body's sleep state from its current velocities. | |
| void | wakeBody (Registry ®istry, entt::entity e) |
| Wake a single body (e.g. | |
| void | wakeIslandOf (Registry ®istry, const ContactCache &cache, entt::entity e) |
| Wake every body that's currently in the same contact island as e. | |
| void | solveContacts (Registry ®istry, ContactCache &cache, const SolverConfig &cfg, float dt) |
| Solve every cached contact manifold for the current tick. | |
| void | buildStaticWorldBroadphase (StaticWorldBroadphase &broadphase, std::span< const WorldTriMesh > triMeshes) |
| Rebuild the immutable broadphase over all static triangle meshes. | |
| void | queryStaticWorldBroadphase (const StaticWorldBroadphase &broadphase, const WorldAABB &query, const std::function< bool(uint32_t meshIndex)> &visit) |
| Visit triangle-mesh indices whose mesh bounds overlap query. | |
| HitResult | sweepAABB (glm::vec3 halfExtents, glm::vec3 start, glm::vec3 end, std::span< const Plane > planes) |
| Sweep an AABB along the path [start, end] against a list of infinite planes. | |
| HitResult | sweepAABBvsBox (glm::vec3 halfExtents, glm::vec3 start, glm::vec3 end, const WorldAABB &box) |
| Sweep an AABB against a static axis-aligned box. | |
| HitResult | sweepAABBvsBrush (glm::vec3 halfExtents, glm::vec3 start, glm::vec3 end, const WorldBrush &brush) |
| Sweep an AABB against a convex brush (set of bounding planes). | |
| HitResult | sweepAABBvsCylinder (glm::vec3 halfExtents, glm::vec3 start, glm::vec3 end, const WorldCylinder &cyl) |
| Sweep an AABB against a vertical cylinder. | |
| HitResult | sweepAABBvsSphere (glm::vec3 halfExtents, glm::vec3 start, glm::vec3 end, const WorldSphere &sph) |
| Sweep an AABB against a sphere. | |
| HitResult | sweepCapsuleVsPlanes (CapsuleShape capsule, glm::vec3 start, glm::vec3 end, std::span< const Plane > planes) |
| Sweep a capsule along [start, end] against a list of infinite planes. | |
| HitResult | sweepCapsuleVsBox (CapsuleShape capsule, glm::vec3 start, glm::vec3 end, const WorldAABB &box) |
| Sweep a capsule against a static axis-aligned box. Conservative. | |
| HitResult | sweepCapsuleVsBrush (CapsuleShape capsule, glm::vec3 start, glm::vec3 end, const WorldBrush &brush) |
| Sweep a capsule against a convex brush. Exact (per-plane Minkowski extent). | |
| HitResult | sweepCapsuleVsCylinder (CapsuleShape capsule, glm::vec3 start, glm::vec3 end, const WorldCylinder &cyl) |
| Sweep a capsule against a vertical cylinder. Conservative. | |
| HitResult | sweepCapsuleVsSphere (CapsuleShape capsule, glm::vec3 start, glm::vec3 end, const WorldSphere &sph) |
| Sweep a capsule against a sphere. Conservative. | |
| HitResult | sweepAll (glm::vec3 halfExtents, glm::vec3 start, glm::vec3 end, const WorldGeometry &world) |
| Sweep an AABB against all world geometry, returning the earliest hit. | |
| HitResult | sweepAll (CapsuleShape capsule, glm::vec3 start, glm::vec3 end, const WorldGeometry &world) |
| Sweep a capsule against all world geometry, returning the earliest hit. | |
| ClearanceResult | clearanceCapsuleVsPlanes (CapsuleShape capsule, glm::vec3 pos, std::span< const Plane > planes) |
| ClearanceResult | clearanceCapsuleVsBox (CapsuleShape capsule, glm::vec3 pos, const WorldAABB &box) |
| ClearanceResult | clearanceCapsuleVsBrush (CapsuleShape capsule, glm::vec3 pos, const WorldBrush &brush) |
| ClearanceResult | clearanceCapsuleVsCylinder (CapsuleShape capsule, glm::vec3 pos, const WorldCylinder &cyl) |
| ClearanceResult | clearanceCapsuleVsSphere (CapsuleShape capsule, glm::vec3 pos, const WorldSphere &sph) |
| ClearanceResult | clearanceCapsuleVsWorld (CapsuleShape capsule, glm::vec3 pos, const WorldGeometry &world, float maxMeshSearchRadius=1024.0f) |
| Scene-wide minimum clearance. | |
| GroundProbeResult | probeGround (CapsuleShape capsule, glm::vec3 pos, float maxDistance, const WorldGeometry &world) |
| Downward sweep that classifies the ground under a capsule. | |
| DepenContact | deepestCapsuleContact (CapsuleShape capsule, glm::vec3 pos, glm::vec3 vel, const WorldGeometry &world) |
| Scene-wide deepest single contact (per-primitive, per-feature). | |
| DepenetrationResult | depenetrateCapsuleVsWorldDetailed (glm::vec3 &pos, glm::vec3 &vel, CapsuleShape capsule, const WorldGeometry &world, DepenetrationOptions options) |
| void | depenetrateCapsuleVsWorld (glm::vec3 &pos, glm::vec3 &vel, CapsuleShape capsule, const WorldGeometry &world) |
| Per-pass-deepest-first capsule depenetration against the whole world. | |
| bool | emergencyUnstick (glm::vec3 &pos, glm::vec3 &vel, CapsuleShape capsule, const WorldGeometry &world) |
| Last-resort recovery for a capsule embedded in geometry with no clear depen direction. | |
| SphereHitResult | sphereCast (float radius, glm::vec3 start, glm::vec3 end, const WorldGeometry &world) |
| Cast a sphere along the path [start, end] against all world geometry. | |
| bool | broadphaseAabbOverlap (const WorldAABB &a, const WorldAABB &b) noexcept |
| template<class Visit> | |
| void | queryStaticWorldBroadphaseFast (const StaticWorldBroadphase &broadphase, const WorldAABB &query, Visit &&visit) |
| void | buildTriMeshBVH (WorldTriMesh &mesh) |
| Build the BVH for a WorldTriMesh. | |
| void | weldTriMesh (WorldTriMesh &mesh, float coplanarTolerance=0.0349065850f) |
| Compute face normals + active edge / vertex flags for a triangle mesh. | |
| TriMeshValidationReport | validateTriMesh (const WorldTriMesh &mesh, float positionEpsilon=1e-4f) |
| Validate authored collision mesh topology before/after cooking. | |
| TriMeshValidationTotals | validateTriMeshes (std::span< const WorldTriMesh > meshes, float positionEpsilon=1e-4f) |
| Validate every triangle mesh in an authored collision set. | |
| TriMeshCookStats | collectTriMeshCookStats (std::span< const WorldTriMesh > meshes) |
| Collect aggregate map-cooking diagnostics for already-cooked meshes. | |
| HitResult | sweepAABBvsTriMesh (glm::vec3 halfExtents, glm::vec3 start, glm::vec3 end, const WorldTriMesh &mesh) |
| Sweep an AABB against a triangle mesh using Voronoi-clipped per-triangle tests. | |
| void | depenetrateAABBvsTriMesh (glm::vec3 &pos, glm::vec3 &vel, glm::vec3 halfExtents, const WorldTriMesh &mesh, float pushback=0.03125f) |
| Push an AABB out of a triangle mesh using Voronoi-clipped face-normal MTVs. | |
| HitResult | sweepCapsuleVsTriMesh (CapsuleShape capsule, glm::vec3 start, glm::vec3 end, const WorldTriMesh &mesh) |
| Sweep a capsule against a triangle mesh. | |
| DepenContact | deepestCapsuleContactVsTriMesh (CapsuleShape capsule, glm::vec3 pos, glm::vec3 vel, const WorldTriMesh &mesh) |
| Single deepest surface contact of a capsule against any triangle in this mesh. | |
| ClosestPointOnMeshResult | closestPointOnMesh (glm::vec3 segA, glm::vec3 segB, float maxDist, const WorldTriMesh &mesh) |
| Find the closest point on the mesh's surface to a query segment, considering only points within maxDist. | |
| ClosestPointOnMeshResult | closestPointOnMesh (CapsuleShape capsule, glm::vec3 center, float maxDist, const WorldTriMesh &mesh) |
| Convenience overload — uses the capsule's inner axis as the query segment at the given centre position. | |
| ClosestPointOnMeshResult | closestPointOnMeshTriangle (CapsuleShape capsule, glm::vec3 center, float maxDist, const WorldTriMesh &mesh, uint32_t triId) |
| Closest point from a capsule axis to one specific cooked triangle. | |
| ClearanceResult | clearanceCapsuleVsTriMesh (CapsuleShape capsule, glm::vec3 pos, float maxReach, const WorldTriMesh &mesh) |
| Capsule-vs-trimesh clearance. | |
| GroundProbeResult | groundProbeCapsuleVsTriMesh (CapsuleShape capsule, glm::vec3 pos, float maxDistance, float minWalkableDot, const WorldTriMesh &mesh) |
| Downward ground probe against walkable triangle faces only. | |
| WallAttachmentResult | findWallRunAttachment (CapsuleShape capsule, glm::vec3 pos, const WorldGeometry &world, glm::vec3 continuityNormal, glm::vec3 travelDir=glm::vec3{0.0f}, float lookaheadDist=0.0f, float checkDist=24.0f, uint32_t previousMeshIndex=UINT32_MAX, uint32_t previousTriId=UINT32_MAX, TriRegion previousRegion=TriRegion::Face) |
| Find the best triangle-mesh wallrun attachment, with optional lookahead along the current travel direction. | |
| WallDetectionResult | detectWalls (glm::vec3 pos, float yaw, glm::vec3 halfExtents, const WorldGeometry &world, float checkDist, float sphereRadius, glm::vec3 prevWallNormal=glm::vec3(0.0f), bool gravityFlipped=false, bool includeGroundDistance=true) |
| Detect walls to the left, right, and front of the player. | |
| float | probeWallrunGroundDistance (glm::vec3 pos, glm::vec3 halfExtents, const WorldGeometry &world, float sphereRadius, bool gravityFlipped=false) |
| Probe only the downward ground distance used by wallrun entry gates. | |
| bool | isWallNormal (glm::vec3 normal) |
| Check if a surface normal represents a wall (not floor/ceiling). | |
| void | setActiveWorld (const WorldGeometry &geo) |
| Set the world geometry that activeWorld() returns. | |
| const WorldGeometry & | activeWorld () |
| Return the world geometry most recently set via setActiveWorld(), or fall back to testWorld() if none has been set. | |
| WorldBrush | makeRamp (float xMin, float xMax, float zMin, float zMax, float height) |
| Create a ramp brush that rises along +Z. | |
| WorldBrush | makeDiagonalWall (glm::vec3 center, float halfLen, float halfThick, float height, glm::vec3 dir) |
| Create a diagonal wall brush from a centre, direction, and dimensions. | |
| const WorldGeometry & | testWorld () |
| The physics test playground. | |
Variables | |
| constexpr int | k_maxContactPoints = 4 |
| Up to 4 points per body pair — enough for any flat-face contact (box-on-box, box-on-ground, etc.). | |
| constexpr float | k_gravity = 1000.0f |
| Downward acceleration (units/s^2) for projectiles / dynamics. | |
| constexpr float | k_playerGravity |
| Player-specific gravity (units/s^2). | |
| constexpr float | k_jumpSpeed = 660.0f |
| Initial upward velocity on jump (units/s). | |
| constexpr float | k_groundAccel = 10.0f |
| Ground acceleration constant. Higher = reaches max speed faster. | |
| constexpr float | k_airAccel |
| Air acceleration constant. Higher than Quake (0.7) for Titanfall-style air control. | |
| constexpr float | k_airMaxSpeed = 30.0f |
| Wish-speed FLOOR in air (units/s). | |
| constexpr float | k_airMaxWishLowSpeed = 120.0f |
| Wish-speed CEILING in air (units/s) when stationary. | |
| constexpr float | k_airWishCurveTop = 250.0f |
| Horizontal speed (u/s) at which the curve plateaus at k_airMaxSpeed. | |
| constexpr float | k_airWishCurveExponent = 0.4f |
| Power-curve exponent for wish-speed falloff (<1 = sharp early drop). | |
| constexpr float | k_friction = 7.5f |
| Ground friction coefficient. Higher = crisper stops, easier-to-track movement. | |
| constexpr float | k_stopSpeed = 150.0f |
| Friction is amplified below this speed for a crisp stop. | |
| constexpr float | k_overbounceWall = 1.001f |
| Separation impulse for walls/ceilings; prevents corner-sticking. | |
| constexpr float | k_overbounceFloor = 1.0f |
| Floor overbounce — exactly 1.0 means no bounce. | |
| constexpr float | k_stepHeight = 18.0f |
| Maximum obstacle height auto-stepped over without jumping (units). | |
| constexpr float | k_floorAngleCos = 0.7f |
| dot(surfaceNormal, up) threshold above which a surface counts as walkable floor. | |
| constexpr float | k_groundSnapDistance = 8.0f |
| Distance the ground probe extends below the capsule foot to snap to descending slopes / steps. | |
| constexpr float | k_emergencyUnstickRadius = 64.0f |
| Maximum radius of the emergency-unstick free-space search. | |
| constexpr int | k_maxDepenPasses = 6 |
| Maximum sequential passes the deepest-first capsule depen attempts before falling through to emergency unstick. | |
| constexpr float | k_explosionGroundPopOffset = 10.0f |
| Upward teleport (units) at epicenter; lifts the victim past k_groundSnapDistance so the KCC won't re-anchor them this tick. | |
| constexpr float | k_explosionGroundVerticalBoost |
| Minimum upward velocity (units/s) at epicenter. | |
| constexpr float | k_gravityFlipCooldown = 0.5f |
| Minimum time between gravity flips (s). | |
| constexpr bool | k_enableSubstepping = true |
| Master toggle for Phase-C sub-stepping. | |
| constexpr float | k_substepSafetyRatio = 0.5f |
| Sub-step when |v|·dt > min_shape_radius · this. | |
| constexpr int | k_maxSubsteps = 8 |
| Clamp on sub-step count to bound worst-case cost. | |
| constexpr float | k_hitscanRange = 5000.0f |
| Maximum hitscan distance in world units. | |
| constexpr float | k_parallelEpsilon = 1e-6f |
| Epsilon for parallel-ray checks. | |
Pure physics math — no ECS types, no registry.
Wall detection.
Pure swept-collision math — no ECS types, no registry.
All physics tuning values in one place.
All functions take values in and return values out (no mutation via pointer). Constants come from PhysicsConstants.hpp.
Units: Quake units (1 unit ≈ 1 inch), Y-up coordinate system.
Starting values target a Titanfall-to-Quake movement feel. Tune iteratively — k_playerGravity and k_jumpSpeed must always be tuned together: jump height = k_jumpSpeed^2 / (2 × k_playerGravity).
Plane convention: dot(normal, p) > distance is free space; dot(normal, p) < distance is solid. The normal always points into free space.
Example planes (Y-up coordinate system):
Used by the movement system each tick to detect nearby surfaces for wallrunning.
|
strong |
Voronoi region of a triangle.
Identifies which feature (face, one of three edges, or one of three vertices) a closest-point query landed on. Used by depenetration / sweep / closest-point queries that need to clip contacts against the cooked welding-active masks, and by the Phase D wallrun manifold walk to decide whether an edge crossing hops to a neighbour triangle.
| Enumerator | |
|---|---|
| Face | |
| Edge0 | Edge v0 → v1. |
| Edge1 | Edge v1 → v2. |
| Edge2 | Edge v2 → v0. |
| Vert0 | |
| Vert1 | |
| Vert2 | |
| glm::vec3 physics::accelerate | ( | glm::vec3 | vel, |
| glm::vec3 | wishDir, | ||
| float | wishSpeed, | ||
| float | accel, | ||
| float | dt ) |
Quake PM_Accelerate: accelerate toward wishDir up to wishSpeed.
Does not cap total speed — only the projection of velocity onto wishDir is capped at wishSpeed. Existing momentum in any other direction is untouched. This property is what makes strafe jumping possible.
| vel | Current velocity. |
| wishDir | Normalised desired movement direction (from InputSnapshot + yaw). |
| wishSpeed | Target speed (systems::currentWishSpeed on ground, airWishSpeedForHorizSpeed in air). |
| accel | Acceleration constant (k_groundAccel or k_airAccel). |
| dt | Delta time in seconds. |
|
inline |
Return the world geometry most recently set via setActiveWorld(), or fall back to testWorld() if none has been set.
This is the single entry point that all physics systems should use.
| float physics::airWishSpeedForHorizSpeed | ( | float | currentHorizSpeed | ) |
Compute the air wish-speed for the player's current horizontal speed.
Returns a value that interpolates from k_airMaxWishLowSpeed (when stationary) down to k_airMaxSpeed (the floor, once horizontal speed reaches k_airWishCurveTop). Uses a power curve pow(t, k_airWishCurveExponent) with exponent < 1 so the high-wish region is concentrated near zero speed — gentle on classic strafe-jump physics, generous on stall recovery.
| currentHorizSpeed | Current horizontal speed (sqrt(vx² + vz²)). |
| glm::vec3 physics::applyGravity | ( | glm::vec3 | vel, |
| float | dt, | ||
| bool | flipped = false ) |
Apply gravity for one tick.
In normal mode subtracts k_gravity * dt from Y; when flipped, adds it.
| vel | Current velocity. |
| dt | Delta time in seconds. |
| flipped | True when the player's gravity is inverted. |
| glm::vec3 physics::applyGroundFriction | ( | glm::vec3 | vel, |
| float | dt ) |
Apply Quake-style ground friction to horizontal (XZ) velocity.
Uses k_stopSpeed as a minimum control speed so entities stop crisply rather than asymptotically approaching zero.
| vel | Current velocity. |
| dt | Delta time in seconds. |
| glm::vec3 physics::applyPlayerGravity | ( | glm::vec3 | vel, |
| float | dt, | ||
| bool | flipped = false ) |
Apply the player's gravity for one tick (k_playerGravity).
Same shape as applyGravity but uses the player-specific constant so projectile and grenade tuning is unaffected by player jump tuning.
|
inlinenodiscardnoexcept |
| void physics::buildStaticWorldBroadphase | ( | StaticWorldBroadphase & | broadphase, |
| std::span< const WorldTriMesh > | triMeshes ) |
Rebuild the immutable broadphase over all static triangle meshes.
| void physics::buildTriMeshBVH | ( | WorldTriMesh & | mesh | ) |
Build the BVH for a WorldTriMesh.
Must be called after vertices and indices are populated. Fills in bvhNodes, triIndices, boundsMin, and boundsMax. Does NOT populate the welding data — call weldTriMesh() after this.
| void physics::clampVelocities | ( | Registry & | registry, |
| float | maxAngular = 30.0f, | ||
| float | maxLinear = 1500.0f ) |
Clamp every dynamic body's angular and linear velocity to a safe upper bound.
PhysX defaults: maxAngularVelocity = 100 rad/s for rigid bodies, ~50 rad/s for articulation links; we target a tighter 30 rad/s for ragdolls so the corpse never spins like a helicopter when the joint solver overshoots. Linear is capped at a generous 1500 u/s. No-op for bodies whose velocity is already within bounds.
| ClearanceResult physics::clearanceCapsuleVsBox | ( | CapsuleShape | capsule, |
| glm::vec3 | pos, | ||
| const WorldAABB & | box ) |
| ClearanceResult physics::clearanceCapsuleVsBrush | ( | CapsuleShape | capsule, |
| glm::vec3 | pos, | ||
| const WorldBrush & | brush ) |
| ClearanceResult physics::clearanceCapsuleVsCylinder | ( | CapsuleShape | capsule, |
| glm::vec3 | pos, | ||
| const WorldCylinder & | cyl ) |
| ClearanceResult physics::clearanceCapsuleVsPlanes | ( | CapsuleShape | capsule, |
| glm::vec3 | pos, | ||
| std::span< const Plane > | planes ) |
| ClearanceResult physics::clearanceCapsuleVsSphere | ( | CapsuleShape | capsule, |
| glm::vec3 | pos, | ||
| const WorldSphere & | sph ) |
| ClearanceResult physics::clearanceCapsuleVsTriMesh | ( | CapsuleShape | capsule, |
| glm::vec3 | pos, | ||
| float | maxReach, | ||
| const WorldTriMesh & | mesh ) |
Capsule-vs-trimesh clearance.
Wraps closestPointOnMesh and converts axis-to-mesh distance into surface-to-surface clearance by subtracting capsule.radius.
Used by the Phase-C scene-wide clearanceCapsuleVsWorld aggregator. maxReach bounds the BVH search radius — pass at least the per-tick motion magnitude plus capsule.radius to ensure no contacts are missed within the integration step.
| ClearanceResult physics::clearanceCapsuleVsWorld | ( | CapsuleShape | capsule, |
| glm::vec3 | pos, | ||
| const WorldGeometry & | world, | ||
| float | maxMeshSearchRadius = 1024.0f ) |
Scene-wide minimum clearance.
Returns the nearest geometry feature in any direction. This is the closest-point query the conservative-advancement integrator drives off of every iteration.
| glm::vec3 physics::clipVelocity | ( | glm::vec3 | vel, |
| glm::vec3 | normal, | ||
| float | overbounce ) |
Project velocity onto a collision surface to slide along it.
| vel | Current velocity. |
| normal | Surface normal at the contact point. |
| overbounce | Separation scalar: use k_overbounceFloor for floors, k_overbounceWall for walls/ceilings. |
| ClosestPointOnMeshResult physics::closestPointOnMesh | ( | CapsuleShape | capsule, |
| glm::vec3 | center, | ||
| float | maxDist, | ||
| const WorldTriMesh & | mesh ) |
Convenience overload — uses the capsule's inner axis as the query segment at the given centre position.
| ClosestPointOnMeshResult physics::closestPointOnMesh | ( | glm::vec3 | segA, |
| glm::vec3 | segB, | ||
| float | maxDist, | ||
| const WorldTriMesh & | mesh ) |
Find the closest point on the mesh's surface to a query segment, considering only points within maxDist.
BVH-accelerated.
For wallrun (Phase D) the query segment is the capsule's inner axis (capsule.segA(pos) to capsule.segB(pos)). The result identifies "what wall am I on" without the heuristic dot-product reassignment that the current sphere-cast-based WallDetection uses. At edges and vertices, region plus triId plus the mesh's edgeNeighbor array is enough to walk the surface manifold across triangle seams.
Returns found = false if no triangle is within maxDist.
| ClosestPointOnMeshResult physics::closestPointOnMeshTriangle | ( | CapsuleShape | capsule, |
| glm::vec3 | center, | ||
| float | maxDist, | ||
| const WorldTriMesh & | mesh, | ||
| uint32_t | triId ) |
Closest point from a capsule axis to one specific cooked triangle.
Used by systems that already track triangle identity, such as wallrun manifold traversal. Returns found=false for invalid triangle ids, degenerate triangles, or distances beyond maxDist.
| TriMeshCookStats physics::collectTriMeshCookStats | ( | std::span< const WorldTriMesh > | meshes | ) |
Collect aggregate map-cooking diagnostics for already-cooked meshes.
Intended for load-time logging and tests. weldedHalfEdges counts inactive manifold half-edges, so a flat seam shared by two triangles contributes two.
| glm::vec3 physics::computeWishDir | ( | float | yaw, |
| bool | forward, | ||
| bool | back, | ||
| bool | left, | ||
| bool | right ) |
Compute the horizontal wish direction from yaw angle and WASD key state.
| yaw | Player's current yaw in radians. |
| forward | True when W is held. |
| back | True when S is held. |
| left | True when A is held. |
| right | True when D is held. |
| DepenContact physics::deepestCapsuleContact | ( | CapsuleShape | capsule, |
| glm::vec3 | pos, | ||
| glm::vec3 | vel, | ||
| const WorldGeometry & | world ) |
Scene-wide deepest single contact (per-primitive, per-feature).
Used by the modern depen as the per-pass oracle: pick the deepest violation across the whole world, push out of it, re-probe.
| DepenContact physics::deepestCapsuleContactVsTriMesh | ( | CapsuleShape | capsule, |
| glm::vec3 | pos, | ||
| glm::vec3 | vel, | ||
| const WorldTriMesh & | mesh ) |
Single deepest surface contact of a capsule against any triangle in this mesh.
BVH-accelerated. Used by the world-level depenetrateCapsuleVsWorld to pick the deepest violator per pass.
Reports capsule surface penetration depth: capsule.radius - distance where distance is the closest distance from the capsule axis segment to the bounded triangle. The normal points from the triangle feature toward the capsule, with the face normal used only for exactly coincident pairs.
| void physics::depenetrateAABBvsTriMesh | ( | glm::vec3 & | pos, |
| glm::vec3 & | vel, | ||
| glm::vec3 | halfExtents, | ||
| const WorldTriMesh & | mesh, | ||
| float | pushback = 0.03125f ) |
Push an AABB out of a triangle mesh using Voronoi-clipped face-normal MTVs.
For each triangle the AABB overlaps (BVH-accelerated leaf search), the closest feature is found and Voronoi-clipped against the mesh's active-edge/active-vertex flags. Surviving contacts contribute one face- normal MTV (depth × face normal); contributions across multiple triangles are aggregated and applied once.
This replaces the older SAT-MTV implementation, which fired on internal edges of triangulated planar surfaces ("ghost contacts") and required 4 averaging passes to mask the noise. With Voronoi clipping, ghosts are suppressed at the source — one pass suffices.
Velocity is updated to cancel the component flowing into the surface, so the entity slides along the contact rather than re-penetrating next frame.
| pos | AABB centre — modified in place to push out of overlaps. |
| vel | Velocity — modified in place to cancel inward motion. |
| halfExtents | AABB half-extents. |
| mesh | Triangle mesh to depenetrate from (must be welded). |
| pushback | Tiny extra distance added to each push to avoid hairline contact (matches Quake's DIST_EPSILON of 1/32 unit). |
| void physics::depenetrateCapsuleVsWorld | ( | glm::vec3 & | pos, |
| glm::vec3 & | vel, | ||
| CapsuleShape | capsule, | ||
| const WorldGeometry & | world ) |
Per-pass-deepest-first capsule depenetration against the whole world.
Replaces the legacy AABB depen + per-feature MTV summation. Each pass:
Oscillation detector: if pass N's contact normal points opposite to pass N-1's (dot < -k_floorAngleCos), the player straddles a 2-sided thin volume with no single consistent ejection direction. Fall straight through to emergencyUnstick() rather than ping-ponging.
| pos | Capsule centre — modified in place to push out of overlaps. |
| vel | Velocity — modified in place to cancel components into surfaces. |
| capsule | Player capsule shape. |
| world | World collision geometry. |
| DepenetrationResult physics::depenetrateCapsuleVsWorldDetailed | ( | glm::vec3 & | pos, |
| glm::vec3 & | vel, | ||
| CapsuleShape | capsule, | ||
| const WorldGeometry & | world, | ||
| DepenetrationOptions | options ) |
| WallDetectionResult physics::detectWalls | ( | glm::vec3 | pos, |
| float | yaw, | ||
| glm::vec3 | halfExtents, | ||
| const WorldGeometry & | world, | ||
| float | checkDist, | ||
| float | sphereRadius, | ||
| glm::vec3 | prevWallNormal = glm::vec3(0.0f), | ||
| bool | gravityFlipped = false, | ||
| bool | includeGroundDistance = true ) |
Detect walls to the left, right, and front of the player.
Also probes downward to measure ground distance (used for wallrun min-height gates).
| pos | Player AABB centre position. |
| yaw | Player facing direction (radians). |
| halfExtents | Player AABB half-extents (for offset calculations). |
| world | World collision geometry. |
| checkDist | How far sideways/forward to trace (u). |
| sphereRadius | Radius of the trace sphere (u). |
| prevWallNormal | Previous tick's wall normal (zero if not wallrunning). When non-zero, an additional trace is cast toward -prevWallNormal to track curved surfaces (cylinders, concave walls) whose normal rotates as the player moves. |
| gravityFlipped | True when the player's local up axis is -Y. |
| bool physics::emergencyUnstick | ( | glm::vec3 & | pos, |
| glm::vec3 & | vel, | ||
| CapsuleShape | capsule, | ||
| const WorldGeometry & | world ) |
Last-resort recovery for a capsule embedded in geometry with no clear depen direction.
Probes outward in axis-aligned cardinal directions at increasing radii looking for any position where the capsule has positive clearance. When found, teleports the capsule centre there and zeros velocity. When nothing within k_emergencyUnstickRadius works, the position is left unchanged (game code should fall back to a respawn).
| void physics::enforceRagdollConnectivity | ( | Registry & | registry, |
| float | dt, | ||
| int | iterations = 8 ) |
Enforce ragdoll connectivity + angular limits via N PBD iterations.
Each iteration walks every RagdollPbdJoint in deterministic order, computes the world-space anchor error, and translates the two bodies to close the gap (split by inverse mass). Then a separate pass clamps the relative rotation between parent and child into the joint's angular limit. After all iterations, per-body velocities are derived from the net position change (PBD-style) so contact response in the next tick still sees realistic motion.
Typical configuration: 8 iterations per tick is overkill for a 15-body humanoid; 4 already gives sub-millimetre anchor error.
| WallAttachmentResult physics::findWallRunAttachment | ( | CapsuleShape | capsule, |
| glm::vec3 | pos, | ||
| const WorldGeometry & | world, | ||
| glm::vec3 | continuityNormal, | ||
| glm::vec3 | travelDir = glm::vec3{0.0f}, | ||
| float | lookaheadDist = 0.0f, | ||
| float | checkDist = 24.0f, | ||
| uint32_t | previousMeshIndex = UINT32_MAX, | ||
| uint32_t | previousTriId = UINT32_MAX, | ||
| TriRegion | previousRegion = TriRegion::Face ) |
Find the best triangle-mesh wallrun attachment, with optional lookahead along the current travel direction.
Current-position attachment keeps ordinary wallruns stable. The lookahead sample lets convex/outside corners select the upcoming perpendicular wall before the old wall's closest point flips the tangent backward.
| GroundProbeResult physics::groundProbeCapsuleVsTriMesh | ( | CapsuleShape | capsule, |
| glm::vec3 | pos, | ||
| float | maxDistance, | ||
| float | minWalkableDot, | ||
| const WorldTriMesh & | mesh ) |
Downward ground probe against walkable triangle faces only.
This is stricter than general capsule CCD: finite edges and vertices block movement, but they are not valid ground support by themselves. The support point of the capsule must project onto a walkable triangle face, preventing stair treads from launching the player upward while the capsule is still in front of the tread edge.
|
inline |
Check if a surface normal represents a wall (not floor/ceiling).
Walls have normals that are roughly horizontal (|normal.y| < 0.3).
| bool physics::loadMapCollision | ( | const std::string & | path, |
| MapCollisionData & | out, | ||
| const MapLoadOptions & | opts = {} ) |
API.
Extract collision geometry from a map .glb file.
Walks the Assimp scene graph. For each mesh node, determines whether it belongs to the collision collection (by checking ancestor node names) or, in all-mesh mode, always. Collision meshes are preserved as WorldTriMesh vertex-for-vertex after Assimp triangulation.
This function does not produce visual / renderable data — use the existing Renderer::loadSceneModel() path for that.
| path | Absolute or relative path to the .glb file. |
| out | Filled with extracted collision geometry on success. |
| opts | Loading options (scale, collection name, all-mesh mode). |
| bool physics::loadPropCollision | ( | const std::string & | path, |
| MapCollisionData & | out, | ||
| glm::vec3 | position, | ||
| float | scale, | ||
| bool | decomposeNonConvex = false ) |
Load collision for a standalone prop GLB and append to existing collision data.
Loads the GLB, applies the given transform (position + uniform scale), runs auto-detection on each mesh, and appends the resulting primitives to out. Call setActiveWorld(out.geometry()) after all props are loaded to update the physics world.
| path | Absolute path to the .glb file. |
| out | Existing collision data to append to. |
| position | World-space position of the prop. |
| scale | Uniform scale factor. |
| decomposeNonConvex | Legacy opt-in: when true and GROUP2_ENABLE_VHACD is enabled at configure time, non-convex meshes inside the prop are run through V-HACD convex decomposition. In normal builds this request logs and falls back to WorldTriMesh. |
|
inline |
Create a diagonal wall brush from a centre, direction, and dimensions.
| center | Centre of the wall base (y=0). |
| halfLen | Half-length along dir. |
| halfThick | Half-thickness perpendicular to dir in XZ. |
| height | Wall height (from y=0 to y=height). |
| dir | Normalised direction along the wall in XZ. |
|
inline |
Create a ramp brush that rises along +Z.
The wedge shape goes from (xMin, 0, zMin) at ground level to (xMax, height, zMax) at the back-top edge.
| GroundProbeResult physics::probeGround | ( | CapsuleShape | capsule, |
| glm::vec3 | pos, | ||
| float | maxDistance, | ||
| const WorldGeometry & | world ) |
Downward sweep that classifies the ground under a capsule.
Sweeps the capsule along -up * maxDistance from pos, then evaluates whether the first contact's normal qualifies as a floor. This is the query the modern two-capsule character controller uses each tick to (a) decide grounded vs airborne and (b) settle the foot onto the surface — replacing the legacy lift→horiz→drop swept-AABB step-up.
| capsule | The full capsule (not the walk-shape) — the foot direction is -capsule.up. |
| pos | Capsule centre at the start of the probe. |
| maxDistance | How far to probe along the foot direction. Should be effectiveStepHeight + k_groundSnapDistance for a grounded player, k_groundSnapDistance for an airborne landing check. |
| world | World collision geometry. |
| float physics::probeWallrunGroundDistance | ( | glm::vec3 | pos, |
| glm::vec3 | halfExtents, | ||
| const WorldGeometry & | world, | ||
| float | sphereRadius, | ||
| bool | gravityFlipped ) |
Probe only the downward ground distance used by wallrun entry gates.
| void physics::queryStaticWorldBroadphase | ( | const StaticWorldBroadphase & | broadphase, |
| const WorldAABB & | query, | ||
| const std::function< bool(uint32_t meshIndex)> & | visit ) |
Visit triangle-mesh indices whose mesh bounds overlap query.
The visitor returns false to stop early, true to continue.
|
inline |
|
inline |
Ray vs axis-aligned box intersection (slab method).
|
inline |
Ray vs convex brush intersection (generalised slab method).
A WorldBrush is the intersection of half-spaces defined by planes with outward normals; the solid interior satisfies dot(n, p) <= distance for every plane. A ray hits the brush at the latest plane it enters from outside, provided that t doesn't exceed the earliest plane it exits. Mirrors the logic in sweepAABBvsBrush but for a point-ray instead of a swept AABB.
|
inline |
Ray vs capsule intersection.
A capsule is the Minkowski sum of the line segment AB and a sphere of radius r. Decomposed into: (1) ray vs infinite cylinder along AB, clamped to the segment, then (2) ray vs hemisphere endcaps.
maxDist.
|
inline |
Ray vs vertical cylinder intersection.
|
inline |
Raycast against all player hitbox capsules (skeleton-driven).
Uses a broad-phase AABB check (CollisionShape) before testing individual capsules, so only nearby players pay the narrow-phase cost.
PR-20.6 (root-cause fix): pre-PR-20.6 the view required the Player tag. That worked on the server (which emplaces Player per connected client), but not on the CLIENT — Player is not in the replicated Synced tuple (network/RegistrySerialization.cpp) and the client never emplaces it locally. Result: client-side resolveHitscanHitbox walked an empty view, no capsule hits ever registered, and the shot-debug visualizer's blue tracer flew straight through every enemy. HitboxInstance is only added by systems::updateHitboxes to entities with JointMatrices — i.e. animated characters — so it's a stronger gate than Player anyway and the filter is now strictly more permissive without picking up any non-character entities.
| bulletRadius | Cylinder/swept-sphere radius (world units) added to every capsule's radius. A thick ray of radius R vs a capsule of radius r is the thin ray vs a capsule of radius (R + r) — so the whole "cylinder hitreg" reduces to inflating the capsule. 0 = exact ray (legacy). The reported hit distance is the distance to the bullet CENTRE at first contact (slightly in front of the surface). |
|
inline |
Raycast against all player hitboxes (axis-aligned capsule approximation).
|
inline |
Ray vs sphere intersection.
|
inline |
Convenience wrapper for callers that don't care which triangle was hit.
|
inline |
Raycast against a triangle mesh using BVH-accelerated Möller-Trumbore.
Indexed variant — also reports the canonical triangle index that was hit, so callers can look up per-triangle materials in the mesh.
|
inline |
Raycast against all static world geometry (planes + boxes + cylinders + spheres).
|
inline |
Full hitscan resolution: world geometry first, then players (closest wins).
|
inline |
Full hitscan with skeleton-driven hitboxes.
World geometry first, then player hitbox capsules (closest wins). Falls back to the old AABB path for players without HitboxInstance.
| bulletRadius | Swept-sphere "cylinder hitreg" radius (world units) applied to PLAYER hitboxes only. World geometry stays a thin ray so bullets still require crosshair line-of-sight past walls. 0 = ray. |
|
inline |
Set the world geometry that activeWorld() returns.
The caller retains ownership of the memory behind the spans — the pointed-to data must outlive every call to activeWorld(). Typically backed by a MapCollisionData whose vectors live for the duration of the game.
Both client and server must call this with identical data before the first physics tick to maintain prediction parity.
| void physics::solveContacts | ( | Registry & | registry, |
| ContactCache & | cache, | ||
| const SolverConfig & | cfg, | ||
| float | dt ) |
Solve every cached contact manifold for the current tick.
Bodies' Velocity / AngularVelocity components are updated in place.
Caller responsibilities:
| void physics::solveJoints | ( | Registry & | registry, |
| const SolverConfig & | cfg, | ||
| float | dt ) |
Solve every joint in the registry using sequential impulses.
Called from the same physics step as solveContacts. Joints are iterated in stable order (sorted by entity id) for determinism.
| SphereHitResult physics::sphereCast | ( | float | radius, |
| glm::vec3 | start, | ||
| glm::vec3 | end, | ||
| const WorldGeometry & | world ) |
Cast a sphere along the path [start, end] against all world geometry.
Uses the Minkowski-sum approach: geometry is expanded by the sphere radius, then the sweep becomes a point (ray) test against the expanded geometry.
| radius | Sphere radius (u). |
| start | World-space start of sweep (sphere centre). |
| end | World-space end of sweep (sphere centre). |
| world | World collision geometry to test against. |
| HitResult physics::sweepAABB | ( | glm::vec3 | halfExtents, |
| glm::vec3 | start, | ||
| glm::vec3 | end, | ||
| std::span< const Plane > | planes ) |
Sweep an AABB along the path [start, end] against a list of infinite planes.
Uses the Minkowski-sum approach: each plane is expanded outward by the AABB half-extents, reducing the problem to a ray-vs-expanded-plane intersection.
| halfExtents | Half-dimensions of the AABB. |
| start | World-space start position (AABB centre). |
| end | World-space end position (AABB centre). |
| planes | World collision planes to test against. |
| HitResult physics::sweepAABBvsBox | ( | glm::vec3 | halfExtents, |
| glm::vec3 | start, | ||
| glm::vec3 | end, | ||
| const WorldAABB & | box ) |
Sweep an AABB against a static axis-aligned box.
Expands the static box by the moving AABB's half-extents (Minkowski sum) and performs a ray-slab intersection test on the swept centre point. Entities starting inside the box are skipped (depenetration handles that).
| HitResult physics::sweepAABBvsBrush | ( | glm::vec3 | halfExtents, |
| glm::vec3 | start, | ||
| glm::vec3 | end, | ||
| const WorldBrush & | brush ) |
Sweep an AABB against a convex brush (set of bounding planes).
Finds the time at which the AABB enters all half-spaces simultaneously. Entities starting inside the brush are skipped (depenetration handles that).
| HitResult physics::sweepAABBvsCylinder | ( | glm::vec3 | halfExtents, |
| glm::vec3 | start, | ||
| glm::vec3 | end, | ||
| const WorldCylinder & | cyl ) |
Sweep an AABB against a vertical cylinder.
Minkowski-expands the cylinder by the AABB half-extents: the radius grows by the XZ extent and the height caps grow by the Y extent. The sweep then reduces to a 2D ray-vs-circle test (XZ) clamped by the expanded Y slab.
| HitResult physics::sweepAABBvsSphere | ( | glm::vec3 | halfExtents, |
| glm::vec3 | start, | ||
| glm::vec3 | end, | ||
| const WorldSphere & | sph ) |
Sweep an AABB against a sphere.
Minkowski-expands the sphere radius by the AABB half-extents (approximation: uses the max half-extent component, making it slightly conservative at corners). Then performs a ray-vs-sphere test on the swept centre.
| HitResult physics::sweepAABBvsTriMesh | ( | glm::vec3 | halfExtents, |
| glm::vec3 | start, | ||
| glm::vec3 | end, | ||
| const WorldTriMesh & | mesh ) |
Sweep an AABB against a triangle mesh using Voronoi-clipped per-triangle tests.
Returns the earliest contact whose closest feature on the hit triangle is an active Voronoi region (face interior or active edge / vertex). Contacts in inactive regions are discarded — the neighbour triangle whose active region actually owns that point will produce the correct face-normal contact instead.
For capsule shapes (Phase 5), pass halfExtents = (radius, radius + halfHeight, radius) — the resulting Minkowski hull is conservative but exact for axis-aligned face normals (the most common case for hand-authored maps). Truly diagonal triangle face normals (e.g. a 45° ramp triangle) produce a slight (sqrt(2)-1)*radius over-estimate of player size.
| HitResult physics::sweepAll | ( | CapsuleShape | capsule, |
| glm::vec3 | start, | ||
| glm::vec3 | end, | ||
| const WorldGeometry & | world ) |
Sweep a capsule against all world geometry, returning the earliest hit.
| HitResult physics::sweepAll | ( | glm::vec3 | halfExtents, |
| glm::vec3 | start, | ||
| glm::vec3 | end, | ||
| const WorldGeometry & | world ) |
Sweep an AABB against all world geometry, returning the earliest hit.
| HitResult physics::sweepCapsuleVsBox | ( | CapsuleShape | capsule, |
| glm::vec3 | start, | ||
| glm::vec3 | end, | ||
| const WorldAABB & | box ) |
Sweep a capsule against a static axis-aligned box. Conservative.
| HitResult physics::sweepCapsuleVsBrush | ( | CapsuleShape | capsule, |
| glm::vec3 | start, | ||
| glm::vec3 | end, | ||
| const WorldBrush & | brush ) |
Sweep a capsule against a convex brush. Exact (per-plane Minkowski extent).
| HitResult physics::sweepCapsuleVsCylinder | ( | CapsuleShape | capsule, |
| glm::vec3 | start, | ||
| glm::vec3 | end, | ||
| const WorldCylinder & | cyl ) |
Sweep a capsule against a vertical cylinder. Conservative.
| HitResult physics::sweepCapsuleVsPlanes | ( | CapsuleShape | capsule, |
| glm::vec3 | start, | ||
| glm::vec3 | end, | ||
| std::span< const Plane > | planes ) |
Sweep a capsule along [start, end] against a list of infinite planes.
| HitResult physics::sweepCapsuleVsSphere | ( | CapsuleShape | capsule, |
| glm::vec3 | start, | ||
| glm::vec3 | end, | ||
| const WorldSphere & | sph ) |
Sweep a capsule against a sphere. Conservative.
| HitResult physics::sweepCapsuleVsTriMesh | ( | CapsuleShape | capsule, |
| glm::vec3 | start, | ||
| glm::vec3 | end, | ||
| const WorldTriMesh & | mesh ) |
Sweep a capsule against a triangle mesh.
Uses capsule-axis vs bounded-triangle closest-point queries with conservative advancement. Finite face, edge, and vertex features block the capsule, and triangles are treated as two-sided thin surfaces by default.
|
inline |
The physics test playground.
Layout along the +Z axis (forward from spawn at origin):
z ~ 400 : Reference cube (64^3) z ~ 800 : Small steppable box (64x16x64) and large jumpable box (80x64x80) z ~ 1000 : Gentle ramp (15deg, left) and steep ramp (40deg, right) z ~ 1500 : Stairs (5 steps rising along +Z) z ~ 1900 : Axis-aligned wall, diagonal wall, pole z ~ 2100 : Elevated thin walkway
| void physics::updateSleep | ( | Registry & | registry, |
| const SleepConfig & | cfg ) |
Update each body's sleep state from its current velocities.
Called once per tick after the solver has converged.
| TriMeshValidationReport physics::validateTriMesh | ( | const WorldTriMesh & | mesh, |
| float | positionEpsilon = 1e-4f ) |
Validate authored collision mesh topology before/after cooking.
This does not mutate the mesh and only inspects vertices / indices, so it can run before BVH construction or after load. It catches the map pipeline issues that destabilize thin-surface KCC contacts: degenerate triangles, duplicated opposite-winding faces, non-manifold edges, and out-of-range indices.
| TriMeshValidationTotals physics::validateTriMeshes | ( | std::span< const WorldTriMesh > | meshes, |
| float | positionEpsilon ) |
Validate every triangle mesh in an authored collision set.
| void physics::wakeBody | ( | Registry & | registry, |
| entt::entity | e ) |
Wake a single body (e.g.
for an explicit force). Does NOT propagate through the contact graph; use wakeIslandOf for that.
| void physics::wakeIslandOf | ( | Registry & | registry, |
| const ContactCache & | cache, | ||
| entt::entity | e ) |
Wake every body that's currently in the same contact island as e.
Walks the contact graph in cache using BFS; O(island size).
| void physics::weldTriMesh | ( | WorldTriMesh & | mesh, |
| float | coplanarTolerance = 0.0349065850f ) |
Compute face normals + active edge / vertex flags for a triangle mesh.
Must be called AFTER buildTriMeshBVH() (it only depends on vertices and indices, but conventionally pairs with the BVH build). Populates the mesh's faceNormals, edgeActive, and vertActive arrays.
Algorithm. Each shared edge between two triangles is classified by dihedral angle:
| mesh | Triangle mesh to weld (modified in place). |
| coplanarTolerance | Dihedral angle (radians) below which an edge counts as flat. Default ~2° — matches Bullet's internal-edge utility and Jolt's MeshShape default. |
|
constexpr |
Air acceleration constant. Higher than Quake (0.7) for Titanfall-style air control.
|
constexpr |
Wish-speed FLOOR in air (units/s).
The wish-speed cap once horizontal speed exceeds k_airWishCurveTop. Preserves classic Quake strafe-jump physics at speed. Does NOT cap total speed — existing momentum is preserved.
|
constexpr |
Wish-speed CEILING in air (units/s) when stationary.
|
constexpr |
Power-curve exponent for wish-speed falloff (<1 = sharp early drop).
t' = pow(t, e).
|
constexpr |
Horizontal speed (u/s) at which the curve plateaus at k_airMaxSpeed.
|
constexpr |
Maximum radius of the emergency-unstick free-space search.
When per-pass depen fails to resolve penetration, we probe outward up to this far in cardinal directions for a clear teleport target.
|
constexpr |
Master toggle for Phase-C sub-stepping.
|
constexpr |
Upward teleport (units) at epicenter; lifts the victim past k_groundSnapDistance so the KCC won't re-anchor them this tick.
|
constexpr |
Minimum upward velocity (units/s) at epicenter.
Floored, not added — never reduces a stronger existing vertical knockback.
|
constexpr |
dot(surfaceNormal, up) threshold above which a surface counts as walkable floor.
Cos(45.6°) ≈ 0.7 — surfaces steeper than this are walls, not floors.
|
constexpr |
Ground friction coefficient. Higher = crisper stops, easier-to-track movement.
|
constexpr |
Downward acceleration (units/s^2) for projectiles / dynamics.
Real-world-ish scale for grenades and rigid bodies. The player uses k_playerGravity instead.
|
constexpr |
Minimum time between gravity flips (s).
|
constexpr |
Ground acceleration constant. Higher = reaches max speed faster.
|
constexpr |
Distance the ground probe extends below the capsule foot to snap to descending slopes / steps.
Allows a grounded player to follow stair-downs and slope-downs without going airborne for a tick.
|
inlineconstexpr |
Maximum hitscan distance in world units.
|
constexpr |
Initial upward velocity on jump (units/s).
Apex = k_jumpSpeed^2 / (2*k_playerGravity) ~ 54 units (~4.5 ft). Mirrored by tms::k_jumpSpeed.
|
inlineconstexpr |
Up to 4 points per body pair — enough for any flat-face contact (box-on-box, box-on-ground, etc.).
Curved-on-curved (sphere-sphere) uses 1 point. Capsule-on-flat uses 1–2 points.
|
constexpr |
Maximum sequential passes the deepest-first capsule depen attempts before falling through to emergency unstick.
|
constexpr |
Clamp on sub-step count to bound worst-case cost.
|
constexpr |
Floor overbounce — exactly 1.0 means no bounce.
|
constexpr |
Separation impulse for walls/ceilings; prevents corner-sticking.
|
inlineconstexpr |
Epsilon for parallel-ray checks.
|
constexpr |
Player-specific gravity (units/s^2).
Doubled vs. k_gravity so the player's apex height and air-time match what the previous (buggy) KCC integration produced — the older KCC double-integrated vertical motion per tick, so all jump-related velocities and the player's gravity are doubled here to preserve the established gameplay feel with the corrected single-integration KCC.
|
constexpr |
Maximum obstacle height auto-stepped over without jumping (units).
|
constexpr |
Friction is amplified below this speed for a crisp stop.
|
constexpr |
Sub-step when |v|·dt > min_shape_radius · this.