点光源
14 / 17
在简单球体上学习光照项(漫反射/高光/边缘光)。
这个教程在方向光的基础上加入了「位置」和「距离衰减」,核心部分是这几行:
下面拆解每个概念。
方向光 vs 点光源
方向光只有方向,没有位置,画面里每个像素收到光的方向都一样。
点光源有位置。每个像素到光源的方向不同,而且越远的像素收到的光越弱——就像蜡烛,靠近的地方亮,远处就暗下去了。
光照方向随位置变化
normalize 把向量缩成长度为 1,只保留方向信息。每个像素算出来的 l 都不一样,这就是点光源和方向光最本质的区别。
距离衰减
光源距离越远,光照越弱。用距离的平方来控制衰减:
dot(v, v) 等于向量长度的平方,省去了开根号的计算。1.0 / (1.0 + 3d²) 的形状是:距离 0 时 att=1(100% 亮),距离越大 att 越趋向 0。系数 3.0 控制衰减速度,越大衰减越快。
组合漫反射和衰减
0.1 是环境光底色(让背光面不完全黑掉),diff * 2.0 是放大后的漫反射贡献。
试着改一改
| 改动 | 效果 |
|---|---|
把 lightPos 的 x/y 改成 -0.3, 0.2 | 光源移到左侧,球体受光面改变 |
把衰减系数 3.0 改为 10.0 | 衰减更快,球体变暗 |
把衰减系数改为 0.5 | 衰减更慢,光照范围更广 |
把 0.1 改为 0.4 | 环境光增强,背光面也变亮 |
练习
练习代码中已经计算了光照方向 l,但缺少距离衰减。补全 att 的计算,并把它乘进 diff,让球体呈现随距离变暗的点光源效果。
答案解析
起始代码里 diff = max(dot(n, l), 0.0),没有乘衰减,相当于光源无限强、距离无影响,整个球面受光均匀。
加上 att 后,离光源近的像素 att 接近 1(亮度几乎不损失),远的像素 att 趋近 0(几乎不受光),球体就产生了真实的明暗过渡。
dot(lightPos-pos, lightPos-pos) 是距离平方,比 length() 少一次开根号运算,在 GPU 上效率更高。
试着把光源位置 z 分量从 0.6 改成 0.1,让光源更贴近球面,观察衰减形状的变化。