也许你正在为机器人算法编写调试工具,也许你需要一个轻量化的点云标注平台,又或者你想为深度学习模型创建一个交互式 Demo,但传统 3D 可视化方案冗长的代码和复杂的交互逻辑总让你望而却步。Viser 的诞生,正是为了让你能用最少的代码,在纯 Python 环境中快速搭建出丝滑的交互式 3D 应用。
Viser 是什么?
Viser 是一个专为计算机视觉与机器人领域打造的命令式 (Imperative) 3D 可视化库。它深受 Pangolin、rviz 等经典工具的启发,并创新性地将整个渲染引擎搬到了浏览器上。它追求两大核心目标:低门槛上手(几行代码就能查看点云或模型)和高自由度组合(能将基础组件灵活拼装成复杂的专业界面)。
核心能力一览
Viser 提供了一套全面且即开即用的能力矩阵:
多样的 3D 视觉要素:提供 API 来可视化点云、三角网格、骨骼动画、Catmull-Rom 样条曲线等多种 3D 基础图形元素。
丰富的交互式 GUI:内置按钮、滑块、输入框、颜色选择器等标准 Web 控件,可直接与 3D 场景参数绑定。
强大的场景交互工具:支持点选、框选、变换控制柄 (Transform Gizmos) 等高级交互功能。
灵活的相机控制:支持可编程的相机视角、渲染参数调节,并能实时追踪相机位姿。
远程与多客户端支持:基于 WebSocket 通信,支持多面板和视图同步连接,可通过 SSH 轻松访问。
原生特性与安装指引
Viser 支持与 Jupyter Notebook 完美集成,可直接在单元格中以内嵌 IFrame 的形式展示可视化结果。顶部的工具栏提供旋转、平移、缩放等基础操作,并提供预设视角切换和截图保存功能,用户无需编写额外代码即可完成场景浏览与图片导出。安装方式非常简单:
如果需要运行官方提供的丰富示例,可以安装额外的依赖:
pip install viser[examples]
工作原理与交互流程
Viser 采用客户端-服务器架构,其工作流程清晰直观,如下图所示:
整个流程的核心优势在于:开发者只需关注 Python 端的业务逻辑,而渲染、交互、多客户端管理等底层复杂性皆由 Viser 替您处理。
核心编程接口
Viser 提供三大核心 API,各自承担不同的职责,共同支撑起整个 3D 交互应用:
接口类别 入口对象 核心职责
场景接口 server.scene 负责在 3D 空间中添加、更新或移除视觉元素,如点云、网格、坐标轴等
GUI 接口 server.gui 负责构建 2D 图形用户界面控件,并将其与场景参数实时绑定
交互接口 回调函数 负责处理用户在浏览器中的交互事件,如点击 mesh、拖拽变换控件等
Scene API:添加 3D 视觉元素
Scene API 是所有可视化操作的起点,用于在 3D 空间中创建和管理各种视觉内容。
添加随机点云 — 30 秒即可完成的示例:
import numpy as npimport viser# 启动 Viser 服务器server = viser.ViserServer()# 生成包含 10000 个随机点的点云数据pts = np.random.randn(10000, 3)# 将点云添加到场景中,指定点的大小和颜色server.scene.add_points( "/random_cloud", pts, size=0.01, color=(255, 100, 100))# 启动服务,终端会打印访问链接server.serve()
运行上述代码后,在浏览器中打开终端显示的链接(默认为 http://localhost:8080),即可看到一个由 10000 个随机点组成的 3D 点云,并可用鼠标进行旋转、缩放和平移操作。
更复杂的 3D 元素添加示例:
# 添加坐标轴server.scene.add_axes("/axes")# 添加自定义网格vertices = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0]], dtype=np.float32)faces = np.array([[0, 1, 2], [1, 3, 2]], dtype=np.int32)server.scene.add_mesh_simple( "/custom_mesh", vertices, faces, color=(0, 200, 100), flat_shading=True)# 添加从 (0,0,0) 到 (1,2,3) 的线条server.scene.add_line("/line", np.array([[0, 0, 0], [1, 2, 3]]), color=(200, 100, 0), line_width=3)
GUI API:绑定交互控件
GUI API 提供了按钮、滑块、输入框、颜色选择器等标准 Web 控件,可以直接绑定到 3D 场景参数,实现实时交互调参。
import numpy as npimport viserserver = viser.ViserServer()pts = np.random.randn(10000, 3)# 添加一个控制点大小的滑块size_slider = server.gui.add_slider( "Point Size", # 控件标签 0.001, # 最小值 0.1, # 最大值 step=0.001, # 步长 initial_value=0.01 # 初始值)# 添加一个 RGB 颜色选择器color_picker = server.gui.add_rgb( "Color", initial_value=(100, 200, 255))# 创建点云对象,并将其属性与 GUI 控件初始值绑定handle = server.scene.add_points( "/cloud", pts, size=size_slider.value, color=color_picker.value)# 定义滑块更新时的回调函数@size_slider.on_updatedef _(evt): handle.size = size_slider.value# 定义颜色选择器更新时的回调函数@color_picker.on_updatedef _(evt): handle.color = color_picker.valueserver.serve()
通过这样简洁的绑定,用户在浏览器中拖动滑块或调整颜色选择器时,3D 场景中的点云会实时更新视觉表现。
此外,Viser 还支持更丰富的 GUI 组件:
# 添加按钮button = server.gui.add_button("Reset View")# 添加文本输入框text_input = server.gui.add_text_input("Model Path", placeholder="/path/to/model")# 添加下拉选择框dropdown = server.gui.add_dropdown("Object Type", ["Point Cloud", "Mesh", "Skeleton"])
交互事件:处理用户操作
Viser 提供了丰富的场景交互工具,开发者可以监听点击、选择、变换控制柄等事件,构建高度交互的 3D 应用。
Mesh 点击事件 — 演示如何让 3D 物体响应鼠标点击:
import numpy as npimport viserserver = viser.ViserServer()# 创建 4×4 的网格,为每个格子添加独立的 meshfor i in range(4): for j in range(4): mesh_handle = server.scene.add_mesh_simple( f"/mesh_{i}_{j}", vertices=np.array([ [i, j, 0], [i+0.5, j, 0], [i+0.5, j+0.5, 0], [i, j+0.5, 0] ], dtype=np.float32), faces=np.array([[0, 1, 2], [0, 2, 3]], dtype=np.int32), color=(128, 128, 128) ) # 绑定点击事件:每次点击切换不同的形状 click_counter = 0 @mesh_handle.on_click def _(evt, i=i, j=j, handle=mesh_handle): nonlocal click_counter # 三种状态循环:灰色方块 -> 彩色方块 -> 彩色球体 if click_counter % 3 == 0: handle.color = (255, 100, 100) elif click_counter % 3 == 1: # 将 mesh 替换为球体 server.scene.add_sphere( f"/mesh_{i}_{j}", radius=0.3, center=(i+0.25, j+0.25, 0), color=(100, 255, 100) ) click_counter += 1server.serve()
变换控制柄 — 允许用户直接在 3D 场景中拖拽移动、旋转或缩放物体:
# 添加可拖拽的三维坐标帧frame_handle = server.scene.add_frame( "/transformable_frame", show_axes=True, axes_length=0.5, axes_radius=0.02)# 监听变换更新事件@frame_handle.on_updatedef _(evt): # evt.position 和 evt.rotation 包含最新的位姿信息 print(f"Position: {evt.position}, Rotation: {evt.rotation}")
相机控制 — 支持编程式控制相机,并可实时追踪每个连接客户端的相机位姿:
import numpy as np# 设置相机视角server.set_camera_position(np.array([5.0, 5.0, 5.0]))server.set_camera_look_at(np.array([0.0, 0.0, 0.0]))# 为每个连接的客户端创建帧标记并绑定点击事件@server.on_client_connectdef _(client_handle): # 在场景中放置十个坐标系标记 for i in range(10): position = np.random.uniform(-3, 3, size=3) frame = client_handle.scene.add_frame( f"/frame_{i}", position=position, show_axes=True, axes_length=0.2, axes_radius=0.01 ) # 当用户点击某个坐标系标记时,将相机移动到该位置 @frame.on_click def _(evt, pos=position, client=client_handle): client.set_camera_position(pos + np.array([0.5, 0.5, 0.5])) client.set_camera_look_at(pos)
高级特性:多客户端与远程访问
Viser 原生支持多客户端同时连接,每个客户端可以拥有独立的场景视图。同时,其纯 Web 前端的架构让远程访问变得极其便捷——只需在服务器上运行 Viser,然后在本地浏览器中输入对应的 URL(无需配置 X11 转发或额外的远程桌面软件)。
适用场景
Viser 的设计使其在以下场景中表现出色:
计算机视觉与机器人调试:快速查看点云配准结果、SLAM 轨迹、机器人关节状态等。
3D 数据处理与标注:加载 .obj/.ply 等格式的网格模型进行交互式查看,或通过点选和变换控件进行数据标注。
学术研究与论文 Demo:Viser 团队提供了 BibTeX 引用格式,并支持将可视化嵌入静态网页(导出为 .viser 文件或独立 HTML),便于在论文或项目主页中展示研究成果。
深度学习的交互式 Demo:与 Gradio 等工具类似,Viser 可以为模型提供基于 Web 的交互式演示界面,支持远程用户实时调节参数并观察结果。
小结
Viser 凭借其极简的 API 设计、强大的交互能力和基于浏览器的天然跨平台特性,为 Python 生态中的 3D 可视化带来了一套全新的范式。无论你是需要在远程服务器上快速调试点云数据,还是想为机器人算法构建一个功能完备的调试控制台,Viser 都能让你从繁重的 OpenGL 绑定和 Web 前端开发中解脱出来,专注于真正重要的算法与业务逻辑。
编辑:余文彬
审校:余雨馨