跳到主要内容

环境光照

物理材质不仅响应场景灯光,也接收周围环境的光:光亮表面映出周围景象,哑光表面受各方向入射光染色,玻璃表面透出周围环境。这些都来自环境贴图,即天空、房间或户外地点等周围环境的图像。

PlayCanvas 可以从场景或材质本身取得环境贴图。本页解释环境为材质提供什么、来源有哪些、何时使用哪个来源,以及哪些设置影响结果。也介绍平面反射,让地板、镜面和水面精确反射周围场景。

环境提供的内容​

**反射。**表面映出环境。光滑表面呈现清晰图像,粗糙表面呈现柔和模糊图像,金属会用自身颜色给反射染色。材质的 Glossiness、Metalness 和 Reflectivity 控制反射强度和清晰度。

**环境光。**从各方向到达表面、而非来自特定灯光实体的光。有环境贴图时,环境光随方向变化:上方天空更亮、更蓝,下方地面更暗、更暖。这使对象自然融入周围环境。没有环境贴图时,环境光就是场景设置中统一的 Ambient Color(环境色)。

**折射。**启用 Refraction 但未启用 Dynamic Refractions 的材质,会透过表面显示按折射率弯曲后的环境。动态折射则显示表面后方的实际对象,不使用环境贴图。

**背景。**在所有内容后方绘制的天空。只有场景环境会绘制为背景;材质环境贴图只影响其所属材质。

场景环境​

场景环境在 Scene Settings → Rendering(场景设置 → 渲染)的 Skybox(天空盒)中设置,代码中对应 app.scene.skybox 和 app.scene.envAtlas。它既作为背景绘制,也照亮所有未自带环境的材质。

要为材质提供光照,天空盒立方体贴图必须预滤波:立方体贴图资源的 Prefilter 按钮会预先计算粗糙反射和环境光所需的模糊版本。未预滤波的立方体贴图仅绘制为背景。制作和预滤波环境贴图参见基于图像的光照。

Scene Settings → Rendering 中以下设置仅适用于场景环境:

设置作用
Intensity(强度)同时提亮或压暗天空及其照亮的所有内容,包括反射、环境光和折射。可用于匹配灯光曝光。
Rotation(旋转)围绕场景旋转环境,反射和环境光随之旋转。
Mip仅模糊背景,材质仍保留清晰反射。
Ambient Color(环境色)统一环境光,仅供不从环境贴图接收环境光的材质使用。

材质环境​

材质可在材质检查器的 Environment(环境)部分,或通过代码中的对应属性提供独立环境。典型用途是从对象所在位置渲染房间立方体贴图,使反射与周围墙壁、地板和窗户匹配。

设置作用
Cube Map(立方体贴图)(cubeMap)对象周围环境的立方体贴图。预滤波后,材质从中取得反射、环境光和折射,与使用场景天空盒相同。未预滤波时,无论光泽度如何,反射都像镜子一样清晰,环境光回退到统一环境色。
Sphere Map(球面贴图)(sphereMap)从镜面球体看到的周围环境的单张二维图像。开销最低,只提供反射,且相对于相机固定,因此相机环绕对象时反射不移动。同时设置时 Cube Map 优先。球面贴图为兼容现有内容而保留,计划在未来主要版本移除。
Use Skybox(使用天空盒)(useSkybox)材质没有独立环境贴图时,是否允许使用场景环境。对于完全不应反射天空的材质应关闭。对具有独立环境贴图的材质无影响。
Projection(投影)(cubeMapProjection)环境在对象周围的放置方式。Normal 将环境视为无限远,适合天空。Box 根据指定位置和尺寸映射到盒体,使反射与房间墙壁、地板和天花板对齐。参见盒式投影映射。
Reflectivity(反射率)(reflectivity)缩放该材质的环境反射强度,与环境来源无关。
Ambient(环境色)(ambient)为该材质的环境光染色,与环境来源无关。

代码中,预滤波光照是一张称为环境图集(envAtlas)的纹理,由 EnvLighting 辅助方法从立方体贴图或等距柱状图像生成。设置到材质后提供反射、环境光和折射;同时设置立方体贴图,可为极光滑表面增加镜面般清晰的反射。

使用哪个环境​

规则很简单:具有独立环境贴图的材质只使用自己的环境;其他材质使用场景环境。

材质环境Use Skybox反射和折射环境光
无开启(默认)场景天空盒场景天空盒
无关闭无环境色
预滤波立方体贴图任意材质立方体贴图材质立方体贴图
普通立方体贴图或球面贴图任意材质贴图环境色

