Visualization#

Visualization helpers for rendering skeletons and meshes.

G1 robot rig: mesh loading, joint mapping, and viser scene setup for G1 skeleton.

kimodo.viz.g1_rig.get_g1_joint_f2q_data(skeleton)[source]#

Return per-hinge-joint f2q data for correct 1-DoF + limits in offset space.

Each entry is for a G1 hinge joint (by name) and contains:
  • “offset_f2q”: (3, 3) matrix such that R_f2q = offset_f2q @ R_local (kimodo).

  • “axis_f2q”: (3,) unit axis in f2q space; angle = dot(axis_angle(R_f2q), axis_f2q).

  • “rest_dof_axis_angle”: angle (rad) at T-pose in f2q space; MuJoCo q = angle_f2q - this.

Limits from the XML apply to q = angle_f2q - rest_dof_axis_angle.

class kimodo.viz.g1_rig.G1MeshRig(name, server, skeleton, mesh_dir, color)[source]#

Bases: object

Rig for G1 STL meshes.

Each instance has its own scene meshes (so clear() only removes one character). Loading is shared: STL files and g1.xml are cached per mesh_dir via _load_g1_mesh_data() and the class- level _mesh_*_cache dicts.

__init__(name, server, skeleton, mesh_dir, color)[source]#
set_visibility(visible)[source]#
set_opacity(opacity)[source]#
set_wireframe(wireframe)[source]#
set_color(color)[source]#
set_pose(joints_pos, joints_rot)[source]#
clear()[source]#

SMPL-X skinning and joint mapping for visualization.

class kimodo.viz.smplx_skin.SMPLXSkin(skeleton, use_mean_hands=True)[source]#

Bases: object

__init__(skeleton, use_mean_hands=True)[source]#
lbs(posed_transform, bind_vertices=None)[source]#
skin(joint_rotmat, joint_pos, rot_is_global=False)[source]#

joint_rotmat: [T, J, 3, 3] local or global joint rotation matrices joint_pos: [T, J, 3] global joint positions rot_is_global: bool, if True, joint_rotmat is global rotation matrices, otherwise it is local rotation matrices and FK is performed internally

Viser-based 3D viz: re-exports from viz submodules for backward compatibility.

class kimodo.viz.viser_utils.Character(
name,
server,
skeleton,
create_skeleton_mesh=True,
create_skinned_mesh=True,
visible_skeleton=False,
visible_skinned_mesh=True,
skinned_mesh_opacity=1.0,
show_foot_contacts=True,
dark_mode=False,
mesh_mode=None,
gui_use_soma_layer_checkbox=None,
)[source]#

Bases: object

__init__(
name,
server,
skeleton,
create_skeleton_mesh=True,
create_skinned_mesh=True,
visible_skeleton=False,
visible_skinned_mesh=True,
skinned_mesh_opacity=1.0,
show_foot_contacts=True,
dark_mode=False,
mesh_mode=None,
gui_use_soma_layer_checkbox=None,
)[source]#
change_theme(is_dark_mode)[source]#
set_skeleton_visibility(visible)[source]#
set_show_foot_contacts(show)[source]#
set_skinned_mesh_visibility(visible)[source]#
set_skinned_mesh_opacity(opacity)[source]#
set_skinned_mesh_wireframe(wireframe)[source]#
precompute_skinning(joints_pos, joints_rot)[source]#

Precompute skinning for all frames.

joints_pos: [T, J, 3], joints_rot: [T, J, 3, 3].

update_skinning_cache(joints_pos, joints_rot, frame_idx)[source]#

Update skinning cache for one frame.

set_pose(
joints_pos,
joints_rot,
foot_contacts=None,
frame_idx=None,
)[source]#
get_pose()[source]#
clear()[source]#
class kimodo.viz.viser_utils.CharacterMotion(character, joints_pos, joints_rot, foot_contacts=None)[source]#

Bases: object

__init__(
character,
joints_pos,
joints_rot,
foot_contacts=None,
)[source]#
precompute_mesh_info()[source]#
set_frame(idx)[source]#

Sets the pose of the character to the given frame index.

update_pose_at_frame(
frame_idx,
joints_pos=None,
joints_rot=None,
joints_local_rot=None,
foot_contacts=None,
)[source]#

Overwrites one or more of the pose components at the given frame.

