webxr光照估测通过摄像头实时分析环境光,为ar中虚拟物体提供物理一致的阴影与高光;需https、授权摄像头、显式请求light-estimation特性,并在three.js中用xrlightestimate更新ambientlight和directionallight。

WebXR 的 Light Estimation(光照估测)功能,能让 AR 场景中的虚拟物体自动感知现实环境的光照方向、强度与色温,从而实现阴影、高光和漫反射的物理一致性。它不是“手动打灯”,而是让浏览器从摄像头视频流中实时分析环境光信息,并异步提供给 Three.js 渲染管线使用。关键在于:获取 → 解析 → 同步到材质/灯光 → 持续更新。
WebXR Light Estimation 的启用前提
必须满足以下条件,API 才会返回有效光照数据:
- 使用支持该特性的浏览器(Chrome 88+ Android、iOS Safari 16.4+ 配合 WebXR Viewer 或 VisionOS)
- 页面运行在 HTTPS 或
localhost环境下 - 初始化 XRSession 时显式请求
'light-estimation'功能:const session = await navigator.xr.requestSession('immersive-ar', { requiredFeatures: ['light-estimation'], }); - 设备摄像头已授权,且当前有足够纹理/亮度变化的现实场景(纯白墙或弱光下可能返回默认值)
在 Three.js 中接入并使用光照估测数据
Light Estimation 不直接创建 Three.js 的 Light 对象,而是通过 XRFrame.getLightEstimate() 异步返回一个 XRLightEstimate 实例,包含两个核心属性:
-
primaryLightDirection:归一化方向向量(世界空间),用于设置主平行光方向 -
primaryLightIntensity和primaryLightColorTemperature:可换算为intensity和color
典型用法示例:
// 假设已有 scene、renderer、xrSession
let ambientLight, directionalLight;
function onXRFrame(frame) {
const lightEstimate = frame.getLightEstimate();
if (lightEstimate) {
const { primaryLightDirection, primaryLightIntensity, primaryLightColorTemperature } = lightEstimate;
// 更新环境光(基础亮度)
if (!ambientLight) {
ambientLight = new THREE.AmbientLight(0xffffff, 0.3);
scene.add(ambientLight);
}
ambientLight.intensity = Math.min(primaryLightIntensity * 0.05, 1.0); // 缩放至合理范围
// 更新主平行光(方向 + 色温近似)
if (!directionalLight) {
directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
scene.add(directionalLight);
directionalLight.castShadow = true;
}
// 将 XR 方向转为 Three.js 坐标系(Z 向前 → Z 向后需翻转)
const dir = new THREE.Vector3()
.fromArray(primaryLightDirection)
.applyEuler(new THREE.Euler(0, 0, 0, 'XYZ')); // 通常无需旋转,但需验证设备坐标系
directionalLight.position.copy(dir.multiplyScalar(10));
directionalLight.target.position.set(0, 0, 0);
directionalLight.lookAt(0, 0, 0);
// 可选:用色温估算颜色(简化版,如 D65≈6500K → 偏冷白)
const temp = Math.max(2000, Math.min(10000, primaryLightColorTemperature || 6500));
directionalLight.color = new THREE.Color().setHex(temperatureToHex(temp));
}
}
✅ 提示:
temperatureToHex()是常见色温转 RGB 工具函数(如 McCamy 公式),不依赖外部库,几十行即可实现。
让材质响应真实光照(而非仅靠灯光)
基础材质(如 MeshBasicMaterial)忽略光照。要体现虚实一致性,必须使用支持光照计算的材质:
-
MeshStandardMaterial(推荐):自动响应AmbientLight+DirectionalLight,支持 roughness/metalness 贴图 -
MeshPhysicalMaterial:更精确,支持 IOR、transmission 等,适合玻璃/金属类物体 - 确保模型启用了
castShadow和receiveShadow,并在渲染器开启阴影:renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFSoftShadowMap;
异步性与性能注意事项
Light Estimation 数据并非每帧都更新(通常 1–4 Hz),因此:
- 不要在每一帧都调用
getLightEstimate()后强制重绘;应缓存上一次有效值,仅当lightEstimate非 null 且数值明显变化时才更新灯光参数 - 避免在
onXRFrame中做复杂计算或材质重建——只改.intensity、.color、.position等轻量属性 - 若需更高频光照响应(如动态阴影软边),可结合设备陀螺仪辅助插值,但需自行处理时间同步
不复杂但容易忽略。










