5.1 基础光照:冯氏模型与布林修正


5.1 基础光照:冯氏模型与布林修正

本节摘要:冯氏光照模型把表面亮度拆成环境光、漫反射、镜面反射三个分量的加法,是实时光照的第一语言。本节逐个解剖三分量的几何含义与公式直觉,解释布林-冯模型修正的「半角向量」退化问题,给出完整可跑的光照着色器,再用法线贴图把表面微结构补进材质层。光照是片元站的重头戏,本节也是第 5 章效果栈的地基。

三分量:一次加法拆出的世界

冯氏模型的哲学是「用三个物理直觉粗糙但计算便宜的分量相加,逼近真实光照」。三个分量各管一片视觉领地:

图 5-1 冯氏三分量:环境、漫反射、镜面反射各管什么

图 5-1 冯氏三分量:环境、漫反射、镜面反射各管什么

三个分量里最容易被低估的是环境光——它没有几何可言,纯粹是「往所有像素上加一个常数」。但调光感的高手都懂:环境光的色温和强度定的是整个画面的情绪底色,冷蓝底的夜景和暖橙底的黄昏,环境光就是第一笔。最容易被误解的是镜面反射的 shininess(反光度)参数:它是 pow 的指数,控制高光的「尺寸」而非「亮度」——高光大小与表面光滑度的物理对应(越光滑高光越小越锐),是材质可信度的关键手感。

完整光照着色器:逐行解剖

把三分量翻译成 GLSL(与 2.3 节骨架衔接,布林版):

#version 330 core in vec3 FragPos; in vec3 Normal; in vec2 TexCoord; // 2.3 节的接口 uniform vec3 lightPos; uniform vec3 viewPos; uniform sampler2D diffuseMap; out vec4 FragColor; void main() { vec3 N = normalize(Normal); // 插值后归一化铁律(2.3 节) vec3 L = normalize(lightPos - FragPos); // 指向光源 vec3 V = normalize(viewPos - FragPos); // 指向眼睛 vec3 base = texture(diffuseMap, TexCoord).rgb; float ambient = 0.15; // 环境光:情绪底色 float diffuse = max(dot(N, L), 0.0); // 漫反射:入射角法则 vec3 H = normalize(L + V); // 布林半角:稳定且便宜 float specular = pow(max(dot(N, H), 0.0), 32.0); // 32 = shininess vec3 color = base * (ambient + diffuse) + vec3(specular); FragColor = vec4(color, 1.0); }

四个工程判断藏在这二十行里。镜面项不加底色(base 只乘前两项)——高光是光源在表面上的直接反射,保持光源色而非材质色,塑料感的一大来源就是镜面被材质色染过。光强随距离衰减(点光源必备)在本段略去,标准做法是除以距离平方再乘一个可调强度,调参时注意「平方衰减」比线性衰减物理正确且更有戏剧性。多光源就是这三行计算循环 N 遍加总——循环次数在编译期写死(着色器变体,2.3 节束内分支的结论),运行期增删光源等于换程序。顺带的诊断口诀:全场均匀发亮查环境光是否乘错位置;高光位置诡异查 V 的方向(是「指向眼睛」不是「眼睛指向片元」)——方向量的符号错误是光照代码的头号笔误。

衰减值得多看一眼,因为它是最常被写错的一环。平方衰减在近距离时数值爆炸(除以极小的数),工程写法是给分母加一个常数项垫底:强度除以「距离平方加常数」——这个常数同时起到「限制最亮值」的作用。另一个实践要点是衰减按光源类型分化:方向光(太阳)不衰减(平行光无位置),聚光灯还要乘「与光锥轴的夹角衰减」让光斑边缘渐暗。三种光源 = 三套衰减公式 + 同一套三分量计算,着色器里的差异全部集中在「L 方向与强度怎么来」,三分量本体一行不改——这是光照代码组织成「光源策略 + 着色核心」两块的理由。

法线贴图:表面微结构的假与真

冯氏光照只吃一根插值法线,整个三角形共用近似方向,表面看起来光溜溜。法线贴图的思路:不再插值大三角形的平均法线,而是从一张纹理里逐像素取出「扰动后的法线」——砖缝的凹陷、布料的织纹、皮肤的毛孔,全部变成光照计算里的真实几何起伏,而三角形数一个不加。

实现要点三条。其一,切线空间:法线贴图存的不是模型空间法线,而是「相对于表面局部坐标系」的法线——这样贴图才能复用到任意朝向的表面(同一张砖纹贴墙贴地都行)。着色器里要先把光方向和视线方向变换进切线空间(靠顶点着色器传来的切线基矩阵 TBN),或者反过来把采样法线变换到世界空间,两条路线等价,前者省片元计算是主流。其二,法线编码:法线三分量在负 1 到 1 之间,纹理存 0 到 1,所以采样后要乘 2 减 1 还原——忘记这步,法线全部朝天,光照发闷是它的指纹。其三,压缩时法线贴图有专用格式(重建 z 分量的那类),乱用普通压缩格式会出方向噪点。

⚠️ 常见坑:法线贴图「凹凸反转」——凸的砖块看起来像凹进去的。病因多半是切线方向约定反了或贴图通道绿通道(Y)约定相反,两种行业标准(上还是下)不兼容。修法不是调光照参数,而是换算 Y 通道或翻切线约定。

从冯氏走向何方

冯氏的三宗罪为后两节埋线:不能量守恒(镜面加漫反射的总能量可以凭空超支,PBR 一节解决);高光是纯几何近似(材质的物理属性缺席,PBR 的 BRDF 解决);阴影缺位(三分量都假设光无遮挡,下一节解决)。它便宜、直觉、可调试,至今仍是移动端与风格化渲染的主力——但要知道它省掉了什么,才知道升级时买到的是什么。

本节要点回顾

  • 三分量各管领地:环境光定情绪底色、漫反射管哑光主体、镜面管高光产权
  • shininess 管尺寸不管亮度:高光小=表面光滑,这是材质手感的第一旋钮
  • 布林修正换半角向量:更稳、更省,永远用布林版
  • 镜面不被底色染:光源色高光是塑料感的分水岭;方向量符号错误是头号笔误
  • 法线贴图三要点:切线空间复用、乘 2 减 1 还原、凹凸反转查 Y 通道约定

光有了,但「光被挡住的地方该是暗的」这件事冯氏模型完全不管——下一节解剖阴影:把第 3 章的 FBO 闭环调转一个视角,影子就掉出来了。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U