Load and pose a character
This example loads a character, changes one model parameter, runs forward kinematics, and skins the character mesh.
Prerequisites
Download the repository's public sample character and model definition:
curl -L \
https://raw.githubusercontent.com/facebookresearch/momentum/main/momentum/examples/convert_model/test_data/character.fbx \
-o character.fbx
curl -L \
https://raw.githubusercontent.com/facebookresearch/momentum/main/momentum/examples/convert_model/test_data/character.model \
-o character.model
The .model file populates character.parameter_transform; loading only the
FBX would produce a character without usable model parameters.
The same pose operations apply to characters loaded from glTF or URDF.
Load and inspect the character
import numpy as np
import pymomentum.geometry as pym_geometry
character = pym_geometry.Character.load_fbx(
fbx_filename="character.fbx",
model_filename="character.model",
)
print(f"joints: {character.skeleton.size}")
print(f"model parameters: {character.parameter_transform.size}")
print(character.skeleton.joint_names[:10])
print(character.parameter_transform.names[:10])
Joint and parameter names come from the asset. Prefer looking them up by name over copying numeric indices between characters:
joint_index = character.skeleton.joint_index("joint1")
parameter_mask = character.parameter_transform.find_parameters(["joint1_rx"])
parameter_index = int(np.flatnonzero(parameter_mask)[0])
Use names that exist in your character; rigs do not share a universal naming scheme.
Run forward kinematics
A zero vector represents the character's reference model parameters. Here we change the first pose parameter so the example does not depend on a particular naming convention:
model_parameters = np.zeros(
character.parameter_transform.size,
dtype=np.float32,
)
pose_parameters = np.flatnonzero(
character.parameter_transform.pose_parameters
)
if len(pose_parameters) == 0:
raise ValueError("The character has no pose parameters")
model_parameters[pose_parameters[0]] = 0.35
skeleton_state = pym_geometry.model_parameters_to_skeleton_state(
character,
model_parameters,
)
For a motion sequence, pass an array with shape (frames, parameters). The
result then has shape (frames, joints, 8).
If the character has a mesh, the same skeleton state can drive linear blend skinning:
if character.has_mesh:
posed_vertices = character.skin_points(skeleton_state)
print(posed_vertices.shape) # (vertices, 3)
See Core concepts for the relationship between model parameters, joint parameters, skeleton states, and posed vertices. The geometry API reference lists the available loaders and conversions. The public model-conversion integration test uses the same sample assets and model definition.