If only a subset of joints_pos, joints_rot, or joints_local_rot are provided, the other components will be updated with FK.

clear()[source]#
get_current_projected_root_pos()[source]#

Get the projected root position on the ground at the current frame.

get_projected_root_pos(
start_frame_idx,
end_frame_idx=None,
)[source]#

If requested frames are out of range, simply pads with the last frame to get expected length.

set_projected_root_pos_path(
root_pos_path,
min_frame_idx=None,
max_frame_idx=None,
)[source]#

Sets the projected root position path for the character motion. Can set only a subset of the path by providing min_frame_idx and max_frame_idx. If not provided, will set the full path.

Parameters:
  • root_pos_path – torch.Tensor, [T, 2] projected root positions

  • min_frame_idx – int, optional, minimum frame index to set the path at

  • max_frame_idx – int, optional, maximum frame index to set the path at

get_joints_pos(start_frame_idx, end_frame_idx=None)[source]#

If requested frames are out of range, simply pads with the last frame to get expected length.

get_joints_rot(start_frame_idx, end_frame_idx=None)[source]#

If requested frames are out of range, simply pads with the last frame to get expected length.

get_current_joints_pos()[source]#
get_current_joints_rot()[source]#
add_root_translation_gizmo(
constraints,
on_2d_root_drag_end=None,
on_drag_start=None,
)[source]#

Create and initialize gizmo to control the root translation.

When the user drags the root 2D gizmo, path updates are skipped until release. Optional on_2d_root_drag_end is called when the drag ends (e.g. to refresh dense path). on_drag_start is called when the drag begins (e.g. to snapshot state for undo).

add_joint_gizmos(
constraints,
space='local',
on_drag_start=None,
)[source]#
clear_all_gizmos()[source]#
class kimodo.viz.viser_utils.ConstraintSet(name, server, skeleton, display_name=None)[source]#

Bases: object

__init__(name, server, skeleton, display_name=None)[source]#
set_label_visibility(visible)[source]#

Show or hide constraint labels without deleting them.

set_overlay_visibility(only_frame=None)[source]#

Show all overlay elements, or only those at the given frame.

Parameters:

only_frame – If None, show all overlays. If int, show only overlays at that frame.

add_keyframe(keyframe_id, frame_idx, pose_data)[source]#

Adds a single keyframe at the given frame with the given pose data.

Parameters:
  • keyframe_id – str, id for the keyframe. Must be unique within the given frame_idx.

  • frame_idx – int, frame index to add the keyframe at

  • pose_data – torch.Tensor, e.g. full-body pose, EE pose, 2D root pose, etc.

add_interval(
interval_id,
start_frame_idx,
end_frame_idx,
pose_seq_data,
)[source]#

Adds a keyframe interval between the given start and end frames with the given pose data.

Parameters:
  • interval_id – str, id for the interval. Must be unique within the given start_frame_idx and end_frame_idx.

  • start_frame_idx – int, start frame index of the interval

  • end_frame_idx – int, end frame index of the interval

  • pose_seq_data – torch.Tensor, data for constrained interval, e.g. full-body poses, EE poses, 2D root poses, etc.

remove_keyframe(keyframe_id, frame_idx)[source]#

Removes a keyframe at the given frame :param keyframe_id: str, id for the keyframe to remove :param frame_idx: int, frame index to remove the keyframe at

remove_interval(
interval_id,
start_frame_idx,
end_frame_idx,
)[source]#

Removes an interval between the given start and end frames :param interval_id: str, id for the interval to remove :param start_frame_idx: int, start frame index of the interval :param end_frame_idx: int, end frame index of the interval

get_constraint_info(device=None)[source]#

Returns constraint information for generation (torch) or UI (numpy).

get_frame_idx()[source]#

Returns all constrained frame indices in the set.

clear(frame_idx=None)[source]#

Clears all keyframes and intervals from the constraint set :param frame_idx: int, sing frame index to clear if given

class kimodo.viz.viser_utils.EEJointsKeyframeSet(name, server, skeleton, display_name=None)[source]#

Bases: ConstraintSet

