- 科研
- 自动驾驶
- 物理引擎
【免费下载链接】webots
Webots Robot Simulator
导读
Web Animation 是 Webots 内建的一项导出功能:它可以把正在运行的 3D 仿真实时录制为一个"可交互的电影"——一个独立的HTML5页面,页面自带播放/暂停等播放控件,同时还允许观众在任意时刻自由旋转、缩放、平移视角。与单纯的 Web Scene 导出(静态 3D 场景快照)不同,Web 动画额外导出一个包含运动物体轨迹的JSON动画文件,完整重现仿真过程中物体的位移、旋转与外观变化。阅读完本文,你将掌握 Web 动画的录制与导出流程、webots-viewWeb 组件(WebotsView.js 包)的属性与方法 API、动画文件记录的字段范围与底层实现原理,并了解如何在自有网站中嵌入动画、如何规避浏览器本地文件安全限制。
什么是 Web 动画
Webots 可以将一段仿真录制为交互式 3DHTML页面,效果类似"带播放控制条的电影",但观看者可以在播放过程中随时改变视角(用鼠标或触摸屏导航,操作方式与 Webots 内 3D 窗口一致)。
其机制与 Web Scene 导出 基本一致:导出时先生成一个包含世界图形信息的W3D文件(Webots 自定义的、基于 XML 的 3D 图形格式),再生成HTML5页面和CSS样式文件。Web 动画与 Web Scene 的唯一区别在于:Web 动画额外导出一个JSON动画文件,其中记录了运动物体的位置序列,页面加载后由播放器按时间轴回放这些更新。
下图为 Webots 生成的一个动画页面示例(原文档中的示例动画页面由 Cyberbotics 官方托管):
说明:在项目仓库的 docs/guide/web-animation.md 中可查看本文对应的官方文档原文;关于导出过程中的静态场景(W3D)、
CSS文件与浏览器兼容性细节,请同时参考 docs/guide/web-scene.md。
如何导出 Web 动画
导出过程全部在 Webots 图形界面中完成,无需编写任何代码:
- 打开一个正在(或准备)运行的仿真世界;
- 在主菜单中选择
Share...; - 在弹出的共享对话框中,选择是上传到 webots.cloud还是保存到本地;
- 点击
Record and export animation按钮开始录制; - 在仿真中执行你想要展示的动作;
- 录制完成后,点击
Stop HTML5 animation按钮结束录制并保存动画; - Webots 会询问是否用操作系统默认浏览器播放生成的文件。
导出产物
录制结束后,目标HTML文件所在目录会同时生成以下文件:
| 文件 | 作用 |
|---|---|
*.html | 包含 Webots 播放器(web component)的 HTML5 页面 |
*.css | 页面样式,仅作为样式参考,可以修改或删除 |
*.w3d | 3D 场景图形文件 |
*.json | 动画序列文件(运动物体位置、颜色等更新的时间序列) |
| 所需纹理图片 | 场景引用的贴图资源 |
注意:由于默认浏览器对本地
file协议的限制(详见下文"浏览器兼容性与安全限制"一节),播放选项可能无法正常工作,此时请改用本地 HTTP 服务器方式预览。
用 Supervisor 控制器控制录制
除了 GUI 按钮,一个 Supervisor 控制器同样可以启动或停止动画录制,这让批量生成动画、或让仿真在特定条件满足时自动开始录制成为可能。对应 API 声明位于 include/controller/c/webots/supervisor.h:
bool wb_supervisor_animation_start_recording(const char *filename); bool wb_supervisor_animation_stop_recording();在 Webots 内部,WbSupervisorUtilities会将 Supervisor 发出的录制请求与WbAnimationRecorder的状态信号(animationStartStatusChanged/animationStopStatusChanged)关联起来(见 src/webots/nodes/utils/WbSupervisorUtilities.cpp)。
如何在网站中嵌入 Web 动画
嵌入方式与 Web Scene 完全一致,请参考 docs/guide/web-scene.md#how-to-embed-a-web-scene-in-your-website 中的说明:
- 导出的
HTML页面本身即为最简单的集成参照,外站可以直接引用;导出的CSS文件可以在集成过程中替换。 - 若追求更省事的方案,可以用一个指向生成页面的
<iframe>标签嵌入。
无论哪种方式,播放器所需的CSS、JavaScript等资源都可以长期复用 Cyberbotics 官网托管的资源。
编程接口:webots-viewWeb 组件
Web 动画页面由 WebotsView.js 包中的webots-viewWeb 组件负责播放。组件通过自定义属性接收配置,通过公开方法实现更复杂的交互。
组件属性(Attributes)
| 属性 | 说明 |
|---|---|
data-thumbnail | 缩略图.jpg文件名;不设置时加载期间显示默认缩略图 |
data-scene | 包含 3D 场景的.w3d文件名 |
data-animation | 包含动画序列的.json文件名 |
data-autoplay | 布尔值,是否自动播放动画,默认为true |
data-isMobileDevice | 布尔值,指定应用是否运行在移动设备上 |
showCustomWindow | 布尔值,是否在工具栏显示自定义窗口按钮;默认隐藏,且必须在加载动画之前设置 |
关键行为:
webots-view的属性只在页面加载时求值一次。如果data-scene与data-animation均已设置,组件会自动尝试加载动画。
典型用法示例(将动画文件与页面放在同一目录时):
<webots-view ><script> const view = document.querySelector('webots-view'); view.loadAnimation('scene.w3d', 'animation.json', true, false, 'scene.jpg', false); </script>自定义信息窗口
你可以将一个空窗口个性化为动画的辅助信息面板(如显示图表、动画说明等)。要启用它,必须在加载动画之前将webots-view元素的showCustomWindow属性设为true,之后工具栏右侧会出现一个打开该窗口的图标。
可用以下函数个性化窗口内容:
| 函数 | 说明 |
|---|---|
setCustomWindowTitle(title) | 设置窗口标题,title为新标题 |
setCustomWindowTooltip(tooltip) | 设置窗口按钮的提示文字,tooltip为新的提示 |
setCustomWindowContent(content) | 设置窗口内容(替换已有内容),content为新内容 |
注意:这些函数必须在
onReady()被调用之后调用,以确保窗口已经创建完成。
动画文件格式与底层实现
JSON 文件结构
动画JSON文件不是对每一帧做完整快照,而是只记录发生变化的部分。从 src/webots/engine/WbAnimationRecorder.cpp 的computeUpdateData()可以看出,每一帧的结构为:
{ "time": 12.34, "updates": [ { "id": 42, "translation": "0.1 0.2 0.3", "rotation": "0 1 0 1.5708" } ] }文件头部还包含两个关键元数据(见 WbAnimationRecorder.cpp):
basicTimeStep:由WorldInfo.basicTimeStep与WorldInfo.fps共同推导,公式为basicTimeStep * ceil((1000.0 / fps) / basicTimeStep),是播放时每个动画帧对应的仿真时间间隔;labelsIds:动画中涉及的 Supervisor 文本标签(label)id 列表,用;分隔。
录制停止时,WbAnimationRecorder::stopRecording()会把初始状态帧(时间time: 0)写在所有更新帧之前;初始状态只包含那些在动画期间实际发生过变化的节点(通过WbAnimationCommand::isChangedFromStart()判断)。如果整个仿真期间没有任何节点发生变化,Webots 会给出明确提示:无动画内容可导出,此时应改用 Web Scene 导出。
录制器的核心流程
Web 动画录制在 Webots 内部由单例WbAnimationRecorder(src/webots/engine/WbAnimationRecorder.hpp)实现,其工作流程为:
start():先把世界导出为 HTML/W3D 场景(world->exportAsHtml(fileName, true)),再把目标文件名由.html替换为.json并开始录制(WbAnimationRecorder.cpp);populateCommands():遍历世界中所有子节点,对每个实现了fieldsToSynchronizeWithW3d()的节点创建一个WbAnimationCommand,监听其相关字段的valueChanged等信号;USE节点被跳过——DEF/USE 机制由前端webots.min.js处理(WbAnimationRecorder.cpp);update():在每个物理步结束(physicsStepEnded信号)时检查是否满足当前时间 - 上次更新时间 >= 1000.0 / fps,满足则把这一时刻的脏字段(dirty fields)序列化写入JSON文件(WbAnimationRecorder.cpp)——这就是下文"刷新率"一节中WorldInfo.fps起作用的代码依据;stop():断开信号、写入头部与初始帧、收尾关闭文件,并询问用户是否在浏览器中打开(WbAnimationRecorder.cpp)。
另外,WbAnimationCommand在序列化translation与rotation时做了数值舍入(ROUND(x, 0.0001)写入文件、ROUND(x, 0.001)做变化检测),既能压缩数据量,又避免每帧都因浮点噪声写出无意义更新(WbAnimationRecorder.cpp)。
节点删除与标签(Labels)
- 当某个节点在录制过程中被删除,
updateCommandsAfterNodeDeletion()会移除对应的录制命令,避免写入失效节点数据(WbAnimationRecorder.cpp); - Supervisor 在仿真中添加的文本标签(
wb_supervisor_set_label)也会被同步记录为动画的labels数组,可随动画一起回放。
动画记录字段的范围(Limitations)
动画文件只记录以下字段的变化:
| 节点字段 | 说明 |
|---|---|
LED.color | LED 颜色变化 |
Material.diffuseColor | 漫反射颜色变化 |
Material.emissiveColor | 自发光颜色变化 |
TextureTransform.translation | 纹理坐标平移(仅针对 Track 节点,用于表现传送带等履带纹理运动) |
Pose.rotation | 姿态旋转 |
Pose.translation | 姿态平移 |
Light.color | 光源颜色变化 |
Light.on | 光源开关变化 |
其余字段均不会被记录;节点的插入与删除也不会被记录。其他限制请参考 docs/guide/web-scene.md#limitations(如Skin节点不支持、Pen设备不支持、同一页面只能存在一个webots-view元素等)。
从源码角度看,"记录哪些字段"由各节点实现的
fieldsToSynchronizeWithW3d()方法决定,录制器只同步这些字段。例如:
- src/webots/nodes/WbPose.cpp:
Pose同步translation、rotation;- src/webots/nodes/WbLight.cpp:
Light同步color、on、intensity、ambientIntensity、castShadows;- src/webots/nodes/WbMaterial.cpp:
Material同步ambientIntensity、shininess、specularColor、transparency、emissiveColor等;- src/webots/nodes/WbTextureTransform.cpp:
TextureTransform同步center、rotation、scale、translation。
一个值得注意的实现细节:LED.color本身并没有独立的序列化逻辑——在 src/webots/nodes/WbLed.cpp 中,LED 节点会递归查找其子结构中的Material、PBRAppearance与Light节点,并把颜色写入这些节点(setMaterialsAndLightsColor())。因此 LED 颜色动画在JSON文件中实际表现为Material.diffuseColor/Material.emissiveColor/Light.color等字段的更新,这也解释了为什么LED.color出现在可记录字段列表中。
场景刷新率(Scene Refresh Rate)
动画的渲染节奏由浏览器标准的window.requestAnimationFrame()驱动,其回调次数通常为每秒 60 次,多数浏览器中会与显示器刷新率保持一致(参见 MDN 关于requestAnimationFrame的文档)。
但刷新率还受WorldInfo.basicTimeStep影响:因为动画更新只在仿真步进(physics step)时才会发出。实际刷新率可用下图公式估算:
即实际帧率受以下三者共同制约:
- 浏览器
requestAnimationFrame提供的显示刷新率(通常约 60 Hz); - 仿真步长
WorldInfo.basicTimeStep(更新只在每个仿真步发送); WorldInfo.fps(录制器按1000 / fps毫秒间隔采样,见上文WbAnimationRecorder::update()源码)。
实际刷新率约为min(1 / basicTimeStep, 显示刷新率)附近,并受WorldInfo.fps的采样上限约束。
注意:不建议在录制动画过程中修改
WorldInfo.FPS或WorldInfo.basicTimeStep字段,否则会导致动画时间轴与采样节奏错乱。
浏览器兼容性与安全限制
Web 动画播放器内部基于WRENJS库(Webots 渲染引擎 WREN 编译为 WebAssembly 的版本,底层依赖WebGL 2)。相关限制与应对方法与 Web Scene 一致,详见 docs/guide/web-scene.md#remarks-on-the-used-technologies-and-their-limitations,核心要点如下:
- WebGL 2 支持:新版 Firefox、Chrome、Edge 均已支持;Safari 尚未支持,遇到渲染异常请先确认浏览器设置中 WebGL 2 已启用。
- 本地文件(
file协议)限制:Chrome、Firefox 68+ 等浏览器默认禁止通过file协议打开本地W3D与纹理文件,而播放器需要读取这些文件。解决方式有两种:- 在导出文件所在目录启动本地 HTTP 服务器,然后通过服务器访问
HTML文件:# Python 3 python3 -m http.server # Python 2 python -m SimpleHTTPServer # Node.js(需先全局安装 http-server) sudo npm install -g http-server http-server - 临时关闭浏览器安全标志:
- Chrome:以
--allow-file-access-from-files或--disable-web-security --user-data-dir=.chrome启动; - Firefox:在地址栏输入
about:config,搜索privacy.file_unique_origin或security.fileuri.strict_origin_policy,双击将其从true改为false。
- Chrome:以
- 在导出文件所在目录启动本地 HTTP 服务器,然后通过服务器访问
总结
Web Animation 把 Webots 仿真与 Web 发布无缝衔接:通过 GUI 一键录制或 Supervisor API 程序化控制,即可产出一套HTML + W3D + JSON + CSS的交互式动画页面,再由webots-viewWeb 组件在任意支持 WebGL 2 的浏览器中回放。录制过程以"只记录变化字段 + 时间序列"的方式生成紧凑的 JSON 动画,字段范围受各节点fieldsToSynchronizeWithW3d()约束,播放节奏则由WorldInfo.basicTimeStep、WorldInfo.fps与浏览器刷新率共同决定。掌握了本文的导出流程、组件 API 与底层机制,你便可以在自己的网站中快速发布可交互、可自由观察视角的机器人仿真动画。
- 科研
- 自动驾驶
- 物理引擎
【免费下载链接】webots
Webots Robot Simulator
相关推荐
Webots 网页接口(Web Interface)完整指南:Web 场景导出、动画录制与 Streaming 流式传输
Webots 网页接口(Web Interface)完整指南:Web 场景导出、动画录制与 Streaming 流式传输 Webots 提供了一整套"仿真上 W
科研自动驾驶物理引擎OpenNHP 架构图动画录制指南:用 Puppeteer 与 ffmpeg 将交互式 SVG 架构图导出为 GIF/MP4
OpenNHP 架构图动画录制指南:用 Puppeteer 与 ffmpeg 将交互式 SVG 架构图导出为 GIF/MP4 导读 OpenNHP(Zero T
网络安全零信任密码学身份认证网络Carbon Components React数据可视化:图表、仪表盘和数据表格的高级应用
Carbon Components React数据可视化:图表、仪表盘和数据表格的高级应用 Carbon Components React是IBM开发的基于Ca
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考