ground-up 2D/3D rewrite with GLM, C++20, GJK+EPA, dynamic BVH, GLFW/OpenGL - #16
Open
IanRPage wants to merge 6 commits into
Open
ground-up 2D/3D rewrite with GLM, C++20, GJK+EPA, dynamic BVH, GLFW/OpenGL#16IanRPage wants to merge 6 commits into
IanRPage wants to merge 6 commits into
Conversation
remove SFML, add GLM, remove old sources, general cleanup
* finalize Types.hpp w matrix_transform header * add Transform struct w point/direction/inverse/compose operations * add quaternion integration and nlerp for rotation * add 2D constraint "seam" for position and velocity * addressing code rabbit comments - use linear interpolation for `nlerp` in Rotation.cpp - derive expected midpoint from corrected endpoint in test_rotation.cpp - test `compose` directly in test_transform.cpp
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Team Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
* add collision shapes with support/inertia/AABB formulas
adds SphereShape, BoxShape, CapsuleShape, and ConvexHullShape, each
owning its own support(), boundingRadius(), localInertiaTensor() &
localAABB()
- ShapeVariant + worldSupport()/worldAABB() free functions. later,
GJK/EPA will take these in
- MassProperties + computeMassProperties()
- math/Constants.hpp for VECTOR_LENGTH_EPSILON and PI. for future shared
constants so there's no magic numbers anywhere
- test_shapes.cpp, test_world_support.cpp, test_mass_properties.cpp
* fix CodeRabbit findings in shape support/inertia and mass-property guards
- CapsuleShape::support normalized only XZ radial projection instead of
full direction. a capsule's support point is segment.support(d)
+ sphere.support(d), and sphere term needs full 3D direction
normalized (confirmed via Minkowski-sum reasoning)
- CapsuleShape::localInertiaTensor's cap parallel-axis coefficient was
3/8, but correct value is 3/4. confirmed by integration via thin-disk
decomposition over the hemisphere caps
- ConvexHullShape::localInertiaTensor set Ixx = Iyy = Izz/2, which only
holds for X/Y-symmetric shapes
- ConvexHullShape's constructor accepted zero vertices, which
support()/localAABB() then index/dereference unconditionally (UB). now
throws std::invalid_argument
- MassProperties::invertDiagonal only guarded isStatic/mass<=0 case, but
degenerate ConvexHullShape (near-zero area) w positive mass produced
zero inertia diagonal that then divided by zero, and thus to +inf. now
guards each diagonal entry individually.
updated test_shapes.cpp's hand-derived reference values to match the
corrected formulas, added regression tests for each fix
* delete QuadTree from code that uses it, and apply clang-format * committing more clang formatted files * broadphase: add PairCache for incremental candidate-pair tracking add persistent candidate-pair tracking that only requeries tree for bodies whose moveProxy() call ACTUALLY mutated their leaf. fully rechecks pass to drop pairs that stopped overlapping * broadphase: add persistent dynamic BVH add fattened-leaf AABB tree: cost-based sibling insertion, AVL rebalancing, and moveProxy()'s no-op fast path for in-margin moves * core: add BodyHandle and a minimal BodyStore added stable body handle & slot-map that later broadphase code will need to reference bodies by AABB + displacement * broadphase: IBroadphase & Naive/Grid/DynamicBVH implementations add debug-layer and its three impls: brute-force port of old naiveBroadphase, 3D port of SpatialGrid, and DynamicBVH-backed default NOTE: selection between these meant to happen once on a cold ImGui path * deprecate/reture QuadTree remove QuadTree now that DynamicBVH succeeds it. it used to be that every particle was reinserted on every solver iteration, not once per step * update core and test CMakeLists.txt * format test_world_support.cpp * fix two conservative overlap bugs mentioned from review PairCache::update() checked its new-pair dedup set before purging stale entries, so a DynamicBVH node id that's freed and reused for a different body within the same step **could** have its new overlap silently swallowed by a leftover key. reordered it so stale entries purged first, then discover GridBroadphase scanned each body's neighborhood using only its own radius, so a small body could miss a large center-distant body whose AABB reached it. scans now expand by the grid's largest body radius
* collision: add dimension-agnostic GJK overlap test implements gjkOverlap/SupportPoint/minkowskiSupport. line/triangle/tetrahedron simplex reduction handles 2D and 3D uniformly w no shape-specific branching. GjkResult::simplex carries each point's originating A-side/B-side support since EPA's contact recovery needs that provenance. also includes fixes for exact-tie floating-point cases that surface readily on axis-aligned test geometry * collision: add EPA penetration depth and normal recovery expands GJK's terminal simplex into a polytope and returns penetration depth, world-space normal, and contact points on each shape. branches on GJK's simplex size (3 -> 2D edge-insertion polygon, 4 -> 3D face-expansion polytope) rather than a body-level 2D flag, since a coplanar Z=0 simplex can never form a 3D tetrahedron * collision: generate multi-point manifolds via face/edge clipping adds Manifold/ManifoldPoint and buildManifold, turning EPA's single deepest point into a stable multi-point contact via Sutherland-Hodgman clipping. spheres and other 3D non-box pairs fall back to EPA's single point * collision: add persistent ManifoldCache with warm-start point matching per body pair manifold storage backed by a flat, index-addressed vector instead of per pair heap allocs. updateManifold carries normalImpulse/tangentImpulse forward across frames by matching points on current frame world anchor proximity * test: port double-dispatcher SAT narrowphase scenarios as GJK/EPA regression * update all CMakeLists.txt * address code rabbit review comments
* core: extend BodyStore with full per-body dynamics state BodyStore held only AABB/displacement for broadphase. added position/orientation, velocities, invMass, invInertiaBody, friction/restitution, and 2D-constraint flag via new BodyDesc constructor that derives initial AABB from shape+transform. kept AABB-only overload for defaulting to a static body * dynamics: add semi-implicit Euler integrator integrateVelocity/integratePosition apply gravity and advance position/orientation for non-static bodies, then apply2DConstraint where flagged. they're behind a small IIntegrator seam so future ntegrators are a new class, not a full-blown call site rewrite * dynamics: add tangent-basis construction for friction computeTangentBasis builds orthonormal basis from a contact normal for Coulomb friction, using the standard two-branch construction to avoid near-parallel degeneracy. also added INV_SQRT_3 to math/Constants.hpp so we don't have magic numbers all over * dynamics: add warm-started velocity/position solver with friction warmStart seeds velocities from cached impulses. solveVelocity resolves normal impulse plus box-clamped friction. solvePosition applies NGS-style correction from penetration recomputed off current transforms. everything reads from Manifold/BodyStore state, so no rederivation from raw positions also adds prepareRestitutionBias. restitution target needs to be sampled once from pre warm-start relative velocity and held fixed across iterations (recomputing it fresh each iteration makes impulse oscillate and decay instead of converging) * core: add World, wiring broadphase/narrowphase/solver into one step() World owns BodyStore, IBroadphase, ManifoldCache, SolverConfig, and implements world step. step() runs broadphase and GJK/EPA/manifold-update once, then iterates solveVelocity/solvePosition. Broadphase and GJK/EPA are swappable via setBroadphase/setNarrowphaseFns addWorldBoundaries replaces old applyWall logic w thin static BoxShape bodies at world bounds, going through same step() pipeline as other bodies * update all CMakeLists.txts with added files * add .clang-format to enforce codestyle * apply formatting to all code * address code rabbit review findings - BodyStore::allocateSlot: fully reset a recycled slot. it was leaking linearVelocity/angularVelocity from a removed body into whatever new body reuses its index - Solver::solvePosition: fix reversed penetration sign (worldAnchorA - worldAnchorB, not B - A). currentPenetration was always negative for real overlaps, making position correction a silent no-op - Integrator::integratePosition: apply2DConstraint before integrateOrientation, not after. out-of-plane angular velocity can't get baked into orientation first - World: normalize a null broadphase to the default DynamicBVHBroadphase and ignore empty narrowphase callbacks. step() is noexcept and calls both unconditionally
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
From-scratch rewrite of RPEngine's core, replacing SFML with GLFW/OpenGL, adding genuine 3D support alongside first-class 2D, and fixing three root-cause bugs from the current architecture in the process rather than patching around them:
Some key architectural decisions
Vec2f/Vec3f,Quatf,Mat3f/Mat4f) for generic linear algebra only — GJK, EPA, the BVH, the solver, and mass-property formulas stay hand-written.Shapeconcept oversupport/localInertiaTensor/boundingRadius) andstd::span.Vec3f+Quatftransform for every body, 2D or 3D — "2D mode" is a constraint applied via a free-function seam, not baked intoBody/solver/BVH.Bodyis the only place a transform lives. Collider and Renderable take it as a parameter on every call — nothing caches a second copy that can go stale.std::variant-based shapes, each implementing its ownsupport(),boundingRadius(),localInertiaTensor(),localAABB()— no shared cross-shape formula, ever. One GJK+EPA implementation replaces the pairwise SAT dispatch matrix entirely.const Manifold&— no code path re-derives geometry from raw positions.Claude helped write this