__init__(
name,
server,
skeleton,
display_name=None,
)[source]#
create_scene_elements(
frame_idx,
joints_pos,
joints_rot,
joint_names,
viz_label=True,
)[source]#
add_keyframe(
keyframe_id,
frame_idx,
joints_pos,
joints_rot,
joint_names,
end_effector_type,
viz_label=True,
exists_ok=False,
)[source]#

Adds a single EE keyframe at the given frame or updates the existing one at this frame.

Parameters:
  • keyframe_id – str, id for the keyframe. Must be unique within the given frame_idx.

  • frame_idx – int, frame index to add the keyframe at

  • joints_pos – torch.Tensor, [J, 3] joints positions to add the keyframe at

  • joints_rot – torch.Tensor, [J, 3, 3] joints rotation matrices to add the keyframe at

  • joint_names – List[str], names of the joints to add the keyframe at

add_interval(
interval_id,
start_frame_idx,
end_frame_idx,
joints_pos,
joints_rot,
joint_names,
end_effector_type,
)[source]#

Adds an interval of EE keyframes at the given frame or updates the existing one at this frame.

Parameters:
  • interval_id – str, id for the interval. Must be unique within the given start_frame_idx and end_frame_idx.

  • start_frame_idx – int, start frame index to add the interval at

  • end_frame_idx – int, end frame index to add the interval at

  • joints_pos – torch.Tensor, [T, J, 3] joints positions to add the interval at

  • joints_rot – torch.Tensor, [T, J, 3, 3] joints rotation matrices to add the interval at

  • joint_names – List[str], names of the joints to add for the entire interval

remove_keyframe(keyframe_id, frame_idx)[source]#

Removes a keyframe at the given frame or updates the existing one at this frame by removing the specified joints.

Parameters:
  • keyframe_id – str, id for the keyframe to remove. This determines which joints to remove.

  • frame_idx – int, frame index to remove the keyframe at

remove_interval(
interval_id,
start_frame_idx,
end_frame_idx,
)[source]#

Removes an interval between the given start and end frames :param interval_id: str, id for the interval to remove :param start_frame_idx: int, start frame index of the interval :param end_frame_idx: int, end frame index of the interval

get_constraint_info(device=None)[source]#

Returns constraint information for generation (torch) or UI (numpy).

clear(frame_idx=None, scene_elements_only=False)[source]#

Clears all keyframes and intervals from the constraint set :param frame_idx: int, sing frame index to clear if given

set_overlay_visibility(only_frame=None)[source]#

Show all overlay elements, or only those at the given frame.

Parameters:

only_frame – If None, show all overlays. If int, show only overlays at that frame.

class kimodo.viz.viser_utils.FullbodyKeyframeSet(name, server, skeleton, display_name=None)[source]#

Bases: ConstraintSet

__init__(
name,
server,
skeleton,
display_name=None,
)[source]#
add_keyframe(
keyframe_id,
frame_idx,
joints_pos,
joints_rot,
viz_label=True,
exists_ok=False,
)[source]#

Adds a single full-body keyframe at the given frame or updates the existing one at this frame. Note if a keyframe already exists at this frame, it will be updated to the given pose.

Parameters:
  • keyframe_id – str, id for the keyframe. Must be unique within the given frame_idx.

  • frame_idx – int, frame index to add the keyframe at

  • joints_pos – torch.Tensor, [J, 3] joints positions to add the keyframe at

add_interval(
interval_id,
start_frame_idx,
end_frame_idx,
joints_pos,
joints_rot,
)[source]#

Adds a full-body keyframe interval between the given start and end frames.

Parameters:
  • start_frame_idx – int, start frame index of the interval

  • end_frame_idx – int, end frame index of the interval

  • joints_pos – torch.Tensor, [T, J, 3] joints positions within the interval

remove_keyframe(keyframe_id, frame_idx)[source]#

Removes a keyframe at the given frame :param keyframe_id: str, id for the keyframe to remove :param frame_idx: int, frame index to remove the keyframe at

remove_interval(
interval_id,
start_frame_idx,
end_frame_idx,
)[source]#

Removes an interval between the given start and end frames :param interval_id: str, id for the interval to remove :param start_frame_idx: int, start frame index of the interval :param end_frame_idx: int, end frame index of the interval

get_constraint_info(device=None)[source]#

Returns constraint information for generation (torch) or UI (numpy).

clear(frame_idx=None)[source]#

Clears all keyframes and intervals from the constraint set :param frame_idx: int, sing frame index to clear if given

