渲染#

相机可以把 Genesis World 场景离屏渲染成图像:颜色、深度、分割结果、表面法线,以及视频。与查看器不同,相机不需要显示器,因此可以在渲染农场、容器中或通过 SSH 以无头方式运行。本页介绍如何添加相机、相机产出哪些图像类型、如何录制视频、光照,以及各类渲染后端——从快速的默认光栅化器到照片级真实感的光线追踪。

完整脚本见 examples/tutorials/visualization.py。

添加相机#

用 scene.add_camera() 添加相机。相机的渲染独立于查看器,因此适用于无头渲染,也适合拍摄查看器没有对准的角度:

cam = scene.add_camera(
    res=(640, 480),  # (width, height) in pixels
    pos=(3.5, 0.0, 2.5),
    lookat=(0, 0, 0.5),
    fov=30,
    GUI=False,
)

设置 GUI=True 时,相机会打开一个独立于查看器窗口的 OpenCV 窗口,显示每一帧渲染结果。以无头方式运行时保持 False。

Note

scene.add_camera() 创建的是可视化相机:一个由你自行驱动的对象,调用 render() 获取像素,调用 start_recording() 录制视频。观察场景用的就是这种相机,本页通篇也都围绕它展开。机器人的机载相机则是相机传感器,通过 scene.add_sensor(...) 添加,像其他传感器一样用 read() 读取,且仅输出 RGB,并通过记录器保存为视频。

渲染图像#

构建场景,然后调用 cam.render()。相机能产出四种图像:颜色、深度、分割掩码和表面法线。默认只渲染 RGB,其他类型要用关键字开关启用。render() 始终按同样的顺序返回这四种结果,未启用的类型返回 None:

scene.build()

# render rgb, depth, segmentation, normal
rgb, depth, segmentation, normal = cam.render(rgb=True, depth=True, segmentation=True, normal=True)

返回的每个数组形状为 (height, width, ...),即相对于 res=(width, height) 转置后的结果。默认情况下,分割掩码在每个像素上存一个整数对象索引;设置 colorize_seg=True 可获得可直接查看的彩色掩码。该索引按照 VisOptions.segmentation_level 设定的层级映射回场景对象(例如 link_idx 对应 scene.rigid_solver.links 中的下标)。

Franka 场景的四种渲染方式:颜色、深度、分割掩码和表面法线

Tip

用 GUI=True 打开的 OpenCV 窗口有时第一帧显示为黑色。再次调用 cam.render() 刷新,或调用 cv2.waitKey(1)。

录制视频#

要录制视频,先用输出文件和帧率调用 start_recording(),推进场景,最后调用 stop_recording() 完成文件写入。每当需要输出一帧时,相机都会在 scene.step() 内部完成渲染,且每一帧都会立即编码并流式写入磁盘,因此录制时长不受内存限制。下面的例子让相机在仿真推进的同时环绕场景运动:

import math

cam.start_recording(save_to_filename="video.mp4", fps=60)

for i in range(120):
    cam.set_pose(
        pos=(3.0 * math.sin(i / 60), 3.0 * math.cos(i / 60), 2.5),
        lookat=(0, 0, 0.5),
    )
    scene.step()

cam.stop_recording()

如果省略 save_to_filename,Genesis World 会根据调用脚本生成文件名,fps 默认为 60。任意两帧之间总是相隔整数个仿真步,因此不落在该网格上的帧率会被取整到最近的网格值并记录日志;场景能录制的最高帧率为每步一帧。视频中的一秒对应按 realtime_factor 步调计时的一秒(参见查看器),因此在默认的 realtime_factor=1.0 下,无论帧率是多少,播放都按实时进行;而每步一帧时,编码帧率为 1 / dt。效果如下:

调用 cam.pause_recording() 可以把仿真中的一段时间排除在视频之外(例如稳定阶段),然后用不带参数的 cam.start_recording() 继续写入同一个文件;暂停的这段时间不会在视频中留下空档。文件名和帧率在整段视频中固定不变,因此恢复录制时传入其中任何一个都会报错。调用 stop_recording() 之后,相机可以以新的帧率录制到新文件。

在批处理场景中,如果相机渲染所有环境,则每个被渲染的环境各写一个文件,文件名带有该环境的索引后缀(video_0.mp4、video_1.mp4、……)。BatchRenderer 后端就是这样做的,光栅化器在 VisOptions 中设置 split_envs=True 时也是如此;否则相机会绑定到单个环境 env_idx,只录制一个文件。

如果需要按计划记录传感器和仿真数据(而不只是视频),请参阅记录数据。

光照#

光栅化器(查看器,以及任何执行光栅化的相机或相机传感器)用 VisOptions 上的灯光列表为场景打光。在没有任何配置时,它使用单个平行光,因此场景开箱即处于被照亮的状态;设置 lights 可自行控制方向、颜色和强度。灯光类位于 gs.options.vis:

scene = gs.Scene(
    vis_options=gs.options.VisOptions(
        lights=[
            gs.options.vis.DirectionalLight(
                dir=(-1, -1, -1),  # direction the light travels, world frame
                color=(1.0, 1.0, 1.0),  # RGB in [0, 1]
                intensity=5.0,
            ),
            gs.options.vis.PointLight(
                pos=(2.0, 0.0, 3.0),  # meters, world frame
                color=(1.0, 0.9, 0.8),
                intensity=8.0,
            ),
        ],
        ambient_light=(0.1, 0.1, 0.1),  # uniform fill so shadows are not pure black
    ),
)

