soma.io#

The soma.io module provides the file-format boundary for the library.

The main responsibilities are:

  • USD mesh and skeleton import/export

  • SOMA NPZ save/load helpers

  • convenience export helpers built around SOMALayer

I/O helpers for SOMA: NPZ animation files and USD mesh/skeleton I/O.

An .npz file contains everything needed to replay an animation with SOMALayer: identity model type, identity coefficients, poses, root translation, and metadata describing the representation.

class soma.io.UVPrimvarEntry#

Bases: dict[str, Any]

Serialized UV primvar data returned by load_usd_mesh.

Behaves like a dict for backwards compatibility (entry["coordinates"]) while also supporting attribute access (entry.coordinates).

class soma.io.SOMANPZData#

Bases: dict[str, Any]

Dictionary returned by load_soma_npz.

Behaves like a dict for backwards compatibility (data["poses"]) while also supporting attribute access (data.poses). Optional fields (scale_params, joint_orient, global_scale, hand_type) are present only if they were saved.

class soma.io.RigUSDData#

Bases: dict[str, Any]

Dictionary returned by load_rig_from_usd.

Behaves like a dict for backwards compatibility (rig["joint_names"]) while also supporting attribute access (rig.joint_names). Mesh-related fields (face_vert_indices, face_vert_counts, uv_data) are present only when the body skin mesh carries polygon/UV data.

soma.io.list_usd_meshes(usd_file_path)#

Return prim paths of all Mesh prims in a USD file.

Parameters:

usd_file_path (str | Path) – Path to the USD file.

Returns:

list of prim path strings.

Return type:

list[str]

soma.io.load_usd_mesh(usd_file_path, mesh_name)#

Load a mesh from a USD file.

Parameters:
  • usd_file_path (str | Path) – Path to the USD file.

  • mesh_name (str) – Prim path of the mesh (e.g. "/Root/Mesh"). A leading / is added if missing.

Returns:

(vertices, face_vert_indices, face_vert_counts, uv_data) where

  • vertices: (V, 3) float32

  • face_vert_indices: (sum(counts),) int32 — flattened

  • face_vert_counts: (F,) int32 — verts-per-face

  • uv_data: {name: {"coordinates": (M,2), "indices": ..., "interpolation": str}}

Return type:

tuple[ndarray, ndarray, ndarray, dict[str, UVPrimvarEntry]]

soma.io.write_usd_mesh(
usd_file_path,
mesh_name,
vertices,
face_vert_indices,
face_vert_counts,
uv_data=None,
)#

Write a mesh to a new USD file.

Parameters:
  • usd_file_path (str | Path) – Output path.

  • mesh_name (str) – Prim path for the mesh.

  • vertices (ndarray) – (V, 3) vertex positions.

  • face_vert_indices (ndarray) – Flattened face-vertex indices.

  • face_vert_counts (ndarray) – Verts-per-face array.

  • uv_data (dict | None) – Optional UV sets (same format as load_usd_mesh output).

soma.io.fan_triangulate(face_vert_indices, face_vert_counts)#

Convert a polygon soup to triangles via fan triangulation.

Parameters:
  • face_vert_indices (ndarray) – Flattened face-vertex indices.

  • face_vert_counts (ndarray) – Verts-per-face array.

Returns:

(F_tri, 3) int32 triangle array.

Return type:

ndarray

soma.io.load_usd_skeleton(usd_file_path)#

Extract skeleton from a USD file.

Parameters:

usd_file_path (str | Path) – Path to the USD file.

Returns:

Tuple (joint_paths, bind_transforms, parent_ids). joint_paths is the list of J joint path strings (for example "Root/Hips"), bind_transforms is a (J, 4, 4) float32 array of world-space bind transforms in USD row-major convention (point * M), and parent_ids contains the J parent indices with -1 for the root.

Return type:

tuple[list[str], ndarray, list[int]]

soma.io.load_usd_animation(usd_file_path)#

Extract SkelAnimation rotations and translations from a USD file.

Parameters:

usd_file_path (str | Path) – Path to the USD file.

Returns:

(rot_mats, translations) where

  • rot_mats: (J, 3, 3) float32 — local rotation matrices

  • translations: (J, 3) float32 — local translations

Returns None if no SkelAnimation is found.

