Skip to content

IPC Contact

Overview

NovaPhy integrates libuipc to provide GPU-accelerated Incremental Potential Contact (IPC) with mathematically guaranteed penetration-free contact.

Optional Feature

IPC is built from the external/libuipc submodule and must be enabled with NOVAPHY_WITH_IPC=ON. Select the GPU path with NOVAPHY_GPU_PLATFORM=NVIDIA or NOVAPHY_GPU_PLATFORM=COREX.

How It Works

The IPC pipeline:

  1. Shape Conversion — NovaPhy shapes are converted to tetrahedral meshes
  2. GPU Newton Solver — libuipc solves the barrier-based contact problem on GPU
  3. Barrier Contact — Log-barrier potential guarantees no interpenetration

Build with IPC

# NVIDIA CUDA path
CMAKE_ARGS="-DNOVAPHY_WITH_IPC=ON -DNOVAPHY_GPU_PLATFORM=NVIDIA" pip install -e .

# NVIDIA RTX 50-series / compute_120 path
CMAKE_ARGS="-DNOVAPHY_WITH_IPC=ON -DNOVAPHY_GPU_PLATFORM=NVIDIA -DCMAKE_CUDA_COMPILER=/usr/local/cuda-12.8/bin/nvcc" pip install -e .

# CoreX compatibility path
CMAKE_ARGS="-DNOVAPHY_WITH_IPC=ON -DNOVAPHY_GPU_PLATFORM=COREX" pip install -e .

Usage

SolverIPC is a Newton-aligned SolverBase adapter; drive it through the standard solver.step(...) contract. dt and gravity are validated against the libuipc scene built at construction:

import novaphy

if novaphy.has_ipc():
    builder = novaphy.ModelBuilder()
    # ... add bodies and shapes ...
    model = builder.finalize()

    config = novaphy.solvers.SolverIPC.Config()
    config.dt = 1.0 / 60.0

    solver   = novaphy.solvers.SolverIPC(model, config)
    state    = model.state()
    control  = model.control()
    contacts = novaphy.CollisionPipeline(model).contacts()
    for _ in range(100):
        solver.step(state, state, control, contacts, config.dt)

novaphy.solvers.SolverIPC is the public IPC entry point. libuipc's scene/world/engine are kept as private solver implementation details. The contacts argument is accepted to preserve the shared SolverBase call shape; libuipc performs IPC collision detection and contact solving internally and does not consume NovaPhy's CollisionPipeline output yet.

The current adapter supports rigid free bodies with plane, box, sphere, cylinder, convex hull, triangle mesh, and heightfield shapes. Box, sphere, cylinder, and convex hull shapes are converted to libuipc affine-body tetrahedral meshes. Triangle mesh and heightfield shapes are mapped as codimensional libuipc shell affine bodies; tune their half-thickness with IPCConfig.shell_thickness or a positive per-shape margin. Multiple shell shapes can share one body and are merged into one libuipc shell object; a body cannot mix shell and volumetric IPC shapes yet. SdfGrid shapes remain unsupported for IPC and should be converted to a triangle mesh or heightfield first.

NovaPhy shape flags, collision groups, disabled collision pairs, per-shape friction, and free-body kinematic flags are mirrored into libuipc's contact element table and affine-body external-kinetic attributes. Articulated joints, particles/deformables, multi-world batching, SDF grids, and mixed shell plus volumetric bodies are rejected with clear errors until those mappings are implemented.

When to Use IPC

Scenario Recommended Solver
Real-time simulation SolverSemiImplicit / SolverFeatherstone
Guaranteed no-penetration SolverIPC
Deformable objects (future) SolverIPC
Large-scale contact SolverIPC

Demo

python python/demos/demo_ipc_stack.py

Requirements

  • NVIDIA CUDA path: CUDA 12.4+.
  • NVIDIA RTX 50-series / compute_120: CUDA 12.8+ and an explicit CMAKE_CUDA_COMPILER, for example /usr/local/cuda-12.8/bin/nvcc, if the system default nvcc is older.
  • CoreX path: CoreX CUDA compatibility toolchain and ivcore11 architecture.
  • Compatible C++ compiler (see Build Documentation)
  • The libuipc submodule is initialized at external/libuipc.