Architecture¶
Each model has one implementation, bound to NumPy, Torch, or JAX through a shared runtime layer.
Names exported from body_models, model packages, and backend modules are
public. Underscore-prefixed modules are private and may change without a major
release.
Model packages¶
Each model lives in body_models/<name>/ and derives from SkinnedModel:
| File | Responsibility |
|---|---|
_io.py |
Find assets and load them as immutable NumPy data. |
_core.py |
Model mathematics, given an array namespace or runtime. |
_model.py |
Validation, state preparation, and forward methods. |
numpy.py, torch.py, jax.py |
Bind the model to an array backend. |
__init__.py |
Export model-specific types and helpers. |
forward_vertices() runs in stages. Identity preparation computes rest vertices
and joints; pose preparation computes transforms and corrective coefficients;
apply_pose_correctives() turns those coefficients into offsets; skinning
produces the posed mesh. forward_points() runs the same stages through a
vertex mapping. Skeleton forwards have their own preparation path.
parameter_spec lists parameters in identity, pose, transform order, each with
its unbatched dimensions, role, default, and rotation representation.
get_rest_pose() builds its defaults from this mapping; models override it to
add named presets such as relaxed hands.
Required numerical inputs may be positional. Optional arguments are keyword-only, in this order: local pose options, identity, global transform, output selection.
Linear blendshape models¶
SMPL, SMPL-H, SMPL-X, MANO, FLAME, and GNM share a private engine. Each model defines its pose blocks (joint order and means); the engine handles rotation conversion, root insertion, batch validation, forward kinematics, bind-relative transforms, and corrective coefficients. It sees only arrays and pose blocks, never model names or feature flags.
These models also share identity preparation. Shape and expression bases are applied separately, which avoids concatenating them on every call.
Runtimes¶
ArrayRuntime owns the array namespace, device- and dtype-aware construction,
state materialization, and the shared operations. Model properties expose
meshes, skeletons, and deformation bases; runtime-specific arrays stay private.
Backend imports select the runtime; create_model() selects it by name. Core
functions that dispatch shared operations receive the runtime, and pure
numerical helpers receive only its array namespace. Models build local
transforms; the runtime composes the kinematic tree and skins.
Backend-specific data, such as Torch/Warp gradient plans for compact skinning weights or prepared sparse corrective bases, is built once during materialization. A selected kernel either runs or raises; it never silently falls back to another backend.
Torch. Models are torch.nn.Modules with their source arrays as persistent
buffers, so checkpoints are complete but can be large. Derived plans move with
the model and are rebuilt, not serialized.
JAX. Models are pytrees. Dataclass metadata is static, arrays are children, and reconstruction preserves model and runtime configuration.
Shared operations¶
| Module | Responsibility |
|---|---|
_common.skinning |
Dense and compact skinning, bind-relative transforms, global transforms. |
_common.deformation |
Linear blend shapes and dense or sparse corrective bases. |
_common.kinematics |
Affine transforms, rigid inversion, parent-relative offsets, forward kinematics. |
Shared operations know nothing about model names, pose layouts, or asset formats. SOMA and MHR, for example, compute corrective coefficients locally and use the shared basis only to turn them into offsets.
Adding a model¶
- Load and validate assets in
_io.py. - Implement the mathematics in
_core.py. - Define the
SkinnedModelsubclass in_model.py. - Bind and export the NumPy, Torch, and JAX classes.
- Register the factory and asset metadata in
_catalog.py. - Test cross-runtime agreement, batching, compilation, gradients, and reference outputs.
Share code only when its meaning, inputs, outputs, batching, and gradients agree across callers; otherwise keep it in the model.