Unity Shader 什么是球谐光照 原理是什么

球谐光照(Spherical Harmonics Lighting,简称SH光照)是Unity中一种高效编码低频环境光照 的技术,主要用于Light Probe(光照探针)Skybox环境光 的漫反射计算。它的核心价值在于:用极少的参数(通常9个浮点数)就能近似表达一个物体周围360°的入射光照分布,并在Shader中快速计算出物体表面接收到的漫反射光。

下面从"为什么需要"、"数学原理"、"Unity中的具体应用"三个层面来解释。

一、为什么需要球谐光照?

在实时渲染中,如果要精确计算物体表面某点接收到的间接漫反射光(比如蓝色墙壁反射到红色地毯上的光),理论上需要对该点上半球所有方向的入射光进行积分,这在运行时是不可能完成的。

传统做法:

  • 预计算辐照度贴图:对空间每个点存储一个cubemap → 内存爆炸。

  • 实时Ray Tracing:性能无法满足游戏需求。

球谐光照提供了一个折衷方案

  • 离线预计算:将场景中每个Light Probe位置周围的入射光照,投影到球谐基函数上,存储少量系数(例如27个float,RGB各9个)。

  • 运行时还原:Shader中只需用表面法线点乘这些系数,就能快速得到该点接收到的漫反射光强度。

这样就实现了"用较低的存储和计算成本,获得非常平滑、无方向细节但整体正确的间接漫反射效果"。

二、球谐光照的数学原理(通俗版)

1. 球谐函数------球面上的傅里叶级数

傅里叶级数可以用正弦余弦函数的叠加来逼近任意周期性波形。类似地,球谐函数是定义在球面上的一组正交基函数,可以用它们的加权和来逼近任意定义在球面上的函数(比如从某个点看向各个方向的光照强度)。

球谐函数有很多阶(Order):

  • 0阶:1个基函数(常数项),代表平均亮度。

  • 1阶:3个基函数(线性项),能表示方向性(如上下比左右亮)。

  • 2阶:5个基函数(二次项),能表示更复杂的分布(例如两极性)。

  • 3阶:7个基函数......阶数越高,能重现的细节越丰富。

实际应用中,渲染漫反射(低频)只需前3阶(共1+3+5=9个系数),因为漫反射光照相当于对原始光照进行了低通滤波,高频细节被抹除。

2. 渲染方程中的漫反射简化

在一点p,漫反射颜色公式为:

其中 Li(p,ωi)Li​(p,ωi​) 是该点从方向 ωiωi​ 入射的光照。

如果我们将 Li(p,ωi)Li​(p,ωi​) 投影到球谐基函数上,得到系数 cl,mcl,m​,同时将漫反射的传输函数 (即 max⁡(0,n⋅ωi)max(0,n⋅ωi​))也投影到同一组基上,那么积分结果就等于两组系数的点积。最终化简为

其中 klkl​ 是预先算好的常数(与球谐阶数相关),Yl,m(n)Yl,m​(n) 是球谐基函数在法线方向n上的取值。

在Shader中,这部分计算被合并为一个法线方向的九次多项式

复制代码
// Unity内置的球谐光照计算(简化逻辑)
half3 SHLighting (half3 normal) {
    half4 SHAr = unity_SHAr;
    half4 SHAg = unity_SHAg;
    half4 SHAb = unity_SHAb;
    half4 SHBr = unity_SHBr;
    half4 SHBg = unity_SHBg;
    half4 SHBb = unity_SHBb;
    half4 SHC = unity_SHC;
    
    half3 res = SHEvalLinearL0L1(normal, SHAr, SHAg, SHAb);
    res += SHEvalLinearL2(normal, SHBr, SHBg, SHBb, SHC);
    return res;
}

三、Unity中球谐光照的具体应用

1. 主要载体:Light Probe

  • Light Probe Group 组件可以在场景中放置多个光照探针。

  • Unity在烘焙时,为每个探针位置计算该点的入射光照立方贴图 ,然后投影到3阶球谐函数 ,得到RGB三组9个系数(共27个float),存储在光照数据中。

  • 运行时,物体使用距离最近的几个探针,通过插值获取当前点的球谐系数。

2. Shader中的使用方式

对于受Light Probe影响的物体(通常是静态或动态物体),Unity会自动将插值后的球谐系数通过 unity_SHArunity_SHAg 等内置变量传递给Shader。

获取球谐漫反射光照的标准代码

复制代码
// 在世界空间法线方向计算球谐光照
half3 ambient = ShadeSH9(float4(worldNormal, 1.0));

或者手动调用内置函数:

复制代码
half3 indirectDiffuse = SampleSH(worldNormal);

3. 与传统环境光的区别

特性 传统 Cubemap 环境光 球谐光照 (SH)
存储量 高(6张纹理) 极低(27个float)
精度 高(可表现细节) 低(只有低频信息)
计算开销 高(需要采样立方体贴图) 极低(几个点积和多项式)
适用场景 静态背景反射、高光环境 动态物体间接漫反射、移动端全局光照

四、局限性

  1. 只能表示低频光照

    球谐无法表现尖锐的光影变化,例如点光源直接照明、阴影边缘。因此它只适合做间接光/环境光

  2. 无法用于高光反射

    镜面反射需要高频的环境信息(如清晰的窗户倒影),球谐阶数不够。镜面反射仍需使用反射探针(Reflection Probe)的Cubemap。

  3. 仅适用于漫反射

    球谐光照的传输函数是低通的,与漫反射BRDF匹配,不适合光泽或镜面材质。

    总结一句话

    球谐光照是一种将周围环境光照"压缩"成9个系数的数学技巧,在Shader中通过法线方向快速恢复出物体表面接收到的平滑漫反射光,是Unity实现Light Probe和轻量级全局光照的核心技术。

相关推荐
心前阳光1 小时前
Unity之使用火山引擎实现语音识别
unity·语音识别·火山引擎
心前阳光1 小时前
Unity之使用火山引擎实现流式语音合成
unity·游戏引擎·火山引擎
心前阳光3 小时前
Unity之使用火山引擎实现音频剪辑提问,流式语音回复
unity·音视频·火山引擎
心前阳光3 小时前
Unity之音频剪辑提问,流式语音回复使用示例
unity·游戏引擎·音视频
小拉达不是臭老鼠15 小时前
Unity学习_ScriptableObject
学习·unity
Thomas_YXQ16 小时前
Unity无GC读取图片与网格完整方案
大数据·人工智能·unity·微信·产品运营
jiayong2318 小时前
虚幻引擎 Unreal Engine 通俗指南
游戏引擎·虚幻
郝学胜-神的一滴20 小时前
中级OpenGL教程 008:精准控制高光光斑大小与强度
c++·unity·godot·three.js·图形学·opengl·unreal
avi91111 天前
Unity 商业插件之(五)课外2 - Zenject的一些小Tips(学习备忘)
unity·游戏开发·团结引擎