Skip to content

prim_base

BasePrim

Bases: Serializable, Recreatable, ABC

Provides high level functions to deal with a basic prim and its attributes/ properties. If there is an Xform prim present at the path, it will use it. Otherwise, a new XForm prim at the specified prim path will be created.

the prim will have "xformOp:orient", "xformOp:translate" and "xformOp:scale" only post init,

unless it is a non-root articulation link.

Parameters:

Name Type Description Default
relative_prim_path str

Scene-local prim path of the Prim to encapsulate or create.

required
name str

Name for the object. Names need to be unique per scene.

required
load_config None or dict

If specified, should contain keyword-mapped values that are relevant for loading this prim at runtime. Note that this is only needed if the prim does not already exist at @relative_prim_path -- it will be ignored if it already exists. Subclasses should define the exact keys expected for their class.

None
Source code in omnigibson/prims/prim_base.py
class BasePrim(Serializable, Recreatable, ABC):
    """
    Provides high level functions to deal with a basic prim and its attributes/ properties.
    If there is an Xform prim present at the path, it will use it. Otherwise, a new XForm prim at
    the specified prim path will be created.

    Note: the prim will have "xformOp:orient", "xformOp:translate" and "xformOp:scale" only post init,
        unless it is a non-root articulation link.

    Args:
        relative_prim_path (str): Scene-local prim path of the Prim to encapsulate or create.
        name (str): Name for the object. Names need to be unique per scene.
        load_config (None or dict): If specified, should contain keyword-mapped values that are relevant for
            loading this prim at runtime. Note that this is only needed if the prim does not already exist at
            @relative_prim_path -- it will be ignored if it already exists. Subclasses should define the exact keys expected
            for their class.
    """

    def __init__(
        self,
        relative_prim_path,
        name,
        load_config=None,
    ):
        self._relative_prim_path = relative_prim_path
        assert relative_prim_path.startswith("/"), f"Relative prim path {relative_prim_path} must start with a '/'!"
        assert all(
            component[0] in string.ascii_letters for component in relative_prim_path[1:].split("/")
        ), f"Each component of relative prim path {relative_prim_path} must start with a letter!"

        self._name = name
        self._load_config = dict() if load_config is None else load_config

        # Other values that will be filled in at runtime
        self._scene = None
        self._scene_assigned = False
        self._applied_visual_material = None
        self._loaded = False  # Whether this prim exists in the stage or not
        self._initialized = False  # Whether this prim has its internal handles / info initialized or not (occurs AFTER and INDEPENDENTLY from loading!)
        self._prim = None
        self._n_duplicates = 0  # Simple counter for keeping track of duplicates for unique name indexing

        # Check if this prim was created manually. This member will be automatically set for prims
        # that get created during the _load phase of this class, but sometimes we create prims using
        # alternative methods and then create this class - in that case too we need to make sure we
        # add the right xform properties, so callers will just pass in the created manually flag.
        self._xform_props_pre_loaded = self._load_config.get("xform_props_pre_loaded", False)
        # Run super init
        super().__init__()

    def _initialize(self):
        """
        Initializes state of this object and sets up any references necessary post-loading. Should be implemented by
        sub-class for extended utility
        """
        pass

    def initialize(self):
        """
        Initializes state of this object and sets up any references necessary post-loading. Subclasses should
        implement / extend the _initialize() method.
        """
        assert (
            not self._initialized
        ), f"Prim {self.name} at prim_path {self.prim_path} can only be initialized once! (It is already initialized)"
        self._initialize()

        self._initialized = True

        # Cache state size (note that we are doing this after initialized is set to True because
        # dump_state asserts that the prim is initialized for some prims).
        self._state_size = len(self.dump_state(serialized=True))

    def load(self, scene):
        """
        Load this prim into omniverse, and return loaded prim reference.

        Returns:
            Usd.Prim: Prim object loaded into the simulator
        """
        # Load the prim if it doesn't exist yet.
        assert (
            not self._loaded
        ), f"Prim {self.name} at prim_path {self.prim_path} can only be loaded once! (It is already loaded)"

        # Assign the scene first.
        self._scene = scene
        self._scene_assigned = True

        # Then check if the prim is already loaded
        if lazy.omni.isaac.core.utils.prims.is_prim_path_valid(prim_path=self.prim_path):
            # TODO(parallel-hang): make this more descriptive
            log.debug(f"prim {self.name} already exists, skipping load")
            self._prim = lazy.omni.isaac.core.utils.prims.get_prim_at_path(prim_path=self.prim_path)
        else:
            # If not, we'll load it.
            self._prim = self._load()

        # Mark the prim as loaded.
        self._loaded = True

        # Run any post-loading logic
        self._post_load()

        return self._prim

    def _post_load(self):
        """
        Any actions that should be taken (e.g.: modifying the object's properties such as scale, visibility, additional
        joints, etc.) that should be taken after loading the raw object into omniverse but BEFORE we initialize the
        object and grab its handles and internal references. By default, this is a no-op.
        """
        pass

    def remove(self):
        """
        Removes this prim from omniverse stage.
        """
        if not self._loaded:
            raise ValueError("Cannot remove a prim that was never loaded.")

        # Remove or deactivate prim if it's possible
        if not delete_or_deactivate_prim(self.prim_path):
            log.warning(f"Prim {self.name} at prim_path {self.prim_path} could not be deleted or deactivated.")

    def _load(self):
        """
        Loads the raw prim into the simulator. Any post-processing should be done in @self._post_load()
        """
        raise NotImplementedError()

    @property
    def loaded(self):
        return self._loaded

    @property
    def initialized(self):
        return self._initialized

    @property
    def scene(self):
        """
        Returns:
            Scene or None: Scene object that this prim is loaded into
        """
        assert self._scene_assigned, "Scene has not been assigned to this prim yet!"
        return self._scene

    @property
    def state_size(self):
        # This is the cached value
        return self._state_size

    @property
    def prim_path(self):
        """
        Returns:
            str: prim path in the stage.
        """
        return scene_relative_prim_path_to_absolute(self.scene, self._relative_prim_path)

    @property
    def name(self):
        """
        Returns:
            str: unique name assigned to this prim
        """
        return self._name

    @property
    def prim(self):
        """
        Returns:
            Usd.Prim: USD Prim object that this object holds.
        """
        return self._prim

    @property
    def property_names(self):
        """
        Returns:
            set of str: Set of property names that this prim has (e.g.: visibility, proxyPrim, etc.)
        """
        return set(self._prim.GetPropertyNames())

    @property
    def visible(self):
        """
        Returns:
            bool: true if the prim is visible in stage. false otherwise.
        """
        return (
            lazy.pxr.UsdGeom.Imageable(self.prim).ComputeVisibility(lazy.pxr.Usd.TimeCode.Default())
            != lazy.pxr.UsdGeom.Tokens.invisible
        )

    @visible.setter
    def visible(self, visible):
        """
        Sets the visibility of the prim in stage.

        Args:
            visible (bool): flag to set the visibility of the usd prim in stage.
        """
        imageable = lazy.pxr.UsdGeom.Imageable(self.prim)
        if visible:
            imageable.MakeVisible()
        else:
            imageable.MakeInvisible()
        return

    def is_valid(self):
        """
        Returns:
            bool: True is the current prim path corresponds to a valid prim in stage. False otherwise.
        """
        return lazy.omni.isaac.core.utils.prims.is_prim_path_valid(self.prim_path)

    def get_attribute(self, attr):
        """
        Get this prim's attribute. Should be a valid attribute under self._prim.GetAttributes()

        Returns:
            any: value of the requested @attribute
        """
        return self._prim.GetAttribute(attr).Get()

    def set_attribute(self, attr, val):
        """
        Set this prim's attribute. Should be a valid attribute under self._prim.GetAttributes()

        Args:
            attr (str): Attribute to set
            val (any): Value to set for the attribute. This should be the valid type for that attribute.
        """
        self._prim.GetAttribute(attr).Set(val)

    def get_property(self, prop):
        """
        Sets property @prop with value @val

        Args:
            prop (str): Name of the property to get. See Raw USD Properties in the GUI for examples of property names

        Returns:
            any: Property value
        """
        self._prim.GetProperty(prop).Get()

    def set_property(self, prop, val):
        """
        Sets property @prop with value @val

        Args:
            prop (str): Name of the property to set. See Raw USD Properties in the GUI for examples of property names
            val (any): Value to set for the property. Should be valid for that property
        """
        self._prim.GetProperty(prop).Set(val)

    def get_custom_data(self):
        """
        Get custom data associated with this prim

        Returns:
            dict: Dictionary of any custom information
        """
        return self._prim.GetCustomData()

    def _create_prim_with_same_kwargs(self, relative_prim_path, name, load_config):
        """
        Generates a new instance of this prim's class with specified @relative_prim_path, @name, and @load_config, but otherwise
        all other kwargs should be identical to this instance's values.

        Args:
            relative_prim_path (str): Scene-local prim path of the Prim to encapsulate or create.
            name (str): Name for the newly created prim
            load_config (dict): Keyword-mapped kwargs to use to set specific attributes for the created prim's instance

        Returns:
            BasePrim: Generated prim object (not loaded, and not initialized!)
        """
        return self.__class__(
            relative_prim_path=relative_prim_path,
            name=name,
            load_config=load_config,
        )