材质环境完全替换场景环境。场景的强度和旋转不影响它,场景也不会为普通立方体贴图或球面贴图补充环境光。若希望具有独立环境的材质获得方向性环境光,应在编辑器中预滤波立方体贴图,或在代码中生成环境图集。

平面反射是例外:它仅替换材质反射,环境光仍按上表取得。

在代码中配置​

// Scene environment from an HDR image: a sharp sky for the background and mirror-like
// reflections, plus a prefiltered lighting atlas for ambient light and rough reflections
const skybox = EnvLighting.generateSkyboxCubemap(hdrTexture);
const lighting = EnvLighting.generateLightingSource(hdrTexture);
const envAtlas = EnvLighting.generateAtlas(lighting);
lighting.destroy();

app.scene.skybox = skybox;
app.scene.envAtlas = envAtlas;
app.scene.skyboxIntensity = 1.5;

// Material environment: this material ignores the scene skybox and reflects its own surroundings
const material = new StandardMaterial();
material.envAtlas = roomAtlas; // prefiltered lighting: reflections, ambient light and refraction
material.cubeMap = roomCubemap; // optional: mirror-sharp reflections on very glossy surfaces
material.update();

平面反射​

环境贴图显示的是从单个点观察的周围景象,无法反射地板上的对象或表现其接触位置。抛光地板、镜面和水面等平面可改用平面反射:由第二台相机每帧向纹理渲染场景,相机按表面所在平面镜像。

PlanarRenderer 脚本(scripts/esm/planar-renderer.mjs)创建相机和纹理,每帧随主相机移动。材质反射 planarReflectionMap 指定的纹理,并用 planarReflectionMatrix 指定的相机视图投影矩阵进行投影。

  • 平面反射只替换反射。材质灯光、阴影和菲涅耳不变,环境光仍来自环境,参见使用哪个环境。
  • 粗糙表面通过纹理 mipmap 模糊反射,因此除完美镜面外,都应启用脚本的 mipmaps。脚本用高斯滤波生成,确保相机移动时模糊反射保持平滑。将 mipmapFilter 设为 'box' 可降低开销,但模糊更有块状感。
  • 法线贴图会扭曲反射,类似凹凸或潮湿表面的反射。
  • 启用脚本的 hdr,使反射中的亮光源与场景中同样明亮。此时纹理存储线性颜色,由渲染材质的相机进行色调映射。
  • 主相机使用 TAA 时,反射相机跟随其抖动,因此反射也获得抗锯齿。
  • 具有平面反射的材质若需折射,必须启用动态折射,因为该纹理没有可透过表面显示的环境。
  • 将反射表面放入反射相机不渲染的图层,因为表面不能出现在自身反射中。
  • 反射每帧额外渲染场景一次。可降低脚本的 scale,按屏幕分辨率的一部分渲染,并只让反射相机包含值得反射的图层。完美镜面每像素读取纹理一次,粗糙表面为平滑模糊会多读取几次。

在代码中配置平面反射:

import { PlanarRenderer } from 'playcanvas/scripts/esm/planar-renderer.mjs';

// The reflection camera renders the reflected layers before the main camera
const reflectionCamera = new Entity('ReflectionCamera');
reflectionCamera.addComponent('camera', {
layers: [worldLayer.id, skyboxLayer.id],
priority: -1
});
reflectionCamera.addComponent('script');
const planarRenderer = reflectionCamera.script.create(PlanarRenderer, {
properties: {
sceneCameraEntity: cameraEntity,
planePoint: new Vec3(0, 0, 0),
planeNormal: new Vec3(0, 1, 0),
mipmaps: true, // blurred reflections on rough surfaces
hdr: true // bright lights stay bright in the reflection
}
});
app.root.addChild(reflectionCamera);

// The floor is on its own layer, rendered by the main camera but not by the reflection camera
floorEntity.render.layers = [floorLayer.id];

// Each frame, after the main camera has moved, the floor reflects the updated texture
app.on('update', () => {
const texture = planarRenderer.frameUpdate();
floorMaterial.planarReflectionMap = texture;
floorMaterial.planarReflectionMatrix = planarRenderer.viewProjectionMatrix;
floorMaterial.update();
});

示例​

  • HDR:由预滤波环境图集照亮的场景。
  • 反射立方体贴图:材质具有从对象位置运行时渲染的独立立方体贴图,并关闭 Use Skybox。
  • 盒式反射:房间材质使用盒式投影环境图集,使反射与墙壁对齐。
  • 平面反射:抛光地板通过平面反射映出房间及其中对象,并提供 Cubemap 模式,与盒式投影环境图集对比。