Return type:

tuple[ndarray, ndarray] | None

soma.io.load_usd_skinning(usd_file_path, mesh_prim_path=None)#

Extract skinning weights from a skinned mesh in a USD file.

The mesh binding may define its own joint order (a subset of the skeleton joints). The returned weight matrix is indexed by the skeleton joint order so it aligns with load_usd_skeleton.

Parameters:
  • usd_file_path (str | Path) – Path to the USD file.

  • mesh_prim_path (str | None) – Prim path of the mesh to read skinning from. If None, the first Mesh prim in the file is used.

Returns:

(skinning_weights, num_joints) where

  • skinning_weights: (V, J_skel) float32 dense weight matrix

  • num_joints: number of skeleton joints

Return type:

tuple[ndarray, int]

soma.io.missing_soma_neutral_rig_keys(data)#

Return rig keys absent from a loaded SOMA_neutral.npz mapping.

soma.io.find_lod_skin_mesh_name(usd_path, lod)#

Find the skinned mesh leaf name for a body LOD in a UsdSkel asset.

The nvHuman publishes use naming conventions such as c_skin_xlo or c_bodyRig_xlo. This helper keeps the runtime tolerant to small naming differences while still requiring a skinned mesh, not just any mesh whose name contains the LOD token.

soma.io.load_lod_rig_from_usd(usd_path, lod, *, skin_mesh_name=None)#

Load rig data for a specific body LOD from a UsdSkel USD file.

soma.io.load_lod_rigs_from_usd(usd_path, lods, *, skin_mesh_names=None)#

Load multiple LOD rigs from one UsdSkel USD file with a shared stage.

soma.io.load_rig_from_usd(usd_path, *, skin_mesh_name=None)#

Load SOMA template rig data from a UsdSkel USD file.

Extracts the joint hierarchy, bind/T-pose transforms, bind-shape vertex positions, and skinning weights from the USD skeleton. Returns the rig-related keys that used to be stored in SOMA_neutral.npz so they can be merged with the slim core asset when initializing SOMALayer.

Shape PCA data (mean, shapedirs, eigenvalues) and mesh topology (triangles, triangles_low, LOD maps, facial segments) are not included; they must still be loaded from SOMA_neutral.npz.

Parameters:
  • usd_path (str | Path) – Path to the .usda, .usdc, or .usd template rig.

  • skin_mesh_name (str | None) – Name of the UsdGeomMesh prim holding the body skin (leaf path component, not full path). If None (the default), look for DEFAULT_SKIN_MESH_NAME first, and fall back to the first UsdGeomMesh descendant of any UsdSkelRoot. Pass an explicit name to pin the search.

Returns:

Dictionary with rig keys supplied by SOMA_template_rig.usdajoint_names, joint_parent_ids, bind_pose_world, bind_pose_local, t_pose_world, t_pose_local, bind_shape, skinning_weights_data, skinning_weights_indices, skinning_weights_indptr, and skinning_weights_shape. When the body skin mesh carries polygon or UV data, the result also includes face_vert_indices, face_vert_counts, and uv_data for save_soma_usd.

Raises:
  • FileNotFoundError – if the USD file does not exist.

  • RuntimeError – if the file cannot be opened, has no UsdSkelSkeleton, has no bindTransforms, has joint/ transform count mismatches, or has malformed skinning primvars.

  • ValueError – if the skin mesh cannot be located under skin_mesh_name (or the auto-discovery fallback), or has no points.

Return type:

RigUSDData

soma.io.add_npz_args(parser)#

Add common NPZ output arguments to an argparse parser.

soma.io.load_soma_npz(path)#

Load a SOMA animation .npz saved by save_soma_npz.

Returns a dict with the following keys:

  • poses: (N, J, 3) rotvec or (N, J, 3, 3) matrices.

  • transl: (N, 3) root translation.

  • joint_names: list of J joint name strings.

  • identity_model_type: e.g. "mhr", "smpl".

  • identity_coeffs: (N, C) or (1, C).

  • rotation_repr: "rotvec" or "matrix".

  • absolute_pose: bool — True if poses are absolute (no joint orient).

  • unit: unit label string (e.g. "meters").

  • keep_root: bool — whether the Root joint (index 0) is included.

Optional keys (present only if saved):

  • scale_params: (N, S) or (1, S).

  • joint_orient: (J, 3, 3) per-joint orient (present when absolute_pose=False).

  • global_scale: scalar uniform scale factor.

  • hand_type: "left" or "right" (absent for body animations).

Any extra arrays stored via extra_arrays are included as-is.

Parameters:

path (str | Path) – Path to the .npz file.

Returns:

dict of numpy arrays and Python scalars.

Return type:

SOMANPZData

soma.io.save_soma_usd(
out_path,
rotations=None,
root_translation=None,
*,
joint_names,
joint_parent_ids,
bind_transforms_world,
bind_transforms_local,
rest_shape,
faces=None,
face_vert_indices=None,
face_vert_counts=None,
uv_data=None,
skinning_weights,
unit='meters',
fps=30.0,
topk=8,
root_joint_idx=None,
skin_mesh_name=DEFAULT_SKIN_MESH_NAME,
)#

Save a SOMA skeletal rig (and optionally animation) to a USD file with UsdSkel.

When rotations and root_translation are omitted, only the static rig is written (skeleton bind pose + skinned mesh) with no SkelAnimation prim.

The rotations and root_translation should come directly from fit (local-space, absolute_pose=True convention).

Parameters:
  • out_path (str | Path) – Output .usd, .usda, or .usdc file path.

  • rotations (ndarray | Tensor | None) – (N, J, 3, 3) local rotation matrices, or None for a static rig.

  • root_translation (ndarray | Tensor | None) – (N, 3) root joint local translation, or None for a static rig.

  • joint_names (Sequence[str]) – list of J joint name strings (including Root).

  • joint_parent_ids (Sequence[int] | ndarray | Tensor) – (J,) parent index array.

  • bind_transforms_world (ndarray | Tensor) – (J, 4, 4) or (1, J, 4, 4) world-space bind transforms.

  • bind_transforms_local (ndarray | Tensor) – (J, 4, 4) or (1, J, 4, 4) local-space bind transforms.

  • rest_shape (ndarray | Tensor) – (V, 3) bind-pose vertex positions.

  • faces (ndarray | Tensor | None) – (F, 3) triangle face indices. Used as fallback when face_vert_indices/face_vert_counts are not provided.

  • face_vert_indices (ndarray | Tensor | None) – Flattened polygon face-vertex indices (e.g. quads from the template USD). Takes priority over faces when provided.

  • face_vert_counts (ndarray | Tensor | None) – Per-face vertex counts matching face_vert_indices.

  • uv_data (Mapping[str, UVPrimvarEntry] | None) – Optional UV sets in nested-dict format {name: {"coordinates": (M,2), "indices": ..., "interpolation": str}}, as returned by load_usd_mesh or load_rig_from_usd.

  • skinning_weights (ndarray | Tensor) – (V, J) dense skinning weights.

  • unit (str) – "meters", "centimeters", or "millimeters".

  • fps (float) – Frames per second (timeCodesPerSecond).

  • topk (int) – Max joint influences per vertex for sparse skinning.

  • root_joint_idx (int | None) – Index of the joint that receives root_translation. Defaults to 1 (SOMA body Hips); pass 0 for hand models.

  • skin_mesh_name (str) – Leaf name for the skinned mesh prim under the UsdSkelRoot. Defaults to DEFAULT_SKIN_MESH_NAME so that files written here round-trip cleanly through load_rig_from_usd.

soma.io.save_vertex_animation_usd(
out_path,
vertices,
faces,
*,
unit='meters',
fps=30.0,
prim_path='/Mesh',
)#

Save a mesh with per-frame vertex positions to USD.

No skeleton or skinning – just animated Points on a Mesh prim. Useful for exporting target meshes, blendshape sequences, or any topology-constant vertex animation.

Parameters:
  • out_path (str | Path) – Output .usd, .usda, or .usdc file path.

  • vertices (ndarray | Tensor) – (N, V, 3) per-frame vertex positions.

  • faces (ndarray | Tensor) – (F, 3) triangle face indices (constant across frames).

  • unit (str) – "meters", "centimeters", or "millimeters".

  • fps (float) – Frames per second.

  • prim_path (str) – USD prim path for the mesh (default "/Mesh").