Shapes
Shapes are immutable, reusable geometry registered with the process Context. Public APIs represent a registered shape with a ShapeHandle; there is no public polymorphic Shape object to manage.
A handle belongs to the Context that created it. The same shape can be shared by actors in multiple scenes owned by that context. Shape-local geometry, including any transform baked while loading, is independent of each actor's world placement.
Geometry Types
The table identifies each shape's primary geometry. A registered shape may also carry reusable auxiliary data, such as a triangular visual mesh, simulation metadata, and precomputed data used for contact queries. These remain part of the same shape and do not create additional ShapeHandles.
| Geometry | Primary representation | Compatible actors | Creation |
|---|---|---|---|
| Tetrahedral mesh | Four node indices per volume element. | Rigid, articulated link, and soft. | CreateTetMeshShape / create_tet_mesh_shape, or generic mesh creation with nodesPerElement / nodes_per_element set to 4. |
| Triangle mesh | Three node indices per surface element. | Rigid, articulated link, and shell. | CreateTriMeshShape / create_tri_mesh_shape, or generic mesh creation with nodesPerElement / nodes_per_element set to 3. |
| Polyline mesh | Two node indices per line element. | Rod. | CreateMeshShape / create_mesh_shape with nodesPerElement / nodes_per_element set to 2. |
| Sphere | Analytic center and radius. | Rigid and articulated link. | CreateSphereShape / create_sphere_shape. |
| Plane | Analytic infinite plane. | Rigid and articulated link. | CreatePlaneShape / create_plane_shape. |
ModelData.box can be registered as an oriented-box shape, but no actor factory currently accepts that shape type.
The public actor-creation API assembles articulated actors from ordinary shape handles assigned to individual links; there is no separate articulated-shape factory. See Articulated Actors for construction and introspection.
Model Data
ModelData is a caller-owned, serializable description used to construct one registered shape. It must provide one primary geometry: mesh, box, plane, or sphere.
A mesh-backed model can include auxiliary visual, simulation, and material data, as well as a precomputed grid of signed-distance function (SDF) evaluations used for contact queries. Not every primary geometry supports every auxiliary data type.
While Shapes can carry data used for contact, actors and articulated links separately select whether and how they act as colliders. See Collider Representations for those configuration options.
CreateModelShape / create_model_shape copies a ModelData value into the Context and returns one ShapeHandle. The source model data remains independent and can be edited or serialized without changing the registered shape.
Model-data loading supports SuperDex Physics JSON (.mochi.json), SuperDex Physics HDF5 (.mochi.h5), OBJ (.obj), OFF (.off), PLY (.ply), and STL (.stl). Saving writes SuperDex Physics JSON or HDF5.
| Operation | C++ / Python |
|---|---|
| Load model data | model_utils::LoadFromFile / physics.model.load_from_file |
| Save model data | model_utils::SaveToFile / physics.model.save_to_file |
| Register as a shape | CreateModelShape / create_model_shape |
Creating Shapes
Analytic Shapes
Use dedicated constructors for spheres and planes.
- C++
- Python
ShapeHandle sphereShape = context->CreateSphereShape(
Real3{0_r, 0_r, 0_r}, 0.2_r, error);
ShapeHandle planeShape = context->CreatePlaneShape(
Real3{0_r, 1_r, 0_r}, 0_r, error);
sphere_shape = mochi.create_sphere_shape(center=[0, 0, 0], radius=0.2)
plane_shape = mochi.create_plane_shape(normal=[0, 1, 0], distance=0)
Mesh Shapes
Mesh coordinates are flat XYZ values in meters, so their length is three times the number of nodes. Connectivity is a flat array of node indices whose length is a multiple of the nodes per element.
For polylines, connectivity is either empty (an open chain) or the sequential segments [0, 1], [1, 2], ..., optionally closed by [n - 1, 0]. In C++, experimental::CreatePolylineShape generates this connectivity from an isClosedLoop flag and accepts per-element frame axes; if the axes are empty, it generates a discrete Bishop frame using parallel transport.
Dedicated helpers cover tetrahedral and triangle meshes:
- C++
- Python
ShapeHandle tetShape =
context->CreateTetMeshShape(tetCoordinates, tetConnectivity, error);
ShapeHandle triShape =
context->CreateTriMeshShape(triCoordinates, triConnectivity, error);
tet_shape = mochi.create_tet_mesh_shape(tet_coordinates, tet_connectivity)
tri_shape = mochi.create_tri_mesh_shape(tri_coordinates, tri_connectivity)
Use MeshData for the stable generic path. Set nodesPerElement / nodes_per_element to 2 for a polyline, 3 for triangles, or 4 for tetrahedra. SuperDex Physics copies the supplied data when the shape is created.
- C++
- Python
MeshData polyline;
polyline.nodesPerElement = 2;
polyline.coordinates = {
0_r, 0_r, 0_r,
1_r, 0_r, 0_r,
1_r, 1_r, 0_r,
};
polyline.connectivity = {0, 1, 1, 2};
ShapeHandle polylineShape = context->CreateMeshShape(polyline, error);
polyline = mochi.MeshData(
nodes_per_element=2,
coordinates=[0, 0, 0, 1, 0, 0, 1, 1, 0],
connectivity=[0, 1, 1, 2],
)
polyline_shape = mochi.create_mesh_shape(polyline)
Loading from Files
LoadShapeFromFile / load_shape_from_file imports any of the supported model-data formats directly into the Context and returns a ShapeHandle.
- C++
- Python
ShapeHandle shape =
context->LoadShapeFromFile("models/part.obj", error);
ShapeHandle bakedShape = context->LoadShapeFromFile(
"models/part.mochi.h5",
Real3{0.5_r, 0.5_r, 0.5_r},
TransformRT::Identity(),
error);
shape = mochi.load_shape_from_file("models/part.obj")
baked_shape = mochi.load_shape_from_file(
"models/part.mochi.h5",
bake_scale=[0.5, 0.5, 0.5],
bake_transform=mochi.TransformRT(),
)
bakeScale / bake_scale and bakeTransform / bake_transform permanently modify the shape-local data during loading. They do not place an actor in the world; use the actor's world transform for placement. Unsupported non-uniform scales are rejected for shape data that cannot represent them.
Inspecting Shape Data
The context exposes the registered data without requiring a public shape object:
| C++ / Python | Result |
|---|---|
GetShapeMesh / get_shape_mesh | The main authored mesh: tetrahedral, triangle, or polyline. The view is empty for implicit geometry such as spheres and planes. |
GetShapeSurfaceMesh / get_shape_surface_mesh | A compact triangle surface for tetrahedral and triangle shapes. Its connectivity indexes the coordinates returned in the same view. |
GetShapeVisualMesh / get_shape_visual_mesh | An optional rendering mesh, including linear skinning data when available. |
GetShapeAabb / get_shape_aabb | The shape's axis-aligned bounds in shape-local coordinates. |
The mesh APIs return non-owning MeshDataView values. A view remains valid only while its corresponding registered shape handle remains valid; copy it into owning MeshData if it must outlive that handle.
Assigning Shapes to Actors
Pass a ShapeHandle in the actor creation parameters. One registered shape can be reused for many actors, and each actor can have a different world transform.
- C++
- Python
RigidActorParams params;
params.shape = sphereShape;
params.worldFromLocal = TransformRT{Real3{0_r, 1_r, 0_r}};
Actor* actor = scene->CreateRigidActor(params, error);
actor = scene.create_rigid_actor(
shape=sphere_shape,
world_from_local=mochi.TransformRT(translation=[0, 1, 0]),
)
Lifetime and Caching
The recommended lifecycle is:
- Create or load a shape.
- Pass its handle into actor creation parameters.
- Let C++ or Python clean up the handle automatically when the last copy is destroyed.
An actor independently retains the underlying shape data. Cleaning up the caller's handle therefore does not invalidate an actor that was already created with it.
ReleaseShape / release_shape is available for optional eager release. Calling it explicitly invalidates the registered handle value, including other copies of that same value, so do not use those copies afterward.
File Cache
The shape file cache is disabled by default and applies only to LoadShapeFromFile / load_shape_from_file. Enable it with EnableFileCache(true) / enable_file_cache(True) when repeatedly loading the same assets.
Cache entries are keyed by the exact file path and baked scale/transform parameters. A cached entry retains the underlying shape data after its handles are released. ClearFileCache / clear_file_cache removes every entry, while ClearFileFromCache / clear_file_from_cache removes all baked variants for one exact path. LoadShapeFromBytes / load_shape_from_bytes does not use this cache.