🏔️ 地形模拟与生成#
Genesis 通过 gs.morphs.Terrain morph 为 高度场地形 提供一流的支持。地形是一个静态刚体对象,内部由高度图(用于快速碰撞查询)和水密三角网格(用于可视化和 SDF 生成)表示。
本页介绍了创建地形的三种最常见方式:
传入你自己的 NumPy 高度图。
程序化生成 子地形 网格(Isaac Gym 风格)。
自动将任意三角网格转换为高度图。
1 使用自定义高度图#
如果你已有地形数据(例如来自 DEM 文件),可以直接将其输入 Genesis。你只需要两个数值:水平比例和垂直比例。
import numpy as np
import genesis as gs
# 1. 初始化 Genesis
gs.init(seed=0, backend=gs.gpu) # 使用 gs.cpu 表示 CPU 后端
# 2. 创建场景
scene = gs.Scene(show_viewer=True)
# 3. 准备高度图(这里是一个简单的凸起用于演示)
hf = np.zeros((40, 40), dtype=np.int16)
hf[10:30, 10:30] = 200 * np.hanning(20)[:, None] * np.hanning(20)[None, :]
horizontal_scale = 0.25 # 网格点之间的米数
vertical_scale = 0.005 # 每个高度场单位的米数
# 4. 添加地形实体
scene.add_entity(
morph=gs.morphs.Terrain(
height_field=hf,
horizontal_scale=horizontal_scale,
vertical_scale=vertical_scale,
),
)
scene.build()
# 运行模拟以便你可以检查表面
for _ in range(1_000):
scene.step()
可视化调试技巧#
构建场景后,高度图存储在 terrain.geoms[0].metadata["height_field"] 中。你可以在每个采样点上绘制小球来查看实际几何形状:
import torch
hf = terrain.geoms[0].metadata["height_field"]
rows = horizontal_scale * torch.arange(hf.shape[0]).unsqueeze(1).repeat(1, hf.shape[1])
cols = horizontal_scale * torch.arange(hf.shape[1]).unsqueeze(0).repeat(hf.shape[0], 1)
heights = vertical_scale * torch.tensor(hf)
poss = torch.stack((rows, cols, heights), dim=-1).reshape(-1, 3)
scene.draw_debug_spheres(poss, radius=0.05, color=(0, 0, 1, 0.7))
2 程序化子地形#
gs.morphs.Terrain 还可以通过拼接 子地形 网格来合成复杂地面——与 Isaac Gym 使用的技术相同。你只需指定:
n_subterrains=(nx, ny)– 每个方向的瓦片数量。subterrain_size=(sx, sy)– 每个瓦片的尺寸(米)。subterrain_types– 一个二维列表,为每个瓦片选择生成器。
内置生成器的完整列表包括:
flat_terrain, random_uniform_terrain, pyramid_sloped_terrain, discrete_obstacles_terrain, wave_terrain, pyramid_stairs_terrain, stairs_terrain, stepping_stones_terrain, fractal_terrain。
scene = gs.Scene(show_viewer=True)
terrain = scene.add_entity(
morph=gs.morphs.Terrain(
n_subterrains=(2, 2),
subterrain_size=(6.0, 6.0),
horizontal_scale=0.25,
vertical_scale=0.005,
subterrain_types=[
["flat_terrain", "random_uniform_terrain"],
["pyramid_sloped_terrain", "discrete_obstacles_terrain"],
],
),
)
scene.build(n_envs=100) # 你仍然可以运行多个并行环境
上面的代码本质上与 Genesis 附带的 examples/rigid/terrain_subterrain.py 相同。欢迎打开该示例查看完整的可运行脚本。
3 从三角网格生成高度图#
有时你已经有一个详细的 CAD 或摄影测量网格,只是希望碰撞检测运行得更快。辅助函数 genesis.utils.terrain.mesh_to_heightfield 使用垂直光线采样网格,并返回一个 NumPy 高度数组以及网格坐标。
from genesis.utils.terrain import mesh_to_heightfield
import os
# 你的 .obj / .glb / .stl 地形文件路径
mesh_path = os.path.join(gs.__path__[0], "assets", "meshes", "terrain_45.obj")
horizontal_scale = 2.0 # 期望的网格间距(米)
height, xs, ys = mesh_to_heightfield(mesh_path, spacing=horizontal_scale, oversample=3)
# 移动地形,使网格中心变为 (0,0)
translation = np.array([xs.min(), ys.min(), 0.0])
scene = gs.Scene(show_viewer=True)
scene.add_entity(
morph=gs.morphs.Terrain(
height_field=height,
horizontal_scale=horizontal_scale,
vertical_scale=1.0,
pos=translation, # 可选的世界变换
),
)
scene.add_entity(gs.morphs.Sphere(pos=(10, 15, 10), radius=1))
scene.build()
这个过程被封装在 examples/rigid/terrain_from_mesh.py 中。
API 参考#
有关完整的关键字参数列表,请参阅自动生成的 API 页面:
- class genesis.options.morphs.Terrain(*, pos: tuple = (0.0, 0.0, 0.0), euler: tuple | None = None, quat: tuple | None = None, visualization: bool = True, collision: bool = True, requires_jac_and_IK: bool = False, is_free: bool | None = None, batch_fixed_verts: bool = False, randomize: bool = False, n_subterrains: Tuple[int, int] = (3, 3), subterrain_size: Tuple[float, float] = (12.0, 12.0), horizontal_scale: float = 0.25, vertical_scale: float = 0.005, uv_scale: float = 1.0, subterrain_types: Any = [['flat_terrain', 'random_uniform_terrain', 'stepping_stones_terrain'], ['pyramid_sloped_terrain', 'discrete_obstacles_terrain', 'wave_terrain'], ['random_uniform_terrain', 'pyramid_stairs_terrain', 'sloped_terrain']], height_field: Any = None, name: str | None = None, from_stored: Any = None, subterrain_parameters: dict[str, dict] | None = None)[source]#
Bases:
MorphMorph for creating a rigid terrain. This can be instantiated from two choices: 1) a grid of subterrains generated using the given configurations 2) a terrain generated using the given height field.
If randomize is True, subterrain type that involves randomness will have random parameters. Otherwise, they will use fixed random seed 0.
Users can easily configure the subterrain types by specifying the subterrain_types parameter. If using a single string, it will be repeated for all subterrains. If it’s a 2D list, it should have the same shape as n_subterrains. The supported subterrain types are:
‘flat_terrain’: flat terrain
‘random_uniform_terrain’: random uniform terrain
‘sloped_terrain’: sloped terrain
‘pyramid_sloped_terrain’: pyramid sloped terrain
‘discrete_obstacles_terrain’: discrete obstacles terrain
‘wave_terrain’: wave terrain
‘stairs_terrain’: stairs terrain
‘pyramid_stairs_terrain’: pyramid stairs terrain
‘stepping_stones_terrain’: stepping stones terrain
Note
Rigid terrain will also be represented as SDF for collision checking, but its resolution is auto-computed and ignores the value specified in gs.materials.Rigid().
- Parameters:
file (str) – The path to the file.
scale (float or tuple, optional) – The scaling factor for the size of the entity. If a float, it scales uniformly. If a 3-tuple, it scales along each axis. Defaults to 1.0. Note that 3-tuple scaling is only supported for gs.morphs.Mesh.
pos (tuple, shape (3,), optional) – The position of the entity in meters. Defaults to (0.0, 0.0, 0.0).
visualization (bool, optional) – Whether the entity needs to be visualized. Set it to False if you need a invisible object only for collision purposes. Defaults to True. visualization and collision cannot both be False.
collision (bool, optional) – Whether the entity needs to be considered for collision checking. Defaults to True. visualization and collision cannot both be False.
randomize (bool, optional) – Whether to randomize the subterrains that involve randomness. Defaults to False.
n_subterrains (tuple of int, optional) – The number of subterrains in x and y directions. Defaults to (3, 3).
subterrain_size (tuple of float, optional) – The size of each subterrain in meters. Defaults to (12.0, 12.0).
horizontal_scale (float, optional) – The size of each cell in the subterrain in meters. Defaults to 0.25.
vertical_scale (float, optional) – The height of each step in the subterrain in meters. Defaults to 0.005.
uv_scale (float, optional) – The scale of the UV mapping for the terrain. Defaults to 1.0.
subterrain_types (str or 2D list of str, optional) – The types of subterrains to generate. If a string, it will be repeated for all subterrains. If a 2D list, it should have the same shape as n_subterrains.
height_field (array-like, optional) – The height field to generate the terrain. If specified, all other configurations will be ignored. Defaults to None.
name (str, optional) – The name of the terrain. If specified, the terrain will only be generated once for a given set of options and later loaded from cache, instead of being re-generated systematically when building the scene. This holds true no matter if randomize is True.
from_stored (str, optional) – This parameter is deprecated.
subterrain_parameters (dictionary, optional) – Lets users pick their own subterrain parameters.
batch_fixed_verts (bool, optional) – Whether to batch fixed vertices. This will allow setting env-specific poses to fixed geometries, at the cost of significantly increasing memory usage. Default to false. This is only used for RigidEntity.
- model_config: ClassVar[ConfigDict] = {}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
保存与重复使用地形#
创建地形时,Genesis 会生成高度图、用于碰撞检测的水密网格以及用于可视化的简化网格。你可以通过在首次创建地形时传入 name="my_terrain" 来启用高度图的缓存,之后将从缓存加载而无需重新生成。这对于精确重建随机化地形非常有用。
祝你攀登愉快!🧗♂️🏔️