Commit e787e9bf authored by Kyle Morgenstein's avatar Kyle Morgenstein Committed by Mayank Mittal

Supports setting the ground plane color using the terrain importer (#1791)

The default plane configuration supports setting the plane color, but
this option is not currently exposed via the terrain importer. This PR
adds a ``color'' field to the terrain importer that is only used for
configuring a plane.

- New feature (non-breaking change which adds functionality)

<img width="912" alt="image"
src="https://github.com/user-attachments/assets/4e509270-a953-49e8-88e7-b67bc1a92d2c"
/>

<img width="909" alt="image"
src="https://github.com/user-attachments/assets/0aa77530-befe-4c30-991d-e668561b9793"
/>

Configuration:

```python
terrain = TerrainImporterCfg(
            prim_path="/World/ground",
            terrain_type="plane",
            terrain_generator=None,
            max_init_terrain_level=None,
            collision_group=-1,
            physics_material=sim_utils.RigidBodyMaterialCfg(
                friction_combine_mode="multiply",
                restitution_combine_mode="multiply",
                static_friction=1.0,
                dynamic_friction=1.0,
            ),
            color=(1.0, 0.0, 0.0), # Red
            debug_vis=False,
        )
```

- [ ] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.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
- [ ] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [X] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there

---------
Signed-off-by: 's avatarKyle Morgenstein <34984693+KyleM73@users.noreply.github.com>
Signed-off-by: 's avatarMayank Mittal <12863862+Mayankm96@users.noreply.github.com>
Co-authored-by: 's avatarMayank Mittal <12863862+Mayankm96@users.noreply.github.com>
parent ae6c5f6c
......@@ -10,6 +10,7 @@ import torch
import trimesh
from typing import TYPE_CHECKING
import omni.log
import warp
from pxr import UsdGeom
......@@ -196,9 +197,21 @@ class TerrainImporter:
# create a warp mesh
device = "cuda" if "cuda" in self.device else "cpu"
self.warp_meshes[key] = convert_to_warp_mesh(mesh.vertices, mesh.faces, device=device)
# obtain ground plane color from the configured visual material
color = (0.0, 0.0, 0.0)
if self.cfg.visual_material is not None:
material = self.cfg.visual_material.to_dict()
# defaults to the `GroundPlaneCfg` color if diffuse color attribute is not found
if "diffuse_color" in material:
color = material["diffuse_color"]
else:
omni.log.warn(
"Visual material specified for ground plane but no diffuse color found."
" Using default color: (0.0, 0.0, 0.0)"
)
# get the mesh
ground_plane_cfg = sim_utils.GroundPlaneCfg(physics_material=self.cfg.physics_material, size=size)
ground_plane_cfg = sim_utils.GroundPlaneCfg(physics_material=self.cfg.physics_material, size=size, color=color)
ground_plane_cfg.func(self.cfg.prim_path, ground_plane_cfg)
def import_mesh(self, key: str, mesh: trimesh.Trimesh):
......
......@@ -65,7 +65,7 @@ class TerrainImporterCfg:
"""The spacing between environment origins when defined in a grid. Defaults to None.
Note:
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".
"""
visual_material: sim_utils.VisualMaterialCfg | None = sim_utils.PreviewSurfaceCfg(
......@@ -73,10 +73,12 @@ class TerrainImporterCfg:
)
"""The visual material of the terrain. Defaults to a dark gray color material.
The material is created at the path: ``{prim_path}/visualMaterial``. If `None`, then no material is created.
This parameter is used for both the "generator" and "plane" terrains.
.. note::
This parameter is used only when the ``terrain_type`` is ``"generator"``.
- If the ``terrain_type`` is "generator", then the material is created at the path
``{prim_path}/visualMaterial`` and applied to all the sub-terrains.
- If the ``terrain_type`` is "plane", then the diffuse color of the material is set to
to the grid color of the imported ground plane.
"""
physics_material: sim_utils.RigidBodyMaterialCfg = sim_utils.RigidBodyMaterialCfg()
......@@ -85,7 +87,7 @@ class TerrainImporterCfg:
The material is created at the path: ``{prim_path}/physicsMaterial``.
.. note::
This parameter is used only when the ``terrain_type`` is ``"generator"`` or ``"plane"``.
This parameter is used only when the ``terrain_type`` is "generator" or "plane".
"""
max_init_terrain_level: int | None = None
......
......@@ -26,7 +26,7 @@ from isaacsim.core.prims import RigidPrim, SingleGeometryPrim, SingleRigidPrim
from isaacsim.core.utils.extensions import enable_extension
import isaaclab.terrains as terrain_gen
from isaaclab.sim import SimulationContext, build_simulation_context
from isaaclab.sim import PreviewSurfaceCfg, SimulationContext, build_simulation_context
from isaaclab.terrains import TerrainImporter, TerrainImporterCfg
from isaaclab.terrains.config.rough import ROUGH_TERRAINS_CFG
from isaaclab.utils.assets import ISAAC_NUCLEUS_DIR
......@@ -101,31 +101,35 @@ class TestTerrainImporter(unittest.TestCase):
def test_plane(self) -> None:
"""Generates a plane and tests that the resulting mesh has the correct size."""
for device in ("cuda:0", "cpu"):
with build_simulation_context(device=device, auto_add_lighting=True) as sim:
sim._app_control_on_stop_handle = None
expectedSizeX = 2.0e6
expectedSizeY = 2.0e6
# Handler for terrains importing
terrain_importer_cfg = terrain_gen.TerrainImporterCfg(
prim_path="/World/ground",
terrain_type="plane",
num_envs=1,
env_spacing=1.0,
)
terrain_importer = TerrainImporter(terrain_importer_cfg)
# check mesh exists
mesh = terrain_importer.meshes["terrain"]
self.assertIsNotNone(mesh)
# get size from mesh bounds
bounds = mesh.bounds
actualSize = abs(bounds[1] - bounds[0])
self.assertAlmostEqual(actualSize[0], expectedSizeX)
self.assertAlmostEqual(actualSize[1], expectedSizeY)
for use_custom_material in [True, False]:
with build_simulation_context(device=device, auto_add_lighting=True) as sim:
sim._app_control_on_stop_handle = None
expectedSizeX = 2.0e6
expectedSizeY = 2.0e6
# create custom material
visual_material = PreviewSurfaceCfg(diffuse_color=(1.0, 0.0, 0.0)) if use_custom_material else None
# Handler for terrains importing
terrain_importer_cfg = terrain_gen.TerrainImporterCfg(
prim_path="/World/ground",
terrain_type="plane",
num_envs=1,
env_spacing=1.0,
visual_material=visual_material,
)
terrain_importer = TerrainImporter(terrain_importer_cfg)
# check mesh exists
mesh = terrain_importer.meshes["terrain"]
self.assertIsNotNone(mesh)
# get size from mesh bounds
bounds = mesh.bounds
actualSize = abs(bounds[1] - bounds[0])
self.assertAlmostEqual(actualSize[0], expectedSizeX)
self.assertAlmostEqual(actualSize[1], expectedSizeY)
def test_usd(self) -> None:
"""Imports terrain from a usd and tests that the resulting mesh has the correct size."""
......
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