Create Actors

SAPIEN simulates rigid body dynamics. In SAPIEN, actor is an alias of rigid body.

In this tutorial, you will learn the following:

  • Create Actor using primitives (box, sphere, capsule)

  • Create Actor using mesh files

  • Use Pose to set the pose of an actor

../../_images/create_actors.png

The full script can be downloaded here create_actors.py

Create an actor by a single primitive

The primitives supported by SAPIEN include box, sphere and capsule. Here we show an example about how to create a box. Examples to create a sphere and a capsule can be found in the code provided.

def create_box(
        scene: sapien.Scene,
        pose: sapien.Pose,
        half_size,
        color=None,
        name='',
) -> sapien.Actor:
    """Create a box.

    Args:
        scene: sapien.Scene to create a box.
        pose: 6D pose of the box.
        half_size: [3], half size along x, y, z axes.
        color: [3] or [4], rgb or rgba
        name: name of the actor.

    Returns:
        sapien.Actor
    """
    half_size = np.array(half_size)
    builder: sapien.ActorBuilder = scene.create_actor_builder()
    builder.add_box_collision(half_size=half_size)  # Add collision shape
    builder.add_box_visual(half_size=half_size, color=color)  # Add visual shape
    box: sapien.Actor = builder.build(name=name)
    # Or you can set_name after building the actor
    # box.set_name(name)
    box.set_pose(pose)
    return box

Actor (or rigid body) is created through ActorBuilder in SAPIEN. An actor consists of both collision shapes (used for physical simulation) and visual shapes (used for rendering). You can call add_box_collision and add_box_visual to add collision and visual shapes of an box respectively.

Note

Collision shapes do not necessarily correspond to visual shapes. For example, you might have a simple collision shape for fast simulation, but a complicated visual shape for realistic rendering.

Then, you might create a box as follows:

    box = create_box(
        scene,
        sapien.Pose(p=[0, 0, 1.0 + 0.05]),
        half_size=[0.05, 0.05, 0.05],
        color=[1., 0., 0.],
        name='box',
    )

The pose of the box in the world frame can be specified by Pose. Pose describes a 6D pose, consisting of a 3-dim position vector p and a 4-dim quaternion q (to represent the rotation, in the wxyz convention).

Create an actor by multiple primitives

Next, we show an example to create an actor (table) by multiple boxes (a tabletop with four legs).

def create_table(
        scene: sapien.Scene,
        pose: sapien.Pose,
        size,
        height,
        thickness=0.1,
        color=(0.8, 0.6, 0.4),
        name='table',
) -> sapien.Actor:
    """Create a table (a collection of collision and visual shapes)."""
    builder = scene.create_actor_builder()
    
    # Tabletop
    tabletop_pose = sapien.Pose([0., 0., -thickness / 2])  # Make the top surface's z equal to 0
    tabletop_half_size = [size / 2, size / 2, thickness / 2]
    builder.add_box_collision(pose=tabletop_pose, half_size=tabletop_half_size)
    builder.add_box_visual(pose=tabletop_pose, half_size=tabletop_half_size, color=color)
    
    # Table legs (x4)
    for i in [-1, 1]:
        for j in [-1, 1]:
            x = i * (size - thickness) / 2
            y = j * (size - thickness) / 2
            table_leg_pose = sapien.Pose([x, y, -height / 2])
            table_leg_half_size = [thickness / 2, thickness / 2, height / 2]
            builder.add_box_collision(pose=table_leg_pose, half_size=table_leg_half_size)
            builder.add_box_visual(pose=table_leg_pose, half_size=table_leg_half_size, color=color)

    table = builder.build(name=name)
    table.set_pose(pose)
    return table

We can call add_box_collision(pose=Pose(...), ...) to set the pose of a collision shape in the actor frame. Similarly, we can call add_box_visual(pose=Pose(...), ...) for a visual shape. Note that table.set_pose(pose) sets the pose of the actor in the world frame.

Create an actor by a mesh file

Apart from primitives, actors can also be created from mesh files.

    builder = scene.create_actor_builder()
    builder.add_collision_from_file(filename='../assets/banana/collision_meshes/collision.obj')
    builder.add_visual_from_file(filename='../assets/banana/visual_meshes/visual.dae')
    mesh = builder.build(name='mesh')
    mesh.set_pose(sapien.Pose(p=[-0.2, 0, 1.0 + 0.05]))

Note

Any collision shape in SAPIEN is required to be convex. To this end, a mesh will be “cooked” into a convex mesh before being used in the simulation. The converted convex mesh is cached at the same directory of the original mesh file. Thus, if the mesh file is changed, please remove the cache.

Remove an actor

After an actor is built with actor = builder.build(), You can call scene.remove_actor(actor) to remove it. Using a removed actor will result in undefined behavior (usually a crash).