光照估算让虚拟物体融入真实光线
为什么虚拟物体看起来"假"
在没有光照估算的 AR 应用里,虚拟物体通常使用一个固定的光色(比如白色)和固定的光照强度。白天在阳光下、夜晚在白炽灯下、阴天在散射光下——同一个虚拟物体在所有环境里看起来都一样。结果就是:虚拟物体的光影和真实环境对不上,用户一眼就能看出"这是假的"。
光照估算(Light Estimation)的目标就是:让 ARCore 自动分析当前画面中的光照条件,然后把这些信息提供给你的 3D 渲染引擎,让虚拟物体呈现出与周围环境一致的明暗和色温。
两种光照估算模式
ARCore 提供两种精度的光照估算:
模式一:基础光照估算(默认)
输出两个标量值:
| 输出 | 含义 | 用途 |
|---|---|---|
AverageIntensity | 当前环境的平均光强(0 ~ 1 之间) | 直接作为 3D 引擎的 ambient light 强度 |
ColorCorrection | 色温校正向量(r, g, b 三个系数) | 调整虚拟物体的颜色,匹配环境色温 |
基础模式开销小、覆盖所有 ARCore 设备。
模式二:HDR 光照估算
输出一个 HDR 环境贴图(Cube Map)——这是从摄像头画面提取的球面全景光信息,相当于把当前环境的所有光线方向和强度编码进一个 6 面立方体贴图里。
HDR 模式可以实现:
- 虚拟物体表面的环境反射(金属光泽的反射看起来像周围真实环境)
- 多方向光照(光从左边来时虚拟物体左侧亮右侧暗)
- 更高的整体真实感
但 HDR 模式需要更多计算资源和内存,对低端设备可能有压力。
Session 配置
session.configure(
Session.Config(context).apply {
// 基础模式默认开启,显式设置也可以
setLightEstimationMode(
Session.Config.LightEstimationMode.AMBIENT_INTENSITY
)
// 或 HDR 模式(如果设备支持)
if (session.isHdrLightEstimationSupported()) {
setLightEstimationMode(
Session.Config.LightEstimationMode.ENVIRONMENTAL_HDR
)
}
}
)
读取光照数据
基础光照
session.update(frame)
// LightEstimate 对象在 Frame 上
val estimate = frame.lightEstimate
// 只有 ESTIMATE_VALID 状态的才可用
if (estimate.state != LightEstimate.State.VALID) return
// 平均光强(0 ~ 1)
val intensity = estimate.averageIntensity
// 色温校正(ColorCorrection)
// 是一个 Vector3:(r, g, b) 三个分量的校正系数
// 把 3D 引擎的 ambient light color 乘以这个向量即可
val colorCorrection = estimate.colorCorrection
// 应用到渲染引擎(伪代码)
renderEngine.ambientLight.intensity = intensity
renderEngine.ambientLight.color = ambientBaseColor * colorCorrection
HDR 光照
val estimate = frame.lightEstimate
if (estimate.state != LightEstimate.State.VALID) return
// 环境贴图 Cube Map
val cubeMap = estimate.environmentHdrCubeMap
// cubeMap 是一个 OpenGL Cube Map 纹理 ID(Android)
// 可以直接传给 PBR 材质做环境反射
// 也可以获取 HDR 颜色校正(比基础模式更精确)
val hdrColorCorrection = estimate.colorCorrection
渲染集成要点
OpenGL ES 中的着色器修改
你的 3D 着色器需要能接收光照估算值:
// 片段着色器
uniform float uAmbientIntensity; // ARCore AverageIntensity
uniform vec3 uColorCorrection; // ARCore ColorCorrection
void main() {
// 基础光照(每个像素一样强)
vec3 ambient = baseColor * uAmbientIntensity * uColorCorrection;
// 加上方向光等...
vec3 finalColor = ambient + diffuse + specular;
gl_FragColor = vec4(finalColor, 1.0);
}
HDR Cube Map 在 PBR 材质中的使用
如果你用的是基于物理的渲染(PBR),HDR Cube Map 可以直接作为 environmentMap 传入——PBR 着色器会自动用它计算反射、折射和环境遮蔽,效果最接近真实。
Unity AR Foundation 中的光照
Unity 把光照估算封装进 AR Session 和渲染管线。配置 Universal Render Pipeline(URP)或 HDRP 后:
// 自动应用光照估算
var lightEstimate = session.Subsystem.systemState;
// Unity 2021+ 的 AR Session Manager 自动处理光照更新
// 把 Light Estimation 数据注入到渲染管线中
Unity 会自动把 ARCore 的 AverageIntensity 映射到场景的 Global Light Intensity,ColorCorrection 映射到 Global Light Color。
光照估算的局限性
| 局限 | 说明 |
|---|---|
| 全局估算 | 平均光强是整个画面的平均值,局部强光/弱光不敏感 |
| 延迟 | HDR 模式的 Cube Map 更新频率可能低于摄像头帧率 |
| 动态光 | 快速变化的光(如闪光灯、快速移动的手电筒)滞后 |
| 方向单一 | 基础模式不包含光的方向信息(只知道亮暗和色温) |
局部光 vs 全局光
一个折中的优化方案:根据虚拟物体在屏幕上的位置,只取该区域附近的光照值而不是整个画面的平均值。这样放在阴影里的物体会更暗、放在阳光下的物体更亮。
性能开销
| 模式 | CPU 开销 | GPU 开销 | 内存 | 适用设备 |
|---|---|---|---|---|
| 基础 AMBIENT_INTENSITY | 极低 | 无 | 可忽略 | 所有 ARCore 设备 |
| HDR ENVIRONMENTAL_HDR | 中 | 中 | 中(HDR Cube Map 纹理) | 中高端设备,低端手机可能自动降级 |
HDR 模式在 Android 上会自动降级——如果 GPU 能力不够,ARCore 会退回到基础光照模式,不会让应用崩溃。你只需要在 Session 配置里指定 ENVIRONMENTAL_HDR 即可。
