Skip to main content

Getting started

Nexus is a physics engine for simulating rigid-bodies and deformable materials with compute shaders. It is available in 3D, through the nexus3d module. This page shows how to set up a simple simulation with a ball falling on a fixed ground. The guide describes the APIs in the 0.7 source tree; an older installed release may expose different methods. The following pages separate rigid-body dynamics from MPM particles and materials, with simulation state and viewer covering the common workflow.

Installing Nexus with pip​

The Python package is named dimforge-nexus3d, whereas the module imported by your code is named nexus3d:

python -m pip install dimforge-nexus3d

The plain nexus3d package on PyPI is an unrelated project. Make sure to install dimforge-nexus3d. The bindings target CPython 3.9 or newer. If a wheel is not available for your platform, build the bindings from the Nexus repository after installing Cargo and the shader compiler:

cargo install cargo-gpu --version 0.10.0
cargo gpu install --auto-install-rust-toolchain
python -m venv .venv
source .venv/bin/activate
python -m pip install maturin
maturin develop --release -m crates/nexus_python3d/Cargo.toml

The activation command above is for a Unix shell. On Windows, activate .venv with the script in its Scripts directory.

note

Only the 3D engine is exposed to Python. The Python bindings do not expose every low-level Rust API. This guide indicates these differences where they matter.

Basic simulation example​

Here is a complete main.py file. The RigidBodyBuilder and ColliderBuilder describe the scene. The NexusState contains that scene, and the NexusPipeline advances it.

from nexus3d import (
NexusViewer, NexusPipeline, NexusState, RbdCoupling,
RigidBodyBuilder, ColliderBuilder, Vec3, Pose,
)


def main():
viewer = NexusViewer().with_running()
viewer.init_backend()
state = NexusState()
pipeline = NexusPipeline()

# Create the ground.
ground = RigidBodyBuilder.fixed().build()
collider = ColliderBuilder.cuboid(5.0, 0.1, 5.0).build()
handle = state.insert_rigid_body(ground, collider, RbdCoupling.NONE)
viewer.insert_shape(handle, collider.shared_shape(), Pose.IDENTITY)

# Create the falling ball.
ball = RigidBodyBuilder.dynamic().translation(Vec3(0.0, 3.0, 0.0)).build()
collider = ColliderBuilder.ball(0.5).build()
handle = state.insert_rigid_body(ball, collider, RbdCoupling.NONE)
viewer.insert_shape(handle, collider.shared_shape(), Pose.IDENTITY)

state.finalize(viewer)
viewer.add_directional_light(Vec3(1.0, -2.0, 3.0))
while viewer.render_frame():
if viewer.simulating():
pipeline.simulate(viewer, state)
viewer.sync(state)


if __name__ == "__main__":
main()

Run the example with python main.py. The NexusViewer opens a window, and viewer.with_running() starts the simulation immediately. The window's controls change the value returned by viewer.simulating(), which determines whether the loop calls pipeline.simulate.

info

Call viewer.init_backend() before state.finalize or pipeline.simulate. The three operations initialize the backend, upload the scene, and advance physics respectively. See simulation state and viewer.

Run NexusViewer on the main thread. A normal Python script is the recommended starting point.