name property

Returns:

Type Description
str

unique name assigned to this prim

prim property

Returns:

Type Description
Prim

USD Prim object that this object holds.

prim_path property

Returns:

Type Description
str

prim path in the stage.

property_names property

Returns:

Type Description
set of str

Set of property names that this prim has (e.g.: visibility, proxyPrim, etc.)

scene property

Returns:

Type Description
Scene or None

Scene object that this prim is loaded into

visible property writable

Returns:

Type Description
bool

true if the prim is visible in stage. false otherwise.

get_attribute(attr)

Get this prim's attribute. Should be a valid attribute under self._prim.GetAttributes()

Returns:

Type Description
any

value of the requested @attribute

Source code in omnigibson/prims/prim_base.py
def get_attribute(self, attr):
    """
    Get this prim's attribute. Should be a valid attribute under self._prim.GetAttributes()

    Returns:
        any: value of the requested @attribute
    """
    return self._prim.GetAttribute(attr).Get()

get_custom_data()

Get custom data associated with this prim

Returns:

Type Description
dict

Dictionary of any custom information

Source code in omnigibson/prims/prim_base.py
def get_custom_data(self):
    """
    Get custom data associated with this prim

    Returns:
        dict: Dictionary of any custom information
    """
    return self._prim.GetCustomData()

get_property(prop)

Sets property @prop with value @val

Parameters:

Name Type Description Default
prop str

Name of the property to get. See Raw USD Properties in the GUI for examples of property names

required

Returns:

Type Description
any

Property value

Source code in omnigibson/prims/prim_base.py
def get_property(self, prop):
    """
    Sets property @prop with value @val

    Args:
        prop (str): Name of the property to get. See Raw USD Properties in the GUI for examples of property names

    Returns:
        any: Property value
    """
    self._prim.GetProperty(prop).Get()

initialize()

Initializes state of this object and sets up any references necessary post-loading. Subclasses should implement / extend the _initialize() method.

Source code in omnigibson/prims/prim_base.py
def initialize(self):
    """
    Initializes state of this object and sets up any references necessary post-loading. Subclasses should
    implement / extend the _initialize() method.
    """
    assert (
        not self._initialized
    ), f"Prim {self.name} at prim_path {self.prim_path} can only be initialized once! (It is already initialized)"
    self._initialize()

    self._initialized = True

    # Cache state size (note that we are doing this after initialized is set to True because
    # dump_state asserts that the prim is initialized for some prims).
    self._state_size = len(self.dump_state(serialized=True))

is_valid()

Returns:

Type Description
bool

True is the current prim path corresponds to a valid prim in stage. False otherwise.

Source code in omnigibson/prims/prim_base.py
def is_valid(self):
    """
    Returns:
        bool: True is the current prim path corresponds to a valid prim in stage. False otherwise.
    """
    return lazy.omni.isaac.core.utils.prims.is_prim_path_valid(self.prim_path)

load(scene)

Load this prim into omniverse, and return loaded prim reference.

Returns:

Type Description
Prim

Prim object loaded into the simulator

Source code in omnigibson/prims/prim_base.py
def load(self, scene):
    """
    Load this prim into omniverse, and return loaded prim reference.

    Returns:
        Usd.Prim: Prim object loaded into the simulator
    """
    # Load the prim if it doesn't exist yet.
    assert (
        not self._loaded
    ), f"Prim {self.name} at prim_path {self.prim_path} can only be loaded once! (It is already loaded)"

    # Assign the scene first.
    self._scene = scene
    self._scene_assigned = True

    # Then check if the prim is already loaded
    if lazy.omni.isaac.core.utils.prims.is_prim_path_valid(prim_path=self.prim_path):
        # TODO(parallel-hang): make this more descriptive
        log.debug(f"prim {self.name} already exists, skipping load")
        self._prim = lazy.omni.isaac.core.utils.prims.get_prim_at_path(prim_path=self.prim_path)
    else:
        # If not, we'll load it.
        self._prim = self._load()

    # Mark the prim as loaded.
    self._loaded = True

    # Run any post-loading logic
    self._post_load()

    return self._prim

remove()

Removes this prim from omniverse stage.

Source code in omnigibson/prims/prim_base.py
def remove(self):
    """
    Removes this prim from omniverse stage.
    """
    if not self._loaded:
        raise ValueError("Cannot remove a prim that was never loaded.")

    # Remove or deactivate prim if it's possible
    if not delete_or_deactivate_prim(self.prim_path):
        log.warning(f"Prim {self.name} at prim_path {self.prim_path} could not be deleted or deactivated.")

set_attribute(attr, val)

Set this prim's attribute. Should be a valid attribute under self._prim.GetAttributes()

Parameters:

Name Type Description Default
attr str

Attribute to set

required
val any

Value to set for the attribute. This should be the valid type for that attribute.

required
Source code in omnigibson/prims/prim_base.py
def set_attribute(self, attr, val):
    """
    Set this prim's attribute. Should be a valid attribute under self._prim.GetAttributes()

    Args:
        attr (str): Attribute to set
        val (any): Value to set for the attribute. This should be the valid type for that attribute.
    """
    self._prim.GetAttribute(attr).Set(val)

set_property(prop, val)

Sets property @prop with value @val

Parameters:

Name Type Description Default
prop str

Name of the property to set. See Raw USD Properties in the GUI for examples of property names

required
val any

Value to set for the property. Should be valid for that property

required
Source code in omnigibson/prims/prim_base.py
def set_property(self, prop, val):
    """
    Sets property @prop with value @val

    Args:
        prop (str): Name of the property to set. See Raw USD Properties in the GUI for examples of property names
        val (any): Value to set for the property. Should be valid for that property
    """
    self._prim.GetProperty(prop).Set(val)