约定#

本页定义我们在整个 API 中遵循的约定:坐标系、旋转、物理单位、张量形状和数据类型,以及决定导入资产朝向的规则。

坐标系#

我们使用右手系、Z 轴向上的坐标系。相对于默认查看器(其相机位于 +X 一侧,朝原点回看):

  • +X:指向屏幕外,朝向查看器。

  • +Y:指向查看器的右侧。

  • +Z:指向上方。

四元数表示#

四元数遵循 (w, x, y, z) 约定:

  • w:标量(实部)分量。

  • x、y、z:向量(虚部)分量。

我们遵循标量在前的 Hamilton 约定,因此在 API 接受四元数的任何地方,都请按此顺序提供。

# 90-degree rotation about the +Z axis
quat = (0.707, 0.0, 0.0, 0.707)  # (w, x, y, z)

在改用欧拉角的场合,欧拉角采用外旋 x-y-z 顺序,单位为度(遵循 SciPy 的约定)。

重力#

重力默认为 (0, 0, -9.81),即沿 -Z 方向、大小为 9.81 m/s²。在没有其他力作用时,物体会沿 -Z 方向下落。可通过 gs.options.SimOptions(gravity=...) 为整个场景设置重力,或通过某个求解器自身选项中的 gravity 字段为该求解器设置;运行时可通过该求解器修改,例如 scene.rigid_solver.set_gravity(gravity, envs_idx)。

导入时的坐标轴转换#

资产格式对于哪个轴向上存在分歧,有些格式甚至根本不记录。下文给出每种格式进入我们的 Z-up 空间时所适用的规则。

选定一种 Y-up 映射#

Y-up 到 Z-up 的转换是一个 3×3 旋转,根据资产将哪个轴视为前方,可以有多种有效旋转。两个网格都可以标记为 Y-up,却以不同朝向导入,因此决定旋转的是前方轴。

因此,我们确定采用一种映射 (X, Y, Z) → (X, -Z, Y),即 Y-up、-Z 向前。这是 Blender 导出为 Y-up 格式时的默认配置;我们与之一致,因为 Blender 是机器人和仿真资产的常用创作工具,其导出器会针对每种目标格式应用定义明确的转换。

因此,以默认设置从 Blender 导出的资产,无论采用 glTF、STL、OBJ 格式,还是 URDF 中引用的网格,都会以你在 Blender 中看到的朝向到达。本文档中凡提到“Y-up”,均指这一映射。

glTF (.gltf, .glb)#

根据规范,glTF 资产始终是 Y-up,因此我们始终会转换它们,没有可关闭该转换的开关:遵循规范的 glTF 文件因而在任何地方行为一致。

如果你取消勾选 +Y-up,Blender 会写出 Z-up 的 glTF,但之后它无法正确读回该文件。由于我们的转换假定遵循规范,Z-up 的 glTF 导入后会是旋转过的。请使用默认的 +Y-up 选项重新导出,而不要在导入时覆盖坐标轴。

已启用 +Y-up 变换选项的 Blender glTF 导出器面板

关于变换设置,请参阅 Blender 的 glTF 导出器文档。

STL (.stl) 与 Wavefront OBJ (.obj)#

这两种格式都不记录坐标系,而且两类文件会因写入工具的不同而以 Y-up 或 Z-up 到达,因此需要你声明自己拥有的是哪一种:

  • Z-up(默认): 假定网格已经处于 Z-up 空间,不做任何转换。

  • Y-up: 应用上面的 (X, Y, Z) → (X, -Z, Y) 映射。

在导入时声明这一点,意味着来自不同来源的资产可以在同一场景中共存,而无需你编辑文件。

显示上轴和前轴设置的 Blender Wavefront OBJ 导出器面板

请参阅 Blender 的 Wavefront OBJ 导出器和 Blender 的 STL 导出器文档。

在导入时声明上轴#

将 file_meshes_are_zup 传给 mesh morph,告诉 Genesis World 所引用网格的朝向。它默认为 True(已经是 Z-up);对于需要转换的 Y-up 资产,将其设为 False:

obj = scene.add_entity(
    gs.morphs.Mesh(
        file="my_obj_file.obj",
        file_meshes_are_zup=False,  # mesh is Y-up; convert to Z-up on import
    ),
)

导入后,每个网格上的 imported_as_zup 元数据标志会记录是否执行了转换:

obj.vgeoms[0].mesh.metadata["imported_as_zup"]  # False if a Y-up -> Z-up conversion ran

单位#

Genesis World 所谓的无单位,是指它不会替你进行任何单位换算;但每个内置默认值都以 SI 单位表示,且 API 假定你也遵循这一约定:

  • 长度以米为单位,质量以千克为单位,时间以秒为单位。

  • 角度以弧度为单位,但有一个刻意保留的例外:传给 morph 的欧拉角以度为单位(见上文的旋转一节)。

  • 派生量由此得出:密度单位为 kg/m³,力单位为牛顿,重力加速度单位为 m/s²。

仿真时间步是以秒为单位的时长,默认值为 dt = 1e-2(10 ms):

gs.options.SimOptions(dt=0.01)  # seconds

少数 API 在 SI 单位不方便的场合使用自己的自然单位。例如,无人机的螺旋桨以 RPM 表示角速度,温度网格传感器以摄氏度报告温度。这些会在相关页面和 docstring 中特别说明。如有疑问,请按 SI 单位处理。

张量形状与批处理#

Genesis World 并行仿真许多环境(参见 并行仿真),因此大多数量都带有一个可选的前导批次维度。文档和 docstring 使用方括号记法描述形状:

distances  # shape ([n_envs,] n_probes)
points     # shape ([n_envs,] n_probes, 3)

[n_envs,] 方括号表示:场景使用多个环境构建时存在,否则不存在。 用 scene.build(n_envs=4096) 构建的场景返回的张量带有一个前导的 4096 维度;未指定 n_envs 构建的场景会完全去掉该维度,而不是使用大小为 1 的轴。

读取或写入逐环境状态的方法接受 envs_idx 参数,用于定位环境的子集。传入 envs_idx=None(默认值)会作用于所有环境;传入索引张量则只沿批次维度选择那些行。

索引参数#

envs_idx 以及逐实体索引参数(links_idx_local、dofs_idx_local、qs_idx_local 等)接受相同的形式:整数、range、slice、列表或元组、NumPy 数组或 PyTorch 张量,None 表示选择全部。负索引像在 Python 和 NumPy 中一样从末尾计数,因此 envs_idx=-1 表示最后一个环境。布尔数组充当掩码,且长度必须覆盖它所选择的维度的完整长度。

数据类型与精度#

API 返回的张量是放置在活动设备(gs.device)上的 PyTorch 张量。其 dtype 取决于初始化时选择的精度:

  • 浮点值默认为 float32;使用 precision="64" 初始化时为 float64。

  • 整数索引(实体、连杆和 dof 索引,envs_idx 等)始终为 int32,与浮点精度无关。

gs.init() 不会改动 PyTorch 的全局默认 dtype 和设备,因此请为你自行分配的张量传入 dtype=gs.tc_float(或 gs.tc_int)和 device=gs.device,使它们与 API 返回的内容保持一致。关于如何选择后端和精度,请参阅 初始化与后端。