1,
聚光灯光源也会随着距离衰减,但它不是像点光源照向四面八方的而是像平行光那样有一个聚光方向(相当于取点光源的一个锥形的一小部分),聚光灯光源呈锥形,因此有一个新的属性,就是离光源越远,照亮的圆形区域会越大(光源位于锥形体的尖端)。例如:手电筒。
图中垂直指向地面的黑色尖头指的是光源方向,这里想实现让光源只照亮两条红线夹角之间的区域,这里仍然可以使用点积来实现。我们可以定义光锥为光线方向L和红线之间的那个夹角(两条红线之间夹角的一半)。计算那个夹角的余弦值'C'(点积计算得到)以及L和V夹角的余弦,其中V指的是光源到某个像素的向量,如果后者的值大于余弦值'C'(夹角越小余弦越大),说明L和V之间的夹角偏小,该像素就位于被照亮的区域内。反之,像素位于区域外就不会被该光源照亮。
如果我们紧紧按照上面说的在照亮区域内就点亮像素,否则就不点亮,那样就会看上去非常假,因为照亮区域和未照亮区域之间的边界边缘会非常明显(没有一个自然的过渡),看上去会是一个清晰的圆形画在一个黑色区域(如果没有其他光源的话)。一个真实的聚光灯光源会从照亮区域的中心向圆形边缘慢慢衰减。这里我们可以利用上面计算得到的那些点积作为一个衰减的参数。首先我们知道,当L和V两个向量相等重合时,点积为'1'。但是用余弦来做衰减参数会有问题,因为聚光灯光源的夹角不能太大,否则范围太广就失去了聚光灯的效果,但是在夹角从0到一个比较小的角度范围内,cos值得变化是很缓慢的,导致衰减不明显。例如:让聚光灯的夹角为20度,余弦值就为0.939,[0.939,1.0]这个变化范围就不好作为衰减参数了,在这个范围内进行插值的空间不足,造成的衰减程度不足以让眼睛察觉到。要想衰减效果明显这个参数范围应该是[0,1]。解决方法是将这个参数的小范围映射到[0,1]的范围,方法如下:
原理很简单:计算大的范围和小的范围的比例,然后根据那个比例对小范围进行映射扩张即可。
2,
聚光灯光源的结构体继承自点光源的结构体,并添加了两个属性和点光源区别开:一个是光源的方向向量,另一个是截断光源照亮范围的一个阈值。阈值代表的是光源方向向量和光源到可照亮像素之间的大夹角。比这个阈值夹角大的像素是不会被该光源照亮的。
这里vec4 CalcSpotLight(SpotLight l, vec3 Normal)这个函数是我们计算聚光灯光源效果的地方。首先得到光源到某个像素的向量,将向量单位化方便点积运算,然后和单位化了的光源方向向量进行点积运算得到他们之间夹角的余弦值。将得到的余弦值和光源的阈值(定义光源范围的大夹角的余弦值)进行比较,如果余弦值比阈值小,说明夹角太大像素在照亮圆区域的外面,这样像素就不会被该光源点亮。这样那个阈值就可以将聚光灯光源的照亮范围限制在一个大的或者小的圆圈内。反之如果像素在照亮区域内,我们就先像点光源那样计算光源的基础颜色。然后将那个点积计算得到的参数'SpotFactor'放到上面的公式中,将这个参数线性插值到0到1的范围,最后和点光源颜色相乘计算得到最终的聚光灯颜色值。
3,