点光源

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,让光源更贴近球面,观察衰减形状的变化。

GLSL 代码编辑器

正确代码预览

当前代码预览