Blinn-Phong

11 / 17
在简单球体上学习光照项(漫反射/高光/边缘光)。

Phong 高光需要计算反射向量,Blinn-Phong 换了一种更快的方式——只用半向量:

下面拆解半向量是什么,以及它和 Phong 的区别。


半向量是什么

l 是指向光源的方向,v 是指向相机的方向。把两者相加再归一化,得到的就是半向量——它指向 lv 正中间的方向。

Phong 高光判断"反射光是否打到眼睛"(dot(r, v)),Blinn-Phong 改为判断"法线是否对准半向量"(dot(n, hV))。两者视觉效果相近,但半向量计算量更小,也是实时渲染中更常用的方案。


pow 控制高光大小

dot(n, hV) 的结果在 0–1 之间(0% 表示法线和半向量垂直,100% 表示完全对齐)。用 pow 做指数运算:指数越大,高光越小越集中,像镜面;指数越小,高光越宽越散,像磨砂材质。

48.0 是一个中等偏高的光泽度,高光区域较小但明显。


漫反射 + 高光合成

baseCol * (0.12 + 0.88 * diff) 是漫反射部分(底色 + 受光面亮度),vec3(1.0) * spec 是白色高光叠加在上面。两者相加就是完整的 Blinn-Phong 光照结果。


试着改一改

改动效果
48.0 改为 8.0高光变大变散,像磨砂球
48.0 改为 128.0高光缩小成一个亮点,像玻璃球
vec3(1.0) * spec 改为 vec3(1.0, 0.8, 0.4) * spec高光变成暖黄色
光源方向 vec3(-0.4, 0.6, 0.7) 改为 vec3(0.8, 0.2, 0.7)高光移到球体右侧

练习

hV = v 替换为正确的半向量计算 hV = normalize(l + v),让球体出现白色高光亮斑。

答案解析

初始状态:hV = v(用视线方向替代半向量),导致 dot(n, hV) 的计算结果不对,高光出现在球体正中心而不是受光面。

改动:normalize(l + v) 把光源方向和视线方向相加后归一化,得到真正的半向量。此时 dot(n, hV) 在法线对准半向量的区域(即高光应出现的地方)最大,pow 之后形成集中的白色亮斑。

试着把 48.0 改为 200.0,感受极高光泽度下高光集中成一个针尖大小的亮点。

GLSL 代码编辑器

正确代码预览

当前代码预览