set_overlay_visibility(only_frame=None)[source]#

Show all overlay elements, or only those at the given frame.

Parameters:

only_frame – If None, show all overlays. If int, show only overlays at that frame.

class kimodo.viz.viser_utils.GuiElements(
gui_play_pause_button: viser._gui_handles.GuiInputHandle,
gui_next_frame_button: viser._gui_handles.GuiInputHandle,
gui_prev_frame_button: viser._gui_handles.GuiInputHandle,
gui_generate_button: viser._gui_handles.GuiInputHandle,
gui_model_fps: viser._gui_handles.GuiInputHandle[int],
gui_timeline: viser._gui_handles.GuiInputHandle[int],
gui_viz_skeleton_checkbox: viser._gui_handles.GuiInputHandle[bool],
gui_viz_foot_contacts_checkbox: viser._gui_handles.GuiInputHandle[bool],
gui_viz_skinned_mesh_checkbox: viser._gui_handles.GuiInputHandle[bool],
gui_viz_skinned_mesh_opacity_slider: viser._gui_handles.GuiInputHandle[float],
gui_camera_fov_slider: viser._gui_handles.GuiInputHandle[float],
gui_duration_slider: viser._gui_handles.GuiInputHandle[float],
gui_num_samples_slider: viser._gui_handles.GuiInputHandle[int],
gui_cfg_checkbox: viser._gui_handles.GuiCheckboxHandle,
gui_cfg_text_weight_slider: viser._gui_handles.GuiInputHandle[float],
gui_cfg_constraint_weight_slider: viser._gui_handles.GuiInputHandle[float],
gui_diffusion_steps_slider: viser._gui_handles.GuiInputHandle[int],
gui_seed: viser._gui_handles.GuiInputHandle[int],
gui_postprocess_checkbox: viser._gui_handles.GuiCheckboxHandle,
gui_root_margin: viser._gui_handles.GuiInputHandle[float],
gui_real_robot_rotations_checkbox: viser._gui_handles.GuiInputHandle[bool],
gui_dark_mode_checkbox: viser._gui_handles.GuiCheckboxHandle,
gui_use_soma_layer_checkbox: viser._gui_handles.GuiCheckboxHandle,
)[source]#

Bases: object

gui_play_pause_button#
gui_next_frame_button#
gui_prev_frame_button#
gui_generate_button#
gui_model_fps#
gui_timeline#
gui_viz_skeleton_checkbox#
gui_viz_foot_contacts_checkbox#
gui_viz_skinned_mesh_checkbox#
gui_viz_skinned_mesh_opacity_slider#
gui_camera_fov_slider#
gui_duration_slider#
gui_num_samples_slider#
gui_cfg_checkbox#
gui_cfg_text_weight_slider#
gui_cfg_constraint_weight_slider#
gui_diffusion_steps_slider#
gui_seed#
gui_postprocess_checkbox#
gui_root_margin#
gui_real_robot_rotations_checkbox#
gui_dark_mode_checkbox#
gui_use_soma_layer_checkbox#
__init__(
gui_play_pause_button,
gui_next_frame_button,
gui_prev_frame_button,
gui_generate_button,
gui_model_fps,
gui_timeline,
gui_viz_skeleton_checkbox,
gui_viz_foot_contacts_checkbox,
gui_viz_skinned_mesh_checkbox,
gui_viz_skinned_mesh_opacity_slider,
gui_camera_fov_slider,
gui_duration_slider,
gui_num_samples_slider,
gui_cfg_checkbox,
gui_cfg_text_weight_slider,
gui_cfg_constraint_weight_slider,
gui_diffusion_steps_slider,
gui_seed,
gui_postprocess_checkbox,
gui_root_margin,
gui_real_robot_rotations_checkbox,
gui_dark_mode_checkbox,
gui_use_soma_layer_checkbox,
)#
class kimodo.viz.viser_utils.RootKeyframe2DSet(name, server, skeleton, display_name=None)[source]#

Bases: ConstraintSet

__init__(name, server, skeleton, display_name=None)[source]#
add_keyframe(
keyframe_id,
frame_idx,
root_pos,
viz_label=True,
update_path=True,
viz_waypoint=True,
exists_ok=False,
)[source]#

