在可视化器中显示相机流视图#
在同一个实时可视化面板中显示多个环境的真值相机图像。视图原理及受支持的可视化器见 相机流视图。
快速开始#
运行 IsaacLab/scripts/tutorials/07_visualizers 中的 run_tiled_camera_visualizer.py 脚本:
uv run python scripts/tutorials/07_visualizers/run_tiled_camera_visualizer.py \
--task Isaac-Velocity-Rough-AnymalD --num_envs 256 --viz kit
uv run python scripts/tutorials/07_visualizers/run_tiled_camera_visualizer.py ^
--task Isaac-Velocity-Rough-AnymalD --num_envs 256 --viz kit
run_tiled_camera_visualizer.py 的代码
1# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
2# All rights reserved.
3#
4# SPDX-License-Identifier: BSD-3-Clause
5
6"""
7This script demonstrates the visualizer tiled camera panel.
8
9.. code-block:: bash
10
11 # Kit visualizer tiled camera panel
12 uv run python scripts/tutorials/07_visualizers/run_tiled_camera_visualizer.py \
13 --task Isaac-Velocity-Rough-AnymalD --num_envs 256 --viz kit
14
15 # Newton visualizer tiled camera panel
16 uv run python scripts/tutorials/07_visualizers/run_tiled_camera_visualizer.py \
17 --task IsaacContrib-Stack-Cube-Galbot-Left-Arm-Gripper-Visuomotor --num_envs 25 --viz newton_gl
18
19"""
20
21from __future__ import annotations
22
23import argparse
24import contextlib
25import sys
26
27import gymnasium as gym
28import torch
29from isaaclab_newton.renderers import NewtonWarpRendererCfg
30from isaaclab_physx.renderers import IsaacRtxRendererCfg
31from isaaclab_visualizers.kit import KitVisualizerCfg
32from isaaclab_visualizers.newton import NewtonGLVisualizerCfg
33
34import isaaclab_tasks # noqa: F401
35
36with contextlib.suppress(ImportError):
37 import isaaclab_tasks_experimental # noqa: F401
38from isaaclab.app import add_launcher_args, launch_simulation
39from isaaclab.sensors import CameraCfg
40from isaaclab.sim import PinholeCameraCfg
41from isaaclab.utils.math import create_rotation_matrix_from_view, quat_from_matrix
42from isaaclab.visualizers import SceneCameraCfg
43
44from isaaclab_tasks.utils import resolve_task_config, setup_preset_cli
45
46KIT_DEFAULT_TASK = "Isaac-Velocity-Rough-AnymalD"
47NEWTON_DEFAULT_TASK = "IsaacContrib-Stack-Cube-Galbot-Left-Arm-Gripper-Visuomotor"
48
49
50# add argparse arguments
51parser = argparse.ArgumentParser(description="Showcase the Kit/Newton visualizer tiled camera panel.")
52parser.add_argument("--num_envs", type=int, default=None, help="Number of environments to simulate.")
53parser.add_argument("--task", type=str, default=None, help="Name of the task.")
54# append simulation launcher cli args
55add_launcher_args(parser)
56parser.set_defaults(visualizer=["kit"])
57args_cli, hydra_args = setup_preset_cli(parser)
58if args_cli.task is None:
59 visualizers = next(arg.split("=", 1)[1].split(",") for arg in hydra_args if arg.startswith("visualizer="))
60 args_cli.task = NEWTON_DEFAULT_TASK if {"newton", "newton_gl"}.intersection(visualizers) else KIT_DEFAULT_TASK
61sys.argv = [sys.argv[0]] + hydra_args
62
63
64def main():
65 """Run a random-action environment with a tiled camera visualizer."""
66 # parse configuration via Hydra (supports preset selection, e.g. presets=newton_mjwarp)
67 env_cfg, _ = resolve_task_config(args_cli.task, "")
68 # Declare the shared scene camera before launching either viewer.
69 visualizers = env_cfg.sim.visualizer_cfgs
70 visualizers = visualizers if isinstance(visualizers, list) else [visualizers] if visualizers else []
71 if not visualizers or any(not isinstance(cfg, (KitVisualizerCfg, NewtonGLVisualizerCfg)) for cfg in visualizers):
72 raise ValueError("This tutorial supports --viz kit or --viz newton_gl.")
73 camera_cfg = next((cfg for cfg in vars(env_cfg.scene).values() if isinstance(cfg, CameraCfg)), None)
74 if camera_cfg is None:
75 eye, target = torch.tensor([[3.0, 3.0, 3.0]]), torch.zeros((1, 3))
76 rotation = quat_from_matrix(create_rotation_matrix_from_view(eye, target, device="cpu"))[0]
77 # Attaching the sensor to the base gives it the robot's pose through the normal camera view.
78 camera_cfg = CameraCfg(
79 prim_path="{ENV_REGEX_NS}/Robot/base/StreamingCamera",
80 width=320,
81 height=240,
82 data_types=["rgb"],
83 spawn=PinholeCameraCfg(focal_length=24.0, clipping_range=(0.1, 1.0e5)),
84 offset=CameraCfg.OffsetCfg(pos=(3.0, 3.0, 3.0), rot=tuple(rotation.tolist()), convention="opengl"),
85 renderer_cfg=(
86 IsaacRtxRendererCfg()
87 if any(isinstance(cfg, KitVisualizerCfg) for cfg in visualizers)
88 else NewtonWarpRendererCfg()
89 ),
90 )
91 env_cfg.scene.streaming_camera = camera_cfg
92 for cfg in visualizers:
93 cfg.streaming_view = True
94 cfg.streaming_envs = 36 if isinstance(cfg, KitVisualizerCfg) else 12
95 cfg.cameras = [SceneCameraCfg(prim_path=camera_cfg.prim_path)]
96
97 with launch_simulation(env_cfg, args_cli):
98 # override with CLI arguments
99 env_cfg.scene.num_envs = args_cli.num_envs if args_cli.num_envs is not None else env_cfg.scene.num_envs
100
101 # create environment
102 env = gym.make(args_cli.task, cfg=env_cfg)
103
104 # print info (this is vectorized environment)
105 print(f"[INFO]: Gym observation space: {env.observation_space}")
106 print(f"[INFO]: Gym action space: {env.action_space}")
107 env.reset()
108
109 # keep stepping until all visualizer windows have been closed
110 while env.unwrapped.sim.is_running():
111 with torch.inference_mode():
112 actions = 2 * torch.rand(env.action_space.shape, device=env.unwrapped.device) - 1
113 env.step(actions)
114
115 env.close()
116
117
118if __name__ == "__main__":
119 main()
选择和控制显示视图#
Kit 将流式视图打开为独立的 Streaming View 视口,可从 Viewport 标签页选择,也可与默认交互视口并排显示,便于同时监测。
Newton GL 和 Newton RTX 在侧边栏提供 Camera View 选择器。选择场景相机后,主视口显示其平铺输出,不再在背后渲染透视视图;选择透视相机后恢复交互场景渲染,Newton GL 也恢复拾取。
未显式提供 cameras 列表时,Newton GL 从透视视图启动,并列出提供所有所需 streaming_gt_types 通道的场景相机。显式设置 streaming_sensor_prim_path 时,以该场景相机作为初始选择。例如,设置 streaming_gt_types=("depth",) 可列出仅提供深度的相机。RGB 视图接受 RGB 或 RGBA 输出,显示时使用不透明 alpha。构建选择器不会捕获图像。显式配置的场景相机选项必须支持所需通道,不兼容的选项会在初始化时报错,即使该选项未启用。
Newton RTX 仅显示 view 或 cameras 声明的来源。两者均未设置时,启动准备会声明一个透视相机,不会自动将场景传感器加入选择器。
使用 cameras 声明可切换视图列表,第一项初始启用:
from isaaclab.visualizers import PerspectiveCameraCfg, SceneCameraCfg
from isaaclab_visualizers.newton import NewtonGLVisualizerCfg
viewer_cfg = NewtonGLVisualizerCfg(
cameras=[
SceneCameraCfg(prim_path="{ENV_REGEX_NS}/Robot/FrontCamera"),
SceneCameraCfg(prim_path="{ENV_REGEX_NS}/Robot/BackCamera"),
PerspectiveCameraCfg(eye=(4.0, -4.0, 3.0)),
],
streaming_envs=list(range(16)),
)
cameras 字段由各可视化器共用。Kit、Rerun 和 Viser 在图像面板中使用第一个场景相机;Newton GL 和 RTX 则提供上述来源下拉框。SceneCameraCfg 选择已有传感器,PerspectiveCameraCfg 配置查看器的交互相机。对于 Newton RTX,launch_simulation(env_cfg, ...) 在构造任何场景对象前向场景添加 CameraCfg,并通过 SceneCameraCfg 选择它。Newton GL 保留原生透视相机。Newton RTX 的透视渲染分辨率固定为初始 WindowCfg.size,窗口变化时缩放图像;传感器分辨率仍由 CameraCfg 控制。调整窗口大小不会重新分配传感器或 RTX 透视图像缓冲区。Newton GL 透视图像则跟随帧缓冲区尺寸。Newton 窗口按实际时间最多以 WindowCfg.fps 显示,默认为 30;改变仿真时间步不会改变此上限。无窗口按需捕获与窗口更新频率无关,Kit 使用应用自身的更新节奏。
Newton RTX 在 Newton GL 窗口中显示普通相机输出。相等的 OVRTXRendererCfg 配置共享同一个渲染器及其场景。NewtonRTXVisualizerCfg.renderer_cfg 为生成的透视相机选择渲染器,显式选中的场景相机则保留各自的渲染器。这里不使用 Newton 的 ViewerRTX 及其借用舞台接口。isaaclab_ov.stage.OvstageBackend 仍可供需要独立原生舞台的下游使用者使用,其 populate(stage, plan) 方法导入并克隆已声明的场景。
相机负责位姿、标定、图像缓冲区、捕获和清理。窗口导航调用 Camera.set_world_poses 和 Camera.set_intrinsic_matrices,图像通过 Camera.data 读取,不存在单独的透视渲染入口。系统不添加默认灯光,未定义灯光的场景保持无光照状态。关闭窗口后,其场景相机和渲染器继续存活。
没有 InteractiveSceneCfg 的脚本使用 ReplicateSession,在生成资产和相机前声明场景,即使只有一个环境也如此:
from isaaclab.app import launch_simulation
from isaaclab.assets import AssetBaseCfg
from isaaclab.cloner import ReplicateSession
from isaaclab.sensors import CameraCfg
from isaaclab.sim import CuboidCfg, DomeLightCfg, PinholeCameraCfg, SimulationCfg, SimulationContext
from isaaclab.utils import instantiate
from isaaclab.visualizers import SceneCameraCfg
from isaaclab_ov.renderers import OVRTXRendererCfg
from isaaclab_visualizers.newton import NewtonRTXVisualizerCfg
camera_cfg = CameraCfg(
prim_path="/World/PerspectiveCamera", width=960, height=540,
spawn=PinholeCameraCfg(focal_length=12.0), renderer_cfg=OVRTXRendererCfg(),
offset=CameraCfg.OffsetCfg(pos=(0.0, 0.0, 5.0), convention="opengl"),
render_settings={"omni:rtx:quality": ("Int", 0)},
)
sim_cfg = SimulationCfg(
visualizer_cfgs=[NewtonRTXVisualizerCfg(cameras=[SceneCameraCfg(prim_path=camera_cfg.prim_path)])]
)
target_cfg = AssetBaseCfg(prim_path="/World/Target", spawn=CuboidCfg(size=(1.0, 1.0, 1.0)))
light_cfg = AssetBaseCfg(prim_path="/World/Light", spawn=DomeLightCfg(intensity=1000.0))
with launch_simulation(sim_cfg, {"physics": "ovphysx", "visualizer": ["newton_rtx"]}):
sim = SimulationContext(sim_cfg)
with ReplicateSession((target_cfg, light_cfg, camera_cfg), num_clones=1, env_spacing=0.0):
instantiate(target_cfg)
instantiate(light_cfg)
camera = instantiate(camera_cfg)
sim.reset()
while sim.is_running():
sim.step()
camera.update(sim.get_physics_dt())
脚本持有相机并推进其传感器计时,与其他直接生成的传感器相同。SceneCameraCfg 可通过 prim 路径发现它,无需 InteractiveScene。
当来源、选择、分辨率或颜色设置改变时,会编译显示布局与通道映射。合成写入可复用的设备 RGBA 存储。Newton GL、Newton RTX 和 Kit 直接显示 CUDA 图像,不下载像素;通过 render_tiled_rgb_array() 录制,以及 Rerun/Viser 传输,则会显式回读合成图像。GPU API render_tiled_rgba_array() 返回借用的存储,下一次合成时会复用;如需保留帧,使用者必须复制。
两个场景相机都必须预先作为 CameraCfg 条目声明在场景中。键鼠导航会对所有环境中所选传感器的副本,施加相同的相机局部平移和旋转,包括未显示的副本;不会移动其他相机选项。这会真正改变传感器位姿,因此使用该传感器的策略和其他查看器也会看到新视角。导航读取实时传感器位姿,包括父刚体运动,不受 CameraCfg.update_latest_camera_pose 影响。暂停渲染会冻结图像显示和传感器导航,仅暂停训练则不会。
当 InteractiveSceneCfg.lazy_sensor_update=True 时,查看器仅读取选中的相机。未选中的相机仍会分配资源,且在其他使用者读取或场景采用即时传感器更新时,仍可能渲染。streaming_envs 选择显示的平铺图像,不决定捕获工作量。
示例#
运行 run_tiled_camera_visualizer.py 可演示相机流视图的两种用法:
场景中声明的相机附着在 AnymalD 机器人基座上,在 Kit 可视化器中显示
使用机器人已有的腕部相机传输画面,在 Newton 可视化器中显示
示例 1:跟随 AnymalD 机器人#
uv run python scripts/tutorials/07_visualizers/run_tiled_camera_visualizer.py \
--task Isaac-Velocity-Rough-AnymalD --num_envs 256 --viz kit
uv run python scripts/tutorials/07_visualizers/run_tiled_camera_visualizer.py ^
--task Isaac-Velocity-Rough-AnymalD --num_envs 256 --viz kit
脚本在构造环境前,为每个机器人的基座下添加 CameraCfg。其偏移定义相对于基座的视图,因此相机通过正常传感器生命周期跟随机器人。在 256 个环境中抽取 36 个用于显示。
Kit 可视化器:交互式视口
Kit 可视化器:串流相机视图
示例 2:传输机器人搭载相机的画面#
uv run --extra teleop python scripts/tutorials/07_visualizers/run_tiled_camera_visualizer.py \
--task IsaacContrib-Stack-Cube-Galbot-Left-Arm-Gripper-Visuomotor --num_envs 25 --viz newton_gl
uv run --extra teleop python scripts/tutorials/07_visualizers/run_tiled_camera_visualizer.py ^
--task IsaacContrib-Stack-Cube-Galbot-Left-Arm-Gripper-Visuomotor --num_envs 25 --viz newton_gl
Galbot 立方体堆叠环境自带腕部相机,可以从第一视角观察夹爪、桌面和立方体。脚本中的 NewtonGLVisualizerCfg 使用 /World/envs/env_.*/Robot/head_camera_sim_view_frame/head_camera 处的已有传感器传输画面;修改 streaming_sensor_prim_path 可显示其他相机。默认显示 25 个环境中 12 个相机的画面。
Newton 可视化器:交互式视口
Newton 可视化器:串流相机视图
配置#
在场景的 CameraCfg 上声明分辨率、位姿、渲染器和输出类型,再在 VisualizerCfg 中选择显示内容:
cameras=[SceneCameraCfg(prim_path=...)]选择场景相机,view=ImageViewCfg(source="name")选择具名传感器及其图像布局。Newton RTX 使用这些显式声明。对于其他查看器,
streaming_sensor_prim_path按配置的 prim 路径选择场景Camera,{ENV_REGEX_NS}宏使用场景的环境模板。省略时,Newton GL 从透视模式启动,并在 Camera View 下拉框中列出兼容场景相机。Kit 和 Web 查看器选择第一个兼容场景相机,若没有则面板为空。streaming_envs控制显示的环境格数。传入int可随机抽取指定数量的环境,传入list[int]则可固定显示指定索引的环境。streaming_gt_types选择显示的真值类型,例如["rgb", "depth", "segmentation", "normals"]。streaming_depth_min/streaming_depth_max设置深度色图的范围,单位为米。
选择或布局变化时,会准备图像布局和颜色表。着色与平铺在源设备上执行,并复用输出缓冲区。Kit 直接显示 CUDA 图像,录制和 Web 使用者则通过 render_tiled_rgb_array() 回读合成 RGB 图像。
显示源#
VisualizerCfg.cameras 接受 PerspectiveCameraCfg 定义交互视图,接受 SceneCameraCfg(prim_path=...) 选择场景中已有的相机传感器。Newton GL 和 RTX 提供来源下拉框,Kit、Rerun 和 Viser 则在相机面板中使用第一个场景来源。每个显式场景来源都必须提供所请求的 streaming_gt_types 通道。
故障排除#
--video viz:newton_gl:streaming_view 录制选定场景相机的平铺图像,而不是网络流。未设置 --viz 时,捕获按需执行,不打开窗口。添加 --viz newton_gl 可显示可视化器,但推进录制帧并不需要它。新的物理步会刷新图像,同一步内重复捕获则复用图像。
若视图提示没有匹配相机,请在场景中声明
CameraCfg,并通过cameras=[SceneCameraCfg(prim_path=...)]或view=ImageViewCfg(source="name")选择它。每个
streaming_gt_types条目都必须在所选相机的data_types中有对应输出;rgba也满足rgb请求。自动列出的相机支持所有所需通道,显式选择不兼容相机会报错。如果深度面板只显示单一颜色,请调整
streaming_depth_min和streaming_depth_max,使其覆盖场景中预期的深度范围。如果视图开销过大,可减小
streaming_envs、--num_envs或相机分辨率。
从自动生成相机迁移#
可视化器不再创建或销毁相机传感器。请用场景中的 CameraCfg 替换 streaming_cam_target_prim_path、streaming_cam_eye 和 streaming_cam_renderer_cfg:将 prim_path 放在所需父节点下,在相机配置中设置 offset 和 renderer_cfg,再通过 cameras=[SceneCameraCfg(...)] 选择它。这样,相机就纳入克隆计划及正常的传感器初始化、更新和销毁生命周期。完整选项对照见 3.0 迁移指南。
关闭可视化器不会影响相机,也不会影响读取同一相机的其他可视化器。streaming_envs 选择显示的平铺图像,不决定相机资源分配或捕获分辨率。