Jump to content

Connect Leeroopedia MCP: Equip your AI agents to search best practices, build plans, verify code, diagnose failures, and look up hyperparameter defaults.

Implementation:Haosulab ManiSkill ActorBuilder TableSceneBuilder

From Leeroopedia
Field Value
Page Type Implementation (API Doc)
Title ManiSkill ActorBuilder and TableSceneBuilder
Domain Simulation, Robotics, Environment_Design, Physics_Simulation
Related Principle Principle:Haosulab_ManiSkill_Scene_Object_Loading
Source Files mani_skill/utils/building/actor_builder.py (L21-261), mani_skill/utils/scene_builder/table/scene_builder.py (L16-66)
Date 2026-02-15
Repository Haosulab/ManiSkill

Overview

Description

ActorBuilder is a ManiSkill extension of SAPIEN's ActorBuilder that supports batched construction of rigid-body actors across multiple parallel sub-scenes. It provides a fluent API for adding collision shapes (box, sphere, capsule, convex mesh, etc.), visual shapes (from files or procedural geometry), and configuring physics body types (dynamic, kinematic, static). The built actor is automatically replicated across all parallel environments unless restricted via set_scene_idxs().

TableSceneBuilder is a pre-built scene template that creates a standard tabletop workspace. It loads a table mesh, positions it so that z=0 corresponds to the table surface, creates a ground plane, and provides robot-specific initialization for supported robot models (Panda, Fetch, xArm6, etc.).

Usage

ActorBuilder is obtained from the scene; TableSceneBuilder is imported directly.

# ActorBuilder -- obtained from scene
builder = self.scene.create_actor_builder()

# TableSceneBuilder -- imported directly
from mani_skill.utils.scene_builder.table import TableSceneBuilder

Code Reference

ActorBuilder (mani_skill/utils/building/actor_builder.py)

class ActorBuilder(SAPIENActorBuilder):
    """
    ActorBuilder class to flexibly build actors in both CPU and GPU simulations.
    Inherits the original SAPIEN ActorBuilder and changes the build functions
    to support a batch of scenes and return a batch of Actors.
    """

    scene: ManiSkillScene

    def __init__(self):
        super().__init__()
        self.initial_pose = None       # Pose: initial pose for the actor
        self.scene_idxs = None         # Optional[Tensor]: which parallel envs to build in
        self._allow_overlapping_plane_collisions = False

    def set_scene_idxs(self, scene_idxs=None):
        """Restrict this actor to specific parallel environment indices."""
        ...

    def build(self, name: str) -> Actor:
        """Build the actor with the given unique name. Returns an Actor object."""
        ...

    def build_static(self, name: str) -> Actor:
        """Build as a static (immovable) body."""
        ...

    def build_kinematic(self, name: str) -> Actor:
        """Build as a kinematic (programmatically movable) body."""
        ...

    def build_dynamic(self, name: str) -> Actor:
        """Build as a dynamic (physics-driven) body."""
        ...

Key inherited methods from SAPIEN ActorBuilder (used before calling .build()):

Method Description
add_box_collision(half_size, ...) Add a box collision shape
add_box_visual(half_size, color, ...) Add a box visual shape
add_sphere_collision(radius, ...) Add a sphere collision shape
add_sphere_visual(radius, color, ...) Add a sphere visual shape
add_capsule_collision(radius, half_length, ...) Add a capsule collision shape
add_convex_collision_from_file(filename, scale, ...) Add a convex mesh collision from file
add_visual_from_file(filename, scale, ...) Add a visual mesh from file
add_nonconvex_collision_from_file(filename, scale, ...) Add a triangle mesh collision from file
set_mass(mass) Set mass of the actor
set_physx_body_type(type) Set body type: "dynamic", "kinematic", or "static"

TableSceneBuilder (mani_skill/utils/scene_builder/table/scene_builder.py)

