Unverified Commit 8c5a0697 authored by Mayank Mittal's avatar Mayank Mittal Committed by GitHub

Fixes the terrain importer to use the new spawning functions for materials (#118)

# Description

This MR allows coloring a mesh using its vertex colors. Right now it
only demonstrates how to do this based on height but one could use it in
more creative ways. For example, coloring boxes in a different color.

It also updates the `TerrainImporter` to use the visual and physics
material configuration classes.

## Type of change

- New feature (non-breaking change which adds functionality)
- This change requires a documentation update

## Screenshots

| Random Color | Color by Height |
| ------ | ----- |
|
![color](https://github.com/isaac-orbit/orbit/assets/12863862/b2c8fa13-aa6f-44ff-a195-509d422a62b6)
|
![tough](https://github.com/isaac-orbit/orbit/assets/12863862/edc14879-8f14-4ebd-9578-a7eaa26eae26)
|

## Checklist

- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./orbit.sh --format`
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
parent 6442cef5
[package] [package]
# Note: Semantic Versioning is used: https://semver.org/ # Note: Semantic Versioning is used: https://semver.org/
version = "0.9.1" version = "0.9.2"
# Description # Description
title = "ORBIT framework for Robot Learning" title = "ORBIT framework for Robot Learning"
......
Changelog Changelog
--------- ---------
0.9.2 (2023-08-22)
~~~~~~~~~~~~~~~~~~~
Added
^^^^^
* Added the ability to color meshes in the :class:`omni.isaac.orbit.terrain.TerrainGenerator` class. Currently,
it only supports coloring the mesh randomly (``"random"``), based on the terrain height (``"height"``), and
no coloring (``"none"``).
Fixed
^^^^^
* Modified the :class:`omni.isaac.orbit.terrain.TerrainImporter` class to configure visual and physics materials
based on the configuration object.
0.9.1 (2023-08-18) 0.9.1 (2023-08-18)
~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~
......
...@@ -172,18 +172,18 @@ def spawn_ground_plane(prim_path: str, cfg: from_files_cfg.GroundPlaneCfg, **kwa ...@@ -172,18 +172,18 @@ def spawn_ground_plane(prim_path: str, cfg: from_files_cfg.GroundPlaneCfg, **kwa
# Create physics material # Create physics material
if cfg.physics_material is not None: if cfg.physics_material is not None:
cfg.physics_material.func(f"{prim_path}/groundMaterial", cfg.physics_material) cfg.physics_material.func(f"{prim_path}/physicsMaterial", cfg.physics_material)
# Apply physics material to ground plane # Apply physics material to ground plane
collision_prim_path = prim_utils.get_prim_path( collision_prim_path = prim_utils.get_prim_path(
prim_utils.get_first_matching_child_prim( prim_utils.get_first_matching_child_prim(
prim_path, predicate=lambda x: prim_utils.get_prim_type_name(x) == "Plane" prim_path, predicate=lambda x: prim_utils.get_prim_type_name(x) == "Plane"
) )
) )
bind_physics_material(collision_prim_path, f"{prim_path}/groundMaterial") bind_physics_material(collision_prim_path, f"{prim_path}/physicsMaterial")
# Scale only the mesh # Scale only the mesh
# Warning: This is specific to the default grid plane asset. # Warning: This is specific to the default grid plane asset.
if cfg.size is not None and prim_utils.is_prim_path_valid(f"{prim_path}/Enviroment"): if prim_utils.is_prim_path_valid(f"{prim_path}/Enviroment"):
# compute scale from size # compute scale from size
scale = (cfg.size[0] / 100.0, cfg.size[1] / 100.0, 1.0) scale = (cfg.size[0] / 100.0, cfg.size[1] / 100.0, 1.0)
# apply scale to the mesh # apply scale to the mesh
......
...@@ -72,7 +72,7 @@ class GroundPlaneCfg(SpawnerCfg): ...@@ -72,7 +72,7 @@ class GroundPlaneCfg(SpawnerCfg):
If None, then the color remains unchanged. If None, then the color remains unchanged.
""" """
size: tuple[float, float] | None = None size: tuple[float, float] = (100.0, 100.0)
"""The size of the ground plane. Defaults to None, which is 100 m x 100 m.""" """The size of the ground plane. Defaults to 100 m x 100 m."""
physics_material: materials.RigidBodyMaterialCfg = materials.RigidBodyMaterialCfg() physics_material: materials.RigidBodyMaterialCfg = materials.RigidBodyMaterialCfg()
"""Physics material properties. Defaults to the default rigid body material.""" """Physics material properties. Defaults to the default rigid body material."""
...@@ -16,6 +16,7 @@ from omni.isaac.orbit.utils.timer import Timer ...@@ -16,6 +16,7 @@ from omni.isaac.orbit.utils.timer import Timer
from .height_field import HfTerrainBaseCfg from .height_field import HfTerrainBaseCfg
from .terrain_generator_cfg import SubTerrainBaseCfg, TerrainGeneratorCfg from .terrain_generator_cfg import SubTerrainBaseCfg, TerrainGeneratorCfg
from .trimesh.utils import make_border from .trimesh.utils import make_border
from .utils import color_meshes_by_height
class TerrainGenerator: class TerrainGenerator:
...@@ -92,6 +93,17 @@ class TerrainGenerator: ...@@ -92,6 +93,17 @@ class TerrainGenerator:
self._add_terrain_border() self._add_terrain_border()
# combine all the sub-terrains into a single mesh # combine all the sub-terrains into a single mesh
self.terrain_mesh = trimesh.util.concatenate(self.terrain_meshes) self.terrain_mesh = trimesh.util.concatenate(self.terrain_meshes)
# color the terrain mesh
if self.cfg.color_scheme == "height":
self.terrain_mesh = color_meshes_by_height(self.terrain_mesh)
elif self.cfg.color_scheme == "random":
self.terrain_mesh.visual.vertex_colors = np.random.choice(
range(256), size=(len(self.terrain_mesh.vertices), 4)
)
elif self.cfg.color_scheme == "none":
pass
else:
raise ValueError(f"Invalid color scheme: {self.cfg.color_scheme}.")
# offset the entire terrain and origins so that it is centered # offset the entire terrain and origins so that it is centered
# -- terrain mesh # -- terrain mesh
transform = np.eye(4) transform = np.eye(4)
......
...@@ -18,6 +18,7 @@ import numpy as np ...@@ -18,6 +18,7 @@ import numpy as np
import trimesh import trimesh
from dataclasses import MISSING from dataclasses import MISSING
from typing import Callable from typing import Callable
from typing_extensions import Literal
from omni.isaac.orbit.utils import configclass from omni.isaac.orbit.utils import configclass
...@@ -85,6 +86,16 @@ class TerrainGeneratorCfg: ...@@ -85,6 +86,16 @@ class TerrainGeneratorCfg:
num_cols: int = 1 num_cols: int = 1
"""Number of columns of sub-terrains to generate. Defaults to 1.""" """Number of columns of sub-terrains to generate. Defaults to 1."""
color_scheme: Literal["height", "random", "none"] = "none"
"""Color scheme to use for the terrain. Defaults to "none".
The available color schemes are:
- "height": Color based on the height of the terrain.
- "random": Random color scheme.
- "none": No color scheme.
"""
horizontal_scale: float = 0.1 horizontal_scale: float = 0.1
"""The discretization of the terrain along the x and y axes (in m). Defaults to 0.1. """The discretization of the terrain along the x and y axes (in m). Defaults to 0.1.
......
...@@ -15,9 +15,9 @@ import warp ...@@ -15,9 +15,9 @@ import warp
from omni.isaac.core.simulation_context import SimulationContext from omni.isaac.core.simulation_context import SimulationContext
from pxr import UsdGeom from pxr import UsdGeom
import omni.isaac.orbit.sim as sim_utils
from omni.isaac.orbit.markers import VisualizationMarkers from omni.isaac.orbit.markers import VisualizationMarkers
from omni.isaac.orbit.markers.config import FRAME_MARKER_CFG from omni.isaac.orbit.markers.config import FRAME_MARKER_CFG
from omni.isaac.orbit.utils.kit import create_ground_plane
from omni.isaac.orbit.utils.warp import convert_to_warp_mesh from omni.isaac.orbit.utils.warp import convert_to_warp_mesh
from .terrain_generator import TerrainGenerator from .terrain_generator import TerrainGenerator
...@@ -110,7 +110,7 @@ class TerrainImporter: ...@@ -110,7 +110,7 @@ class TerrainImporter:
Operations - Import. Operations - Import.
""" """
def import_ground_plane(self, key: str, size: tuple[int, int] = (2.0e6, 2.0e6), **kwargs): def import_ground_plane(self, key: str, size: tuple[int, int] = (2.0e6, 2.0e6)):
"""Add a plane to the terrain importer. """Add a plane to the terrain importer.
Args: Args:
...@@ -131,21 +131,11 @@ class TerrainImporter: ...@@ -131,21 +131,11 @@ class TerrainImporter:
device = "cuda" if "cuda" in self.device else "cpu" device = "cuda" if "cuda" in self.device else "cpu"
self.warp_meshes[key] = convert_to_warp_mesh(mesh.vertices, mesh.faces, device=device) self.warp_meshes[key] = convert_to_warp_mesh(mesh.vertices, mesh.faces, device=device)
# properties for the terrain # get the mesh
mesh_props = { ground_plane_cfg = sim_utils.GroundPlaneCfg(physics_material=self.cfg.physics_material)
"color": self.cfg.color, ground_plane_cfg.func(self.cfg.prim_path, ground_plane_cfg)
"static_friction": self.cfg.static_friction,
"dynamic_friction": self.cfg.dynamic_friction, def import_mesh(self, key: str, mesh: trimesh.Trimesh):
"restitution": self.cfg.restitution,
"improve_patch_friction": self.cfg.improve_patch_friction,
"combine_mode": self.cfg.combine_mode,
}
# update the properties
mesh_props.update(kwargs)
# import the grid mesh
create_ground_plane(self.cfg.prim_path, **mesh_props)
def import_mesh(self, key: str, mesh: trimesh.Trimesh, **kwargs):
"""Import a mesh into the simulator. """Import a mesh into the simulator.
The mesh is imported into the simulator under the prim path ``cfg.prim_path/{key}``. The created path The mesh is imported into the simulator under the prim path ``cfg.prim_path/{key}``. The created path
...@@ -154,7 +144,6 @@ class TerrainImporter: ...@@ -154,7 +144,6 @@ class TerrainImporter:
Args: Args:
key (str): The key to store the mesh. key (str): The key to store the mesh.
mesh (trimesh.Trimesh): The mesh to import. mesh (trimesh.Trimesh): The mesh to import.
**kwargs: The properties of the mesh. If not provided, the default properties are used.
Raises: Raises:
ValueError: If a terrain with the same key already exists. ValueError: If a terrain with the same key already exists.
...@@ -171,19 +160,13 @@ class TerrainImporter: ...@@ -171,19 +160,13 @@ class TerrainImporter:
# get the mesh # get the mesh
mesh = self.meshes[key] mesh = self.meshes[key]
mesh_prim_path = self.cfg.prim_path + f"/{key}" mesh_prim_path = self.cfg.prim_path + f"/{key}"
# properties for the terrain
mesh_props = {
"color": self.cfg.color,
"static_friction": self.cfg.static_friction,
"dynamic_friction": self.cfg.dynamic_friction,
"restitution": self.cfg.restitution,
"improve_patch_friction": self.cfg.improve_patch_friction,
"combine_mode": self.cfg.combine_mode,
}
# update the properties
mesh_props.update(kwargs)
# import the mesh # import the mesh
create_prim_from_mesh(mesh_prim_path, mesh.vertices, mesh.faces, **mesh_props) create_prim_from_mesh(
mesh_prim_path,
mesh,
visual_material=self.cfg.visual_material,
physics_material=self.cfg.physics_material,
)
def import_usd(self, key: str, usd_path: str): def import_usd(self, key: str, usd_path: str):
"""Import a mesh from a USD file. """Import a mesh from a USD file.
...@@ -208,6 +191,7 @@ class TerrainImporter: ...@@ -208,6 +191,7 @@ class TerrainImporter:
raise ValueError(f"Mesh with key {key} already exists. Existing keys: {self.meshes.keys()}.") raise ValueError(f"Mesh with key {key} already exists. Existing keys: {self.meshes.keys()}.")
# add the prim path # add the prim path
prim_utils.create_prim(self.cfg.prim_path + f"/{key}", usd_path=usd_path) prim_utils.create_prim(self.cfg.prim_path + f"/{key}", usd_path=usd_path)
# traverse the prim and get the collision mesh # traverse the prim and get the collision mesh
# THINK: Should the user specify the collision mesh? # THINK: Should the user specify the collision mesh?
mesh_prim = prim_utils.get_first_matching_child_prim( mesh_prim = prim_utils.get_first_matching_child_prim(
......
...@@ -9,6 +9,7 @@ from dataclasses import MISSING ...@@ -9,6 +9,7 @@ from dataclasses import MISSING
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import Literal from typing_extensions import Literal
import omni.isaac.orbit.sim as sim_utils
from omni.isaac.orbit.utils import configclass from omni.isaac.orbit.utils import configclass
from .terrain_importer import TerrainImporter from .terrain_importer import TerrainImporter
...@@ -24,6 +25,9 @@ class TerrainImporterCfg: ...@@ -24,6 +25,9 @@ class TerrainImporterCfg:
cls_name: type = TerrainImporter cls_name: type = TerrainImporter
"""The class name of the terrain importer.""" """The class name of the terrain importer."""
collision_group: int = -1
"""The collision group of the terrain. Defaults to -1."""
prim_path: str = MISSING prim_path: str = MISSING
"""The absolute path of the USD terrain prim. """The absolute path of the USD terrain prim.
...@@ -58,28 +62,24 @@ class TerrainImporterCfg: ...@@ -58,28 +62,24 @@ class TerrainImporterCfg:
This parameter is used only when the ``terrain_type`` is ``"plane"`` or ``"usd"``. This parameter is used only when the ``terrain_type`` is ``"plane"`` or ``"usd"``.
""" """
color: tuple[float, float, float] | None = (0.065, 0.0725, 0.080) visual_material: sim_utils.VisualMaterialCfg | None = sim_utils.PreviewSurfaceCfg(
"""The color of the terrain. Defaults to (0.065, 0.0725, 0.080). diffuse_color=(0.065, 0.0725, 0.080)
)
If :obj:`None`, no color is applied to the prim. """The visual material of the terrain. Defaults to a dark gray color material.
"""
static_friction: float = 1.0 The material is created at the path: ``{prim_path}/visualMaterial``. If `None`, then no material is created.
"""The static friction coefficient of the terrain. Defaults to 1.0."""
dynamic_friction: float = 1.0 .. note::
"""The dynamic friction coefficient of the terrain. Defaults to 1.0.""" This parameter is used only when the ``terrain_type`` is ``"generator"``.
"""
restitution: float = 0.0
"""The restitution coefficient of the terrain. Defaults to 0.0."""
improve_patch_friction: bool = False physics_material: sim_utils.RigidBodyMaterialCfg = sim_utils.RigidBodyMaterialCfg()
"""Whether to enable patch friction. Defaults to False.""" """The physics material of the terrain. Defaults to a default physics material.
combine_mode: str = "average" The material is created at the path: ``{prim_path}/physicsMaterial``.
"""Determines the way physics materials will be combined during collisions. Defaults to `average`.
Available options are `average`, `min`, `multiply`, `multiply`, and `max`. .. note::
This parameter is used only when the ``terrain_type`` is ``"generator"`` or ``"plane"``.
""" """
max_init_terrain_level: int | None = None max_init_terrain_level: int | None = None
......
...@@ -20,6 +20,7 @@ def color_meshes_by_height(meshes: List[trimesh.Trimesh], **kwargs) -> trimesh.T ...@@ -20,6 +20,7 @@ def color_meshes_by_height(meshes: List[trimesh.Trimesh], **kwargs) -> trimesh.T
Keyword Args: Keyword Args:
color (List[int]): A list of 3 integers in the range [0,255] representing the RGB color (List[int]): A list of 3 integers in the range [0,255] representing the RGB
color of the mesh. Used when the z-coordinates of all vertices are the same. color of the mesh. Used when the z-coordinates of all vertices are the same.
color_map (str): The name of the color map to be used. Defaults to "turbo".
Returns: Returns:
trimesh.Trimesh: A trimesh object with the vertices colored based on the z-coordinate (height) of each vertex. trimesh.Trimesh: A trimesh object with the vertices colored based on the z-coordinate (height) of each vertex.
...@@ -38,15 +39,18 @@ def color_meshes_by_height(meshes: List[trimesh.Trimesh], **kwargs) -> trimesh.T ...@@ -38,15 +39,18 @@ def color_meshes_by_height(meshes: List[trimesh.Trimesh], **kwargs) -> trimesh.T
else: else:
# Normalize the heights to [0,1] # Normalize the heights to [0,1]
heights_normalized = (heights - np.min(heights)) / (np.max(heights) - np.min(heights)) heights_normalized = (heights - np.min(heights)) / (np.max(heights) - np.min(heights))
# clip lower and upper bounds to have better color mapping
heights_normalized = np.clip(heights_normalized, 0.1, 0.9)
# Get the color for each vertex based on the height # Get the color for each vertex based on the height
colors = trimesh.visual.color.interpolate(heights_normalized, color_map="turbo") color_map = kwargs.pop("color_map", "turbo")
colors = trimesh.visual.color.interpolate(heights_normalized, color_map=color_map)
# Set the vertex colors # Set the vertex colors
mesh.visual.vertex_colors = colors mesh.visual.vertex_colors = colors
# Return the mesh # Return the mesh
return mesh return mesh
def create_prim_from_mesh(prim_path: str, vertices: np.ndarray, triangles: np.ndarray, **kwargs): def create_prim_from_mesh(prim_path: str, mesh: trimesh.Trimesh, **kwargs):
"""Create a USD prim with mesh defined from vertices and triangles. """Create a USD prim with mesh defined from vertices and triangles.
The function creates a USD prim with a mesh defined from vertices and triangles. It performs the The function creates a USD prim with a mesh defined from vertices and triangles. It performs the
...@@ -59,67 +63,62 @@ def create_prim_from_mesh(prim_path: str, vertices: np.ndarray, triangles: np.nd ...@@ -59,67 +63,62 @@ def create_prim_from_mesh(prim_path: str, vertices: np.ndarray, triangles: np.nd
Args: Args:
prim_path (str): The path to the primitive to be created. prim_path (str): The path to the primitive to be created.
vertices (np.ndarray): The vertices of the mesh. Shape is :math:`(N, 3)`, where :math:`N` mesh (trimesh.Trimesh): The mesh to be used for the primitive.
is the number of vertices.
triangles (np.ndarray): The triangles of the mesh as references to vertices for each triangle.
Shape is :math:`(M, 3)`, where :math:`M` is the number of triangles / faces.
Keyword Args: Keyword Args:
translation (Optional[Sequence[float]]): The translation of the terrain. Defaults to None. translation (Optional[Sequence[float]]): The translation of the terrain. Defaults to None.
orientation (Optional[Sequence[float]]): The orientation of the terrain. Defaults to None. orientation (Optional[Sequence[float]]): The orientation of the terrain. Defaults to None.
scale (Optional[Sequence[float]]): The scale of the terrain. Defaults to None. visual_material (Optional[sim_utils.VisualMaterialCfg]): The visual material to apply. Defaults to None.
color (Optional[tuple]): The color of the terrain. Defaults to (0.065, 0.0725, 0.080). physics_material (Optional[sim_utils.RigidBodyMaterialCfg]): The physics material to apply. Defaults to None.
static_friction (float): The static friction of the terrain. Defaults to 1.0.
dynamic_friction (float): The dynamic friction of the terrain. Defaults to 1.0.
restitution (float): The restitution of the terrain. Defaults to 0.0.
improve_patch_friction (bool): Whether to enable patch friction. Defaults to False.
combine_mode (str): Determines the way physics materials will be combined during collisions.
Available options are `average`, `min`, `multiply`, `multiply`, and `max`. Defaults to `average`.
""" """
# need to import these here to prevent isaacsim launching when importing this module # need to import these here to prevent isaacsim launching when importing this module
import omni.isaac.core.utils.prims as prim_utils import omni.isaac.core.utils.prims as prim_utils
from omni.isaac.core.materials import PhysicsMaterial, PreviewSurface from pxr import UsdGeom
from omni.isaac.core.prims import GeometryPrim, XFormPrim
from pxr import PhysxSchema import omni.isaac.orbit.sim as sim_utils
# create parent prim # create parent prim
prim_utils.create_prim(prim_path, "Xform") prim_utils.create_prim(prim_path, "Xform")
# create mesh prim # create mesh prim
prim_utils.create_prim( prim = prim_utils.create_prim(
f"{prim_path}/mesh", f"{prim_path}/mesh",
"Mesh", "Mesh",
translation=kwargs.get("translation"), translation=kwargs.get("translation"),
orientation=kwargs.get("orientation"), orientation=kwargs.get("orientation"),
scale=kwargs.get("scale"),
attributes={ attributes={
"points": vertices, "points": mesh.vertices,
"faceVertexIndices": triangles.flatten(), "faceVertexIndices": mesh.faces.flatten(),
"faceVertexCounts": np.asarray([3] * len(triangles)), "faceVertexCounts": np.asarray([3] * len(mesh.faces)),
"subdivisionScheme": "bilinear", "subdivisionScheme": "bilinear",
}, },
) )
# apply collider properties
collider_cfg = sim_utils.CollisionPropertiesCfg(collision_enabled=True)
sim_utils.define_collision_properties(prim.GetPrimPath(), collider_cfg)
# add rgba color to the mesh primvars
if mesh.visual.vertex_colors is not None:
# obtain color from the mesh
rgba_colors = np.asarray(mesh.visual.vertex_colors).astype(np.float32) / 255.0
# displayColor is a primvar attribute that is used to color the mesh
color_prim_attr = prim.GetAttribute("primvars:displayColor")
color_prim_var = UsdGeom.Primvar(color_prim_attr)
color_prim_var.SetInterpolation(UsdGeom.Tokens.vertex)
color_prim_attr.Set(rgba_colors[:, :3])
# displayOpacity is a primvar attribute that is used to set the opacity of the mesh
display_prim_attr = prim.GetAttribute("primvars:displayOpacity")
display_prim_var = UsdGeom.Primvar(display_prim_attr)
display_prim_var.SetInterpolation(UsdGeom.Tokens.vertex)
display_prim_var.Set(rgba_colors[:, 3])
# create visual material # create visual material
color = kwargs.get("color", (0.065, 0.0725, 0.080)) if kwargs.get("visual_material") is not None:
if color is not None: visual_material_cfg: sim_utils.VisualMaterialCfg = kwargs.get("visual_material")
material = PreviewSurface(f"{prim_path}/visualMaterial", color=np.asarray(color)) # spawn the material
XFormPrim(f"{prim_path}/mesh").apply_visual_material(material) visual_material_cfg.func(f"{prim_path}/visualMaterial", visual_material_cfg)
sim_utils.bind_visual_material(prim.GetPrimPath(), f"{prim_path}/visualMaterial")
# create physics material # create physics material
material = PhysicsMaterial( if kwargs.get("physics_material") is not None:
f"{prim_path}/physicsMaterial", physics_material_cfg: sim_utils.RigidBodyMaterialCfg = kwargs.get("physics_material")
static_friction=kwargs.get("static_friction", 1.0), # spawn the material
dynamic_friction=kwargs.get("dynamic_friction", 1.0), physics_material_cfg.func(f"{prim_path}/physicsMaterial", physics_material_cfg)
restitution=kwargs.get("restitution", 0.0), sim_utils.bind_physics_material(prim.GetPrimPath(), f"{prim_path}/physicsMaterial")
)
# apply PhysX Rigid Material schema
physx_material_api = PhysxSchema.PhysxMaterialAPI.Apply(material.prim)
# set patch friction property
improve_patch_friction = kwargs.get("improve_patch_friction", False)
physx_material_api.CreateImprovePatchFrictionAttr().Set(improve_patch_friction)
# set combination mode for coefficients
combine_mode = kwargs.get("combine_mode", "multiply")
physx_material_api.CreateFrictionCombineModeAttr().Set(combine_mode)
physx_material_api.CreateRestitutionCombineModeAttr().Set(combine_mode)
# apply physics material to ground plane
GeometryPrim(f"{prim_path}/mesh", collision=True).apply_physics_material(material)
...@@ -39,9 +39,17 @@ parser.add_argument("--geom_sphere", action="store_true", default=False, help="W ...@@ -39,9 +39,17 @@ parser.add_argument("--geom_sphere", action="store_true", default=False, help="W
parser.add_argument( parser.add_argument(
"--terrain_type", "--terrain_type",
type=str, type=str,
choices=["generated", "usd", "plane"],
default="generator", default="generator",
help="Type of terrain to import. Can be 'generated' or 'usd' or 'plane'.", help="Type of terrain to import. Can be 'generated' or 'usd' or 'plane'.",
) )
parser.add_argument(
"--color_scheme",
type=str,
default="height",
choices=["height", "random", "none"],
help="The color scheme to use for the generated terrain.",
)
args_cli = parser.parse_args() args_cli = parser.parse_args()
# launch omniverse app # launch omniverse app
...@@ -69,7 +77,7 @@ from omni.isaac.orbit.terrains.terrain_importer import TerrainImporter ...@@ -69,7 +77,7 @@ from omni.isaac.orbit.terrains.terrain_importer import TerrainImporter
from omni.isaac.orbit.utils.assets import ISAAC_NUCLEUS_DIR from omni.isaac.orbit.utils.assets import ISAAC_NUCLEUS_DIR
def main(terrain_type: str): def main():
"""Generates a terrain from orbit.""" """Generates a terrain from orbit."""
# Load kit helper # Load kit helper
...@@ -100,8 +108,8 @@ def main(terrain_type: str): ...@@ -100,8 +108,8 @@ def main(terrain_type: str):
env_spacing=3.0, env_spacing=3.0,
prim_path="/World/ground", prim_path="/World/ground",
max_init_terrain_level=None, max_init_terrain_level=None,
terrain_type=terrain_type, terrain_type=args_cli.terrain_type,
terrain_generator=ROUGH_TERRAINS_CFG.replace(curriculum=True), terrain_generator=ROUGH_TERRAINS_CFG.replace(curriculum=True, color_scheme=args_cli.color_scheme),
usd_path=f"{ISAAC_NUCLEUS_DIR}/Environments/Terrains/rough_plane.usd", usd_path=f"{ISAAC_NUCLEUS_DIR}/Environments/Terrains/rough_plane.usd",
) )
terrain_importer = TerrainImporter(terrain_importer_cfg) terrain_importer = TerrainImporter(terrain_importer_cfg)
...@@ -191,6 +199,6 @@ def main(terrain_type: str): ...@@ -191,6 +199,6 @@ def main(terrain_type: str):
if __name__ == "__main__": if __name__ == "__main__":
# Runs the main function # Runs the main function
main(terrain_type=args_cli.terrain_type) main()
# Close the simulator # Close the simulator
simulation_app.close() simulation_app.close()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment