Skip to content

Architecture

Core Pipeline

NovaPhy follows a three-stage pipeline:

graph LR
    A[ModelBuilder<br/>mutable] --> B[Model<br/>immutable]
    B --> C[World<br/>simulation]
    C --> D[step dt]
    D --> C
  1. ModelBuilder — Mutable scene description. Add bodies, shapes, joints, articulations.
  2. Model — Immutable, baked data. Created by builder.build(). Can be shared across multiple worlds.
  3. World — Simulation state and stepping. Owns the solver, manages contacts and integration.

World Variants

World Solver(s) Use Case
World SolverSemiImplicit, SolverFeatherstone, SolverXPBD Standard rigid body simulation
FluidWorld PBFSolver + Akinci Fluid and rigid-fluid coupling
IPCWorld libuipc GPU Newton Penetration-free contact (CUDA)
VBDWorld VbdSolver (CPU/CUDA) AVBD primal-dual

Solver Pipelines

Free Bodies (SolverSemiImplicit)

graph LR
    A[Broadphase<br/>SAP] --> B[Narrowphase]
    B --> C[Sequential Impulse<br/>PGS]
    C --> D[Integrate]
  • Sweep and Prune broadphase filters candidate pairs
  • Narrowphase generates contact points with normals and penetration depths
  • Sequential Impulse solver resolves contacts with warm starting and Coulomb friction
  • Semi-implicit Euler integration updates positions and velocities

Articulated Bodies (SolverFeatherstone)

graph LR
    A[FK] --> B[RNEA<br/>bias forces]
    B --> C[CRBA<br/>mass matrix]
    C --> D[Cholesky<br/>solve]
    D --> E[Integrate]
  • Forward Kinematics computes body transforms from joint coordinates
  • RNEA computes bias forces (Coriolis, centrifugal, gravity)
  • CRBA computes the joint-space mass matrix
  • Cholesky factorization solves for joint accelerations
  • Semi-implicit Euler integrates joint coordinates

PBF Fluids

graph LR
    A[Predict] --> B[Neighbor Search<br/>spatial hash]
    B --> C[Density Constraint<br/>iterative]
    C --> D[XSPH + Vorticity]
    D --> E[Update]

Collision System

Broadphase

Multiple broadphase implementations behind the IBroadphase interface:

  • SweepAndPrune — Default, O(n log n) sort-based
  • BVH — Bounding Volume Hierarchy tree
  • AllPairs — Brute-force O(n^2), for testing

Narrowphase

Dispatches to specialized collision pair algorithms:

  • Sphere-Sphere, Sphere-Plane, Sphere-Box
  • Box-Plane, Box-Box (SAT)
  • GJK/EPA for general convex shapes
  • Cylinder collision pairs

Contact Convention

  • Normal direction: body_a → body_b (positive impulse separates)
  • Plane shapes use body_index = -1 (world-owned, always static)

Data Types

NovaPhy uses float32 exclusively — never double.

Type Definition
Scalar float
Vec3f Eigen::Vector3f
Mat3f Eigen::Matrix3f
Quatf Eigen::Quaternionf
VecXf Eigen::VectorXf
MatXf Eigen::MatrixXf

Spatial algebra uses the Featherstone convention: [angular; linear] for 6D vectors.

File Organization

NovaPhy/
├── include/novaphy/
│   ├── math/           # Vec3f, Mat3f, Quatf, spatial algebra
│   ├── core/           # Body, Shape, Joint, Model, ModelBuilder, Contact
│   ├── collision/      # SAP, BVH, Narrowphase, GJK/EPA
│   ├── dynamics/       # SolverBase, integrator
│   │   ├── semi_implicit/   # SolverSemiImplicit
│   │   ├── featherstone/    # SolverFeatherstone, FK, RNEA, CRBA
│   │   ├── xpbd/           # SolverXPBD
│   │   ├── vbd/            # VBDWorld, VbdSolver
│   │   └── ipc/            # IPCWorld, IPCConfig
│   ├── fluid/          # PBF, SPH kernels, Akinci boundary
│   ├── io/             # URDF, OpenUSD, scene builder
│   └── sim/            # World, SimState, PerformanceMonitor
├── src/                # C++ implementations (mirrors include/)
├── python/
│   ├── novaphy/        # Python package
│   └── bindings/       # pybind11 binding files
├── tests/
│   ├── python/         # pytest files
│   └── cpp/            # C++ unit tests
└── demos/              # Polyscope demo scripts