lights 列表接受两种类型:

  • DirectionalLight: 从固定方向射出的平行光线,类似阳光。设置 dir(光线传播方向)、color 和 intensity。位置无关紧要。

  • PointLight: 从一个点向外辐射的光。设置 pos、color 和 intensity。

环境光是独立于 lights 条目的一种均匀补光,通过 ambient_light 字段设置。

Note

这里的设置只作用于光栅化器。光线追踪器会忽略 VisOptions.lights,它有自己的一套三个光源:gs.renderers.RayTracer(...) 上的球形面光源列表 lights、它的 env_surface 环境贴图,以及任何带有 Emission 表面的实体。参见表面与纹理。BatchRenderer 后端则在运行时通过 scene.add_light(...) 接收灯光。

渲染后端#

gs.Scene(renderer=...) 决定场景中的相机如何把场景转换为像素:

  • gs.renderers.Rasterizer():默认选项。速度快,也是查看器始终使用的后端。

  • gs.renderers.RayTracer():路径追踪器,用于生成照片级真实感的静帧(见下文)。

  • gs.renderers.BatchRenderer(...):跨多个环境的高吞吐量渲染(见使用 gs-madrona 进行批渲染)。

使用 Nyx 进行照片级真实感渲染#

Nyx 是实现照片级真实感渲染的推荐途径。与上文的后端不同,它以相机传感器的形式挂载,而不是作为场景级渲染器:添加一个 NyxCameraOptions 传感器,再从 cam.read().rgb 读回帧。它支持 PBR 材质、HDRI 光照、3D 高斯泼溅资产、多相机与多环境渲染,以及逐像素对象拾取。安装方法、最小示例和完整功能集请参阅Nyx 渲染器页面。

Note

路线图。 我们正在把光栅化和路径追踪统一到 Nyx 之下,形成单一的、基于传感器的渲染接口。Nyx 将逐步取代下文的 Luisa 后端和默认光栅化器,最终 Genesis World 中所有基于相机的渲染都由它承担。

使用 Luisa 进行照片级真实感渲染(已弃用)#

Genesis World 还提供基于 Luisa 的光线追踪后端。创建场景时传入 renderer=gs.renderers.RayTracer() 即可启用;它暴露了 spp、aperture 以及相机 model 等额外参数。

Warning

该后端已弃用并由 Nyx 取代,且需要从源码构建 LuisaRender。

安装步骤(已在 Ubuntu 22.04、CUDA 12.4 和 Python 3.9 上测试):

  1. 拉取子模块并安装渲染相关的额外依赖:

    # inside the genesis-world repo
    git submodule update --init --recursive
    pip install -e ".[render]"
    
  2. 确保 PATH 中有 gcc/g++ >= 11 和 CMake >= 3.26,并安装 Vulkan、X11、UUID 和 zlib 的开发头文件(有 sudo 时用 apt,没有时用 conda install -c conda-forge)。

  3. 构建 LuisaRender:

    cd genesis/ext/LuisaRender
    cmake -S . -B build -D CMAKE_BUILD_TYPE=Release -D PYTHON_VERSIONS=3.9 \
        -D LUISA_COMPUTE_DOWNLOAD_NVCOMP=ON -D LUISA_COMPUTE_ENABLE_GUI=OFF \
        -D LUISA_RENDER_BUILD_TESTS=OFF
    cmake --build build -j $(nproc)
    
  4. 运行示例:

    cd examples/rendering
    python demo.py
    
使用 Luisa 光线追踪后端渲染出的照片级真实感场景

Note

常见 CUDA 与 Python 组合的预编译 LuisaRender 二进制文件可在 Google Drive 上获取,命名格式为 build_<commit-tag>_cuda<version>_python<version>。下载与你的系统匹配的文件,重命名为 build/,放入 genesis/ext/LuisaRender。构建和 CUDA 工具包的故障排查请参阅 genesis-world README。

使用 gs-madrona 进行批渲染#

要在大量并行环境上实现高吞吐量渲染,可传入 renderer=gs.renderers.BatchRenderer(use_rasterizer=True) 使用 gs-madrona 后端(设为 use_rasterizer=False 则改用路径追踪)。

先安装该包。PyPI 上提供适用于 x86 和 Python >= 3.10 的预编译 wheel:

pip install gs-madrona

然后运行随附的示例,它会把帧写入 out/batch_render,也可以用 -o 写到其他位置:

python examples/rigid/single_franka_batch_render.py

批渲染器只能在 CUDA 上运行,因此该示例没有可回退的 CPU 后端。

批渲染器不在 VisOptions 中取灯光,而是在场景创建之后通过 scene.add_light(...) 在运行时设置:

scene.add_light(
    pos=(0.0, 0.0, 10.0),   # position, used for positional lights
    dir=(0.0, 0.0, -1.0),   # direction the light travels, normalized internally
    color=(1.0, 1.0, 1.0),  # RGB, each channel in [0, 1]
    intensity=1.0,
    directional=True,       # parallel rays if True, positional if False
    castshadow=True,
    cutoff=45.0,            # spotlight cutoff angle, degrees
    attenuation=0.0,        # distance falloff for positional lights
)

另请参阅#