方向光
撰写时间:2026-07-04
修订时间:2026-07-04
方向光的概念及作用
方向光,也称平行光,是指因光源位置非常远,其照射至场景中的任意一个位置的方向是平行的。典型例子为太阳光。
由此决定了方向光的特点是:没有位置,只有方向且方向固定(因此不需要位置变换),强度恒定(无需衰减)。但我们需要向着色器传入方向光的方向(基于世界空间)和颜色强度。
方向光照射到物体表面后,将产生漫反射(diffuse relfection)及高光反射(specular relfection)。我们需将这些光照效果与上一章中的环境光进行融合。
顶点着色器
顶点着色器代码与环境光的代码一致,只需传入法线矩阵及法线数据。其余光照属性在片断着色器中处理。
片断着色器
uLightDirection代表方向光的方向,uLightColor代表方向光的颜色,uLightIntensity代表方向光的强度。
首先,根据均处于世界空间中的vNormal及uLightDirection求出漫反射diffuse。
其次,将diffuse与光的颜色及光的强度相乘后,与环境光uAmbient融合后,赋值于scatteredLight。
最后,再将结果融合进各个网格物体的基本颜色中。
客户端主要代码
需要强调指出的是,所谓光源的方向,是指从物体表面指向光源的方向向量。它与光线传播方向(photon direction)正好相反。后者是指光子从光源出发,射向物体。这两者很容易混淆。
尽管方向光确实没有位置之说,但我们可以根据任意两点来构建一个向量来代表光的方向,而这两点,可以分别是光源位置及其光源所要照向的目标位置。只要用代表光源位置的向量减去代表照射目标的向量,其结果就是光源的方向。鉴于此,上面代码设计了calcLightDirection函数:
这样,只要调节lightPos及target的值,我们就很容易、且绝不会出错地得到代表光源的方向的值。
在该函数参数中,形参outLightDir表示该参数用于存储输出结果。因为实参lightDirWorld是一个对象,因此它能承载函数内部的运算结果。这样做,有一个巨大的好处,我们可以将calcLightDirection函数安全地放置于动画循环内部,只要实参lightDirWorld位于动画循环外部,在动画过程中就不会因产生过多的中间变量而导致频繁地触发垃圾回收,从而降低应用程序的性能。
运行
运行应用。
两个网格物体,一个平躺,另一个竖立,从(0.5, 0.5, 0.5)照向(0.0, 0.0, 0.0)的方向光能将它们同时照亮。
两个模型的法线数据均是一样的。但注意第一个模型。它围绕X轴旋转了-90o,但上面所谈到的代码:
能让其normalMatrix自动随之而改变,从而确保了其法线总是处于正确的状态。
通过调节lightPos及target的值,改变光线的方向,将会看到截然不同的光照效果,从而验证我们的法线是否设置正确。