class TableSceneBuilder(SceneBuilder):
    """A simple scene builder that adds a table to the scene such that
    the height of the table is at z=0, and gives reasonable initial
    poses for robots."""

    def build(self):
        """Build the table, ground plane, and store references to
        self.table, self.ground, self.scene_objects.
        Also computes self.table_length, self.table_width, self.table_height."""
        ...

    def initialize(self, env_idx: torch.Tensor):
        """Set initial poses for the table and robot based on the
        robot_uids of the environment. Supports: panda, panda_wristcam,
        fetch, xarm6 variants, panda_stick, widowxai, so100, and others."""
        ...

I/O Contract

ActorBuilder.build()

Parameter Type Required Description
name str Yes Unique name for the actor within the scene

Preconditions:

  • The builder must be created via self.scene.create_actor_builder() so that builder.scene is set.
  • At least one collision or visual shape should be added before building.
  • initial_pose should be set to prevent physics instabilities (a warning is logged if omitted).
  • The name must be unique -- building with a duplicate name raises an AssertionError.

Returns: An Actor object representing the built rigid body across all (or selected) parallel environments.

Side effects:

  • Adds the actor to self.scene.actors[name].
  • Registers the actor in the scene's state dict registry.
  • Creates SAPIEN entities in the appropriate sub-scenes.

TableSceneBuilder Constructor

Parameter Type Required Description
env BaseEnv Yes The environment instance
robot_init_qpos_noise float No Standard deviation of noise added to robot initial joint positions (default: 0.02)

Usage Examples

Building a Custom Cube Actor

def _load_scene(self, options: dict):
    # Use TableSceneBuilder for the workspace
    self.table_scene = TableSceneBuilder(
        env=self, robot_init_qpos_noise=self.robot_init_qpos_noise
    )
    self.table_scene.build()

    # Build a custom cube using the raw ActorBuilder API
    builder = self.scene.create_actor_builder()
    builder.add_box_collision(half_size=[0.02, 0.02, 0.02])
    builder.add_box_visual(
        half_size=[0.02, 0.02, 0.02],
        color=[1.0, 0.0, 0.0, 1.0],
    )
    builder.initial_pose = sapien.Pose(p=[0, 0, 0.02])
    self.cube = builder.build("red_cube")

Using Convenience Build Functions

from mani_skill.utils.building import actors

def _load_scene(self, options: dict):
    self.table_scene = TableSceneBuilder(env=self)
    self.table_scene.build()

    # Convenience function wraps the ActorBuilder pattern
    self.obj = actors.build_cube(
        self.scene,
        half_size=0.02,
        color=np.array([12, 42, 160, 255]) / 255,
        name="cube",
        body_type="dynamic",
        initial_pose=sapien.Pose(p=[0, 0, 0.02]),
    )

    # Build a visual-only goal marker (no collision)
    self.goal_region = actors.build_red_white_target(
        self.scene,
        radius=0.1,
        thickness=1e-5,
        name="goal_region",
        add_collision=False,
        body_type="kinematic",
        initial_pose=sapien.Pose(p=[0, 0, 1e-3]),
    )

Restricting an Actor to Specific Environments

def _load_scene(self, options: dict):
    # Only create the obstacle in environments 0 and 2
    builder = self.scene.create_actor_builder()
    builder.add_box_collision(half_size=[0.1, 0.1, 0.1])
    builder.add_box_visual(half_size=[0.1, 0.1, 0.1], color=[0.5, 0.5, 0.5, 1.0])
    builder.set_scene_idxs([0, 2])
    builder.initial_pose = sapien.Pose(p=[0.3, 0, 0.1])
    self.obstacle = builder.build_static("obstacle")

Loading a Mesh-Based Actor from File

def _load_scene(self, options: dict):
    builder = self.scene.create_actor_builder()
    builder.add_convex_collision_from_file(
        filename="path/to/mesh.obj",
        scale=[0.01, 0.01, 0.01],
    )
    builder.add_visual_from_file(
        filename="path/to/mesh.glb",
        scale=[0.01, 0.01, 0.01],
    )
    builder.initial_pose = sapien.Pose(p=[0, 0, 0.05])
    self.mesh_actor = builder.build("mesh_object")

Related Pages

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment