- 科研
- 自动驾驶
- 物理引擎
【免费下载链接】webots
Webots Robot Simulator
导读
本教程面向已完成 Webots 入门系列前两课的开发者,系统讲解如何用Light 光源节点与PBRAppearance 物理渲染外观节点快速搭建视觉上真实、物理上可信的仿真环境。你将掌握 Webots 三种光源的适用场景与性能差异、PBRAppearance 核心字段的语义与取值、磁盘纹理的加载与 UV 映射规则,以及渲染模式的切换技巧,最终通过一份可直接对照的解决方案世界文件完成从“能跑”到“好看”的仿真升级。
教程背景与前置条件
本教程是 Webots 官方教程系列(tutorials.md)的第三课,时长约 20 分钟,承接 Tutorial 2: Modification of the Environment 的成果。在开始之前,你需要已经完成以下工作:
- 拥有一个基于 Tutorial 1/2 建立的项目目录(名为
my_first_simulation); - 场景中已有一个带物理属性的球(
BALLSolid,内含Sphere几何与Physics节点); - 已用
Floor与四面Solid墙围出约 1m × 1m 的方形区域; - 已在四面墙上正确使用DEF-USE 机制(教程 2 的核心内容),这是本教程“一键把四面墙同时变蓝”的前提。
在场景树中,这些对象的结构形如:
Floor E-puck DEF BALL Solid DEF WALL_1 Solid (children 中 DEF WALL_SHAPE Shape) DEF WALL_2 Solid (children 中 USE WALL_SHAPE) DEF WALL_3 Solid (children 中 USE WALL_SHAPE) DEF WALL_4 Solid (children 中 USE WALL_SHAPE)动手练习 #1:在上一教程成果的基础上,使用菜单
File / Save World As...将当前仿真另存为appearance.wbt。
本教程的目标是理解与图形渲染相关的节点。恰当使用这些节点,可以非常快速地创建视觉效果良好的仿真。良好的图形质量不仅提升用户体验,对机器人通过视觉感知环境的仿真(相机图像处理、巡线等)同样至关重要。本教程结束时的效果见最终仿真效果图。
理解 Webots 的光源系统:三种 Light 节点
一个世界的照明由 Light 节点家族与 Background 节点共同决定。Webots 提供三种可直接实例化的光源,全部继承自抽象的Light基类(其派生关系可参见 node-chart.md 中的节点继承图):
| 光源节点 | 物理模型 | 典型比喻 | 参考文档 |
|---|---|---|---|
| DirectionalLight | 无限远光源,沿平行射线照明,光强不随距离衰减 | 太阳 | directionallight.md |
| PointLight | 从单一空间点向四周均匀发射光 | 灯泡 | pointlight.md |
| SpotLight | 从特定点沿特定方向、约束在锥形立体角内发射光 | 手电筒 | spotlight.md |
下图展示了三种光源在同一场景中的渲染差异。
Light基类定义了所有光源共有的字段,完整语义如下(引自 light.md):
Light { SFFloat ambientIntensity 0 # [0, 1] SFColor color 1 1 1 # any color SFFloat intensity 1 # [0, inf) SFBool on TRUE # {TRUE, FALSE} SFBool castShadows FALSE # {TRUE, FALSE} }intensity:光源直接发射光的亮度;ambientIntensity:环境光分量的强度。注意它只作用于使用旧版 Appearance 节点的对象,对使用PBRAppearance的对象无效;color:直接光与环境光的 RGB 光谱颜色;on:光源开关(TRUE 打开 / FALSE 关闭);castShadows:是否投射阴影。开启后,除半透明对象以及 IndexedLineSet、PointSet 图元之外,所有可渲染对象之间都会产生清晰的阴影;阴影是叠加式的(多个光源可同时投射)。只开启一个光源的阴影就可能显著影响整体渲染性能,尤其是世界中对象众多或网格复杂时,在封闭空间内还可能出现阴影瑕疵。
性能提示:光源在性能上代价较高,会降低仿真速度(尤其开启阴影时)。尽量压缩光源数量以提升渲染速度。就效率而言,
PointLight比SpotLight高效,但比DirectionalLight低效。从源码角度看,渲染层在src/wren中维护了各类光源的上限(gMaxActiveDirectionalLights等常量定义于src/wren/Constants.hpp);由于 Firefox 在 Windows 与 macOS 上的性能问题,默认每类光源限制为 48 个(详见 light.md 的 Limitation 一节),需要更多光源时必须自行从源码编译并同步修改src/wren/Constants.hpp与src/wren下的多个 shader 文件。
场景中的光源藏在哪里:TexturedBackgroundLight PROTO
在本教程的仿真中,场景树里看不到任何 Light 节点——因为光源被封装在TexturedBackgroundLightPROTO 节点内部。打开 TexturedBackgroundLight.proto 可以看到它的实现逻辑:该 PROTO 根据texture字段(默认"mountains")选择天空盒,并通过 JavaScript 模板自动计算出一个 DirectionalLight 的direction、color、intensity,使其与背景天空的光照方向与颜色相匹配:
DirectionalLight { ambientIntensity 1 direction %<= direction[0] >% %<= direction[1] >% %<= direction[2] >% color %<= color[0] >% %<= color[1] >% %<= color[2] >% intensity %<= luminosity * intensity >% ... castShadows IS castShadows }也就是说,方向光的强度与方向根据场景背景自动计算,你只需搭配同纹理的TexturedBackground(天空盒背景)即可获得自洽的环境照明。PROTO 还暴露了luminosity(乘到Light.intensity上)与castShadows两个可调字段。若要更精细地控制灯光,也可以随时在场景树中手动添加独立的三种 Light 节点。
给墙面改色:Appearance 与 PBRAppearance 的选择
Shape节点的外观由 Appearance 或 PBRAppearance 节点决定,它们负责对象的颜色、纹理等视觉属性。
PBR(Physically-Based Rendering,基于物理的渲染)是一类基于物体物理属性的着色模型,区别于旧式 Blinn-Phong BRDF 模型(即 Appearance 节点所用的模型)。Webots 的 PBR 着色模型对直接光照采用 Lambertian 漫反射、Cook-Torrance 高光与 Fresnel-Schlick GGX,对环境光与反射则使用基于图像的照明(IBL)BRDF,能带来高度真实的渲染效果。下图是两者在同一对象上的渲染对比。
建议:优先使用 PBRAppearance以获得更佳渲染效果。唯一需要注意的限制是:
PBRAppearance不能用于包含IndexedLineSet或PointSet几何的Shape节点。
PBRAppearance 核心字段速查
PBRAppearance的完整字段定义如下(引自 pbrappearance.md):
PBRAppearance { SFColor baseColor 1 1 1 # any color SFNode baseColorMap NULL # {ImageTexture, PROTO} SFFloat transparency 0 # [0, 1] SFFloat roughness 0 # [0, 1] SFNode roughnessMap NULL # {ImageTexture, PROTO} SFFloat metalness 1 # [0, 1] SFNode metalnessMap NULL # {ImageTexture, PROTO} SFFloat IBLStrength 1 # [0, inf) SFNode normalMap NULL # {ImageTexture, PROTO} SFFloat normalMapFactor 1 # [0, inf) SFNode occlusionMap NULL # {ImageTexture, PROTO} SFFloat occlusionMapStrength 1 # [0, inf) SFColor emissiveColor 0 0 0 # any color SFNode emissiveColorMap NULL # {ImageTexture, PROTO} SFFloat emissiveIntensity 1 # [0, inf) SFNode textureTransform NULL # {TextureTransform, PROTO} SFString name "PBRAppearance" # any string }本教程用到的三个关键字段:
| 字段 | 语义 | 取值范围/说明 |
|---|---|---|
baseColor | 材质表面的基色(albedo),类比旧模型的diffuseColor | 任意 RGB 颜色 |
metalness | 材质的金属度:0 为完全介电质(非金属),1 为完全金属 | [0, 1],建议只用 0 或 1,因为真实世界不存在“半金属”材质 |
roughness | 材质的粗糙度:0 为完美光滑表面,1 为高度粗糙表面 | [0, 1],类比旧模型shininess的倒数 |
其他常用字段包括:baseColorMap(albedo 贴图,会覆盖baseColor)、transparency(透明度,非零时对象不再投射阴影)、normalMap(法线贴图,在平面上制造浮雕感或为低模增加细节)、occlusionMap(预烘焙的环境光遮蔽信息)、emissiveColor/emissiveIntensity(自发光)、IBLStrength(来自Background的光照贡献缩放系数)等,完整语义详见 pbrappearance.md。
动手练习 #2:把四面墙一次变蓝
在场景树中展开代表第一面墙的Shape节点,向其appearance字段添加一个PBRAppearance节点:
- 用颜色选择器将
baseColor字段设为蓝色; - 用字段编辑器将
metalness字段设为0(墙面是典型的非金属介电质); - 用字段编辑器将
roughness字段设为0.5(中等粗糙的墙面质感); - 关键一步:由于上一教程中 DEF-USE 机制的正确实现(四面墙共享同一个
DEF WALL_SHAPE),此时所有墙都会同步变为蓝色。
在最终的解决方案文件 appearance.wbt 中,这面墙的完整写法为:
DEF WALL_SHAPE Shape { appearance PBRAppearance { baseColor 0.12549 0.368627 0.729412 roughness 1 metalness 0 } geometry Box { size 0.02 0.98 0.1 } }其余三面墙的children中只需USE WALL_SHAPE,即可共享同一外观定义。
使用预定义 PBRAppearance:给球换上旧钢材
Webots 发行版内置了大量预定义的 PBRAppearance(按类别存放在projects/appearances/protos/目录下的 PROTO 文件中,例如OldSteel.proto)。你可以直接复用它们,避免从零调参。
动手练习 #3:为球添加一个预定义的 PBRAppearance
- 选中
appearance字段并移除之前添加的节点:按键盘上的 delete 键,或右键该字段并在菜单中选择delete。此时字段应显示appearance NULL(而不是appearance PBRAppearance);- 再次双击该字段,导航到
PROTO nodes (Webots Projects)→appearances,选择OldSteel (PBRAppearance)。
这样,球的材质便换成了带有金属感的旧钢材外观,配合场景中的TexturedBackgroundLight环境光,球体表面会呈现出金属反射质感。
从磁盘加载纹理:ImageTexture 与 UV 映射
纹理可以让对象表面产生真实的材质细节。对一个滚动的球而言,表面纹理还能帮助观察者直观感受其滚动运动。
动手练习 #4:给球应用一张本地纹理
- 下载仓库中现成的纹理 red_brick_wall.jpg(红砖墙贴图),保存到你的磁盘;
- 将
appearance字段中先前添加的节点移除,改添加一个 PBRAppearance 节点;- 为该 PBRAppearance 的
baseColorMap字段添加一个 ImageTexture 节点(albedo 贴图,会覆盖baseColor);- 点击
Add按钮,为 ImageTexture 的url字段添加一个条目;- 用
Select按钮定位到刚才保存纹理的位置并选中它。
ImageTexture节点的字段定义如下(引自 imagetexture.md):
ImageTexture { MFString url [ ] SFBool repeatS TRUE # {TRUE, FALSE} SFBool repeatT TRUE # {TRUE, FALSE} SFInt32 filtering 4 # [0, 5] }url:纹理文件路径,支持 JPEG 与 PNG 格式(PNG 的 alpha 通道可渲染半透明效果);repeatS/repeatT:纹理在 s / t 方向是否重复填充(超出 [0,1] 坐标范围时)。设为 FALSE 则钳制在 [0,1] 内;filtering:过滤质量等级,0 为最近邻采样(无过滤,易产生锯齿伪影),1 为简单 mipmap,2 以上叠加各向异性过滤。通常 4 以内对运行时性能影响不大,但会略微增加初始化时间(生成 mipmap)。
纹理路径的搜索规则
教程强调:纹理 URL 必须要么相对于你项目目录的worlds目录定义,要么相对于默认项目目录WEBOTS_HOME/projects/default/worlds定义。这正是 Webots 纹理路径搜索算法(引自 imagetexture.md 的 Search Rule 一节)的体现:
i = current_url_index generic_textures_path = "$WEBOTS_HOME/projects/default/worlds" if is_absolute(url[i]) then if is_existing(url[i]) return url[i] else return Error else if defined_in_a_project_PROTO(current_node) and exists(PROTO_path + url[i]) return PROTO_path + url[i] else if exists(world_path + url[i]) return world_path + url[i] else if defined_in_a_webots_PROTO(current_node) and exists(PROTO_path + url[i]) return PROTO_path + url[i] else if exists(generic_textures_path + url[i]) return generic_textures_path + url[i] endif endif return Error相对路径会依次尝试:当前项目 PROTO 所在目录 →当前世界的worlds目录→ Webots 内置 PROTO 目录 →$WEBOTS_HOME/projects/default/worlds通用纹理目录。本教程把纹理放在默认项目目录下,因此在解决方案中直接写成webots://协议路径即可:
baseColorMap ImageTexture { url [ "webots://projects/default/worlds/textures/red_brick_wall.jpg" ] }webots://是 Webots 内置的资源寻址协议,等价于从WEBOTS_HOME根目录解析路径,可确保跨机器可移植。
UV 映射与纹理观察
把red_brick_wall.jpg在图片查看器中打开,同时观察它在 Webots 3D 视图中的 Sphere 表面上如何映射:纹理按预定义的UV 映射函数被贴到几何节点上(各类几何的具体映射规则详见 imagetexture.md)。所谓 UV 映射,就是把二维图像坐标 (s,t) 映射到三维模型表面的一种函数关系:纹理坐标系的 s 轴对应图像底边,t 轴对应图像左边,图像左下角像素对应 s=0、t=0,右上角像素对应 s=1、t=1。正是这一映射让平面贴图“包裹”住球面,也让你能通过砖纹的流动观察球的旋转与滚动。
渲染选项:线框模式与辅助显示
Webots 在View菜单中提供了多种渲染模式,可用于调试与教学。
动手练习 #5:用菜单项
View / Wireframe Rendering以线框模式查看仿真,观察对象的三角面片结构;随后用View / Plain Rendering恢复实体渲染模式。
其他常用的渲染辅助功能:
- 查看坐标系:
View / Optional Rendering / Show Coordinates System,快捷键ctrl-F1; - 查看距离传感器射线:
View / Optional Rendering / Show DistanceSensor Rays,快捷键ctrl-F10。
后者在后续教程(如 tutorial-6-4-wheels-robot.md)中会反复用到,可用于直观验证距离传感器的探测范围。
最终效果与解决方案世界文件
完成以上全部动手练习后,仿真应呈现如下效果:四面蓝墙围成场地,球体表面带有红砖纹理,场景由TexturedBackgroundLight提供的方向光照明。
若想核对你的世界文件与标准答案的差异:前往 Tutorial 1 创建的my_first_simulation项目文件夹,进入worlds子目录,用文本编辑器打开对应的世界文件即可。本教程的标准答案位于教程解决方案目录 projects/samples/tutorials/worlds/,对应文件为 appearance.wbt。
该解决方案文件的完整内容(Webots R2025a 版本格式)如下:
#VRML_SIM R2025a utf8 EXTERNPROTO "webots://projects/objects/backgrounds/protos/TexturedBackground.proto" EXTERNPROTO "webots://projects/objects/backgrounds/protos/TexturedBackgroundLight.proto" EXTERNPROTO "webots://projects/objects/floors/protos/Floor.proto" EXTERNPROTO "webots://projects/robots/gctronic/e-puck/protos/E-puck.proto" WorldInfo { basicTimeStep 16 } Viewpoint { orientation -0.19848337736886706 0.4566708842966275 0.8672116537178132 0.9291859728079841 position -0.31179145440206374 -0.4909533805845714 0.3315760210320914 } TexturedBackground { } TexturedBackgroundLight { } Floor { size 1 1 } E-puck { controller "epuck_go_forward" } DEF BALL Solid { translation 0.2 0 0.1 children [ Shape { appearance PBRAppearance { baseColor 0.8 0.8 0.8 baseColorMap ImageTexture { url [ "webots://projects/default/worlds/textures/red_brick_wall.jpg" ] } roughness 0.5 metalness 0 } geometry DEF BALL_GEOMETRY Sphere { radius 0.05 subdivision 2 } } ] boundingObject USE BALL_GEOMETRY physics Physics { } } DEF WALL_1 Solid { translation 0.5 0 0.05 children [ DEF WALL_SHAPE Shape { appearance PBRAppearance { baseColor 0.12549 0.368627 0.729412 roughness 1 metalness 0 } geometry Box { size 0.02 0.98 0.1 } } ] name "solid(1)" boundingObject USE WALL_SHAPE } DEF WALL_2 Solid { translation -0.5 0 0.05 children [ USE WALL_SHAPE ] name "solid(2)" boundingObject USE WALL_SHAPE } DEF WALL_3 Solid { translation 0 -0.5 0.05 rotation 0 0 1 1.5708 children [ USE WALL_SHAPE ] name "solid(3)" boundingObject USE WALL_SHAPE } DEF WALL_4 Solid { translation 0 0.5 0.05 rotation 0 0 1 1.5708 children [ USE WALL_SHAPE ] name "solid(4)" boundingObject USE WALL_SHAPE }对照这份文件可以核验本教程全部要点的落地方式:
- 光源:
TexturedBackgroundLight(内含自动计算方向与强度的DirectionalLight)+TexturedBackground天空盒; - PBRAppearance 三要素:
baseColor(蓝墙 / 灰球基色)、metalness 0(非金属)、roughness(0.5 球 / 1 墙); - 纹理:
baseColorMap内嵌ImageTexture,url 指向webots://projects/default/worlds/textures/red_brick_wall.jpg; - DEF-USE 复用:
DEF WALL_SHAPE只定义一次,WALL_2/3/4 通过USE WALL_SHAPE共享外观与碰撞体。
总结与进阶方向
本教程帮助你掌握了用PBRAppearance 节点与光源节点搭建高观感仿真环境的核心方法:选择合适的光源类型(方向光 / 点光 / 聚光灯)、理解 PBR 材质三要素(基色、金属度、粗糙度)、复用 Webots 内置的预定义外观、从磁盘加载纹理并理解 UV 映射与路径搜索规则,以及按需切换渲染模式。
如需进一步深入,可以:
- 阅读以上各节点在 Reference Manual 中的详细字段描述(pbrappearance.md、imagetexture.md、light.md、background.md 等);
- 为 PBRAppearance 继续添加法线贴图、遮蔽贴图与自发光贴图,并结合 TextureTransform 调整贴图平铺与旋转;
- 为场景手动添加独立光源并开启
castShadows,观察阴影对真实感与渲染性能的双重影响; - 使用仓库 scripts/image_tools 提供的工具集,把 HDR 等格式的贴图资源转换为 Webots 可用的背景与纹理。
下一课将进入四轮机器人建模与运动学内容,把本课的外观经验继续延伸到完整机器人上。
- 科研
- 自动驾驶
- 物理引擎
【免费下载链接】webots
Webots Robot Simulator
相关推荐
Webots 高级渲染示例深度解析:PBRAppearance、Skin 动画与环境光遮蔽(Ambient Occlusion)
Webots 高级渲染示例深度解析:PBRAppearance、Skin 动画与环境光遮蔽(Ambient Occlusion) 本文基于 Webots 官方示
科研自动驾驶物理引擎rsuite Nav 组件外观(appearance)详解:default / tabs / subtle 三种导航样式的实现与实战
rsuite Nav 组件外观(appearance)详解:default / tabs / subtle 三种导航样式的实现与实战 本文基于 rsuite 开
前端UI组件Rsuite ButtonGroup 外观定制详解:appearance 的五种取值与>Rsuite ButtonGroup 外观定制详解:appearance 的五种取值与 data appearance 实现原理 本文以 Rsuite 官方文档
前端UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考