Adds a single 2D root keyframe at the given frame or updates the existing one at this frame.

Parameters:
  • keyframe_id – str, id for the keyframe. Must be unique within the given frame_idx.

  • frame_idx – int, frame index to add the keyframe at

  • root_pos – torch.Tensor, [3] root position to add the keyframe at, y entry (index 1) should be 0

  • viz_label – bool, whether to visualize the label for the keyframe

add_interval(
interval_id,
start_frame_idx,
end_frame_idx,
root_pos,
)[source]#

Adds an interval of 2D root keyframes between the given start and end frames.

Parameters:
  • interval_id – str, id for the interval. Must be unique within the given start_frame_idx and end_frame_idx.

  • start_frame_idx – int, start frame index to add the interval at

  • end_frame_idx – int, end frame index to add the interval at

  • root_pos – torch.Tensor, [T, 3] root positions to add the interval at

set_smooth_path(smooth_path)[source]#
set_dense_path(dense_path)[source]#

If dense_path is True, will make the path dense by interpolated between added keyframes.

Parameters:

dense_path – bool, whether to make the path dense

interpolate_path(t)[source]#

Interpolates the path between the given frame indices.

Parameters:

t – np.ndarray, frame indices to interpolate at

update_line_segments()[source]#
remove_keyframe(keyframe_id, frame_idx)[source]#

Removes a keyframe at the given frame :param keyframe_id: str, id for the keyframe to remove :param frame_idx: int, frame index to remove the keyframe at

remove_interval(
interval_id,
start_frame_idx,
end_frame_idx,
)[source]#

Removes an interval between the given start and end frames :param interval_id: str, id for the interval to remove :param start_frame_idx: int, start frame index of the interval :param end_frame_idx: int, end frame index of the interval

get_constraint_info(device=None)[source]#

Returns constraint information for generation (torch) or UI (numpy).

clear(frame_idx=None)[source]#

Clears all keyframes and intervals from the constraint set :param frame_idx: int, sing frame index to clear if given

set_overlay_visibility(only_frame=None)[source]#

Show all overlay elements, or only those at the given frame.

Parameters:

only_frame – If None, show all overlays. If int, show only overlays at that frame.

class kimodo.viz.viser_utils.SkeletonMesh(
name,
server,
skeleton,
joint_color=(255, 235, 0),
bone_color=(27, 106, 0),
starting_joints_pos=None,
)[source]#

Bases: object

__init__(
name,
server,
skeleton,
joint_color=(255, 235, 0),
bone_color=(27, 106, 0),
starting_joints_pos=None,
)[source]#

name: str, name of the skeleton mesh server: viser.ViserServer, server to add the skeleton mesh to skeleton: SkeletonBase, skeleton to visualize joint_color: Optional[Tuple[float, float, float] | np.ndarray], color of the joints bone_color: Optional[Tuple[float, float, float] | np.ndarray], color of the bones starting_joints_pos: Optional[torch.Tensor], starting joint positions

compute_single_pose(joints_pos)[source]#

Compute the mesh for a single frame.

joints_pos: [J, 3] global joint positions.

precompute_mesh_info(joints_pos)[source]#

Precompute the meshes for all frames at once.

joints_pos: [T, J, 3].

update_mesh_info_cache(joints_pos, frame_idx)[source]#

Update the mesh info cache for the given frame.

set_pose(joints_pos, foot_contacts=None, frame_idx=None)[source]#

Set pose from [J, 3] global joint positions.

set_visibility(visible)[source]#
get_pose()[source]#
clear()[source]#
class kimodo.viz.viser_utils.WaypointMesh(name, server, position, heading=None, color=(255, 0, 0))[source]#

Bases: object

__init__(
name,
server,
position,
heading=None,
color=(255, 0, 0),
)[source]#
update_position(position, heading=None)[source]#
clear()[source]#
set_visible(visible)[source]#
kimodo.viz.viser_utils.build_constraint_set_table_markdown(constraint_list)[source]#
kimodo.viz.viser_utils.load_example_cases(examples_base_dir)[source]#

List subdirectories of examples_base_dir as a name -> path dict.

kimodo.viz.viser_utils.update_interval(
interval_start,
interval_end,
start_frame_idx,
end_frame_idx,
)[source]#

Updates an interval after removing the range from start_frame_idx to end_frame_idx.