Implementation:Isaac sim IsaacGymEnvs Skeleton3D
| Knowledge Sources | |
|---|---|
| Domains | Character_Animation, Skeleton_Representation |
| Last Updated | 2026-02-15 11:00 GMT |
Overview
The skeleton3d module provides three core classes -- SkeletonTree, SkeletonState, and SkeletonMotion -- that form a complete hierarchical skeleton representation system for loading, manipulating, and retargeting 3D character poses and motion sequences.
Description
The module at isaacgymenvs/tasks/amp/poselib/poselib/skeleton/skeleton3d.py implements a layered skeleton abstraction. SkeletonTree represents the static joint hierarchy as a tree of named nodes with parent indices and local translation offsets. It can be constructed from MJCF files (from_mjcf()), dictionaries (from_dict()), or FBX files, and serialized back via to_dict(). The tree defines the topology (which joints are connected) and the rest-pose bone lengths.
SkeletonState represents a single pose of the skeleton. It combines a SkeletonTree with per-joint rotations and a root translation. The class provides both local and global coordinate frame accessors: local_rotation/global_rotation and local_translation/global_translation, automatically performing forward kinematics to convert between frames. The factory method from_rotation_and_root_translation() constructs a state from local joint rotations and a root position, while zero_pose() creates a rest pose.
SkeletonMotion extends SkeletonState to represent a temporal sequence of poses with an associated framerate. It provides velocity, angular_velocity, global_root_velocity, and global_root_angular_velocity properties computed via finite differences. The from_file() factory loads motion from NPZ/FBX files, and retarget_to() performs motion retargeting between different skeleton topologies. All three classes inherit from Serializable, enabling consistent serialization and deserialization.
Usage
Use these classes throughout the AMP pipeline to load motion capture data, compute reference states for the discriminator, perform motion retargeting between different character morphologies, and represent skeleton poses during simulation. They are the primary data structures for the poselib motion processing library.
Code Reference
Source Location
- Repository: IsaacGymEnvs
- File: isaacgymenvs/tasks/amp/poselib/poselib/skeleton/skeleton3d.py
- Lines: 1-1419
Signature
class SkeletonTree(Serializable):
"""Joint hierarchy with node names, parent indices, and local translations."""
@staticmethod
def from_dict(dict_repr, *args, **kwargs) -> "SkeletonTree":
"""Construct from dictionary representation."""
@staticmethod
def from_mjcf(path: str) -> "SkeletonTree":
"""Parse MJCF XML file to build skeleton tree."""
def to_dict(self) -> OrderedDict:
"""Serialize to dictionary."""
@property
def node_names(self) -> List[str]: ...
@property
def parent_indices(self) -> Tensor: ...
@property
def local_translation(self) -> Tensor: ...
@property
def num_joints(self) -> int: ...
class SkeletonState(Serializable):
"""Single skeleton pose: rotations + root translation on a SkeletonTree."""
@staticmethod
def from_rotation_and_root_translation(skeleton_tree, rotation, root_translation, is_local=True):
"""Construct state from per-joint rotations and root position."""
@staticmethod
def zero_pose(skeleton_tree) -> "SkeletonState":
"""Create identity/rest pose."""
@property
def global_rotation(self) -> Tensor: ...
@property
def local_rotation(self) -> Tensor: ...
@property
def global_translation(self) -> Tensor: ...
@property
def local_translation(self) -> Tensor: ...
@property
def root_translation(self) -> Tensor: ...
class SkeletonMotion(SkeletonState):
"""Temporal sequence of skeleton poses with framerate."""
@staticmethod
def from_file(path: str) -> "SkeletonMotion":
"""Load motion from NPZ or FBX file."""
def retarget_to(self, target_skeleton_tree, joint_mapping, ...) -> "SkeletonMotion":
"""Retarget motion to a different skeleton topology."""
@property
def fps(self) -> float: ...
@property
def velocity(self) -> Tensor: ...
@property
def angular_velocity(self) -> Tensor: ...
@property
def global_root_velocity(self) -> Tensor: ...
@property
def global_root_angular_velocity(self) -> Tensor: ...
Import
from isaacgymenvs.tasks.amp.poselib.poselib.skeleton.skeleton3d import SkeletonTree, SkeletonState, SkeletonMotion
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| path | str | Yes | File path for loading: MJCF XML for SkeletonTree, NPZ/FBX for SkeletonMotion |
| skeleton_tree | SkeletonTree | Yes | Joint hierarchy definition required by SkeletonState and SkeletonMotion |
| rotation | Tensor(..., num_joints, 4) | Yes | Per-joint quaternion rotations in (x, y, z, w) format |
| root_translation | Tensor(..., 3) | Yes | Root joint world-space position |
| is_local | bool | No | Whether rotations are in local (True) or global (False) frame; defaults to True |
| joint_mapping | dict | No | Mapping from source to target joint names for retargeting |
Outputs
| Name | Type | Description |
|---|---|---|
| SkeletonTree | SkeletonTree | Parsed joint hierarchy with node_names, parent_indices, local_translation |
| SkeletonState | SkeletonState | Single pose with global/local rotation and translation accessors |
| SkeletonMotion | SkeletonMotion | Temporal pose sequence with velocity properties and fps |
| global_translation | Tensor(..., num_joints, 3) | World-space positions of all joints via forward kinematics |
| velocity | Tensor(..., num_joints, 3) | Per-joint linear velocities computed via finite differences |
Usage Examples
from isaacgymenvs.tasks.amp.poselib.poselib.skeleton.skeleton3d import (
SkeletonTree, SkeletonState, SkeletonMotion
)
# Load skeleton from MJCF
skeleton_tree = SkeletonTree.from_mjcf("assets/mjcf/amp_humanoid.xml")
print(f"Joints: {skeleton_tree.num_joints}")
print(f"Names: {skeleton_tree.node_names}")
# Create a zero (rest) pose
rest_pose = SkeletonState.zero_pose(skeleton_tree)
print(f"Root position: {rest_pose.root_translation}")
# Load a motion capture clip
motion = SkeletonMotion.from_file("assets/amp/motions/walk.npz")
print(f"Duration: {motion.tensor.shape[0] / motion.fps:.2f}s")
print(f"Global root velocity shape: {motion.global_root_velocity.shape}")
# Access per-frame data
frame_0_global_pos = motion.global_translation[0] # (num_joints, 3)
frame_0_global_rot = motion.global_rotation[0] # (num_joints, 4)
# Retarget motion to a different skeleton
target_tree = SkeletonTree.from_mjcf("assets/mjcf/target_humanoid.xml")
retargeted = motion.retarget_to(
target_skeleton_tree=target_tree,
joint_mapping={"source_hip": "target_hip", "source_knee": "target_knee"}
)