聚光灯局限于点光源,例如,光源光线仅仅发射限制于一个方向。我们经常使用一个椎体来定义这个限制,但是其他形状同样也是可能的。
下面的图展示了一个聚光灯椎体形状和相关数据:
1. 位置:就是椎体的顶点(sp);
2. 聚光灯方向:椎体轴定义的方向向量(sd);
3. 截止角:椎体的光圈。在这里我们将假设是从方向向量到椎体边缘的角度()。
顶点着色器跟点光源一样。它是在片段着色器中决定这个片段是否在椎体里面,比如,也就是光源方向和椎体方向的点乘结果是否小于cutoff角度,从而在椎体里面。实际上,代替使用角度,我们在着色器中提过一个角度的余弦值来避免计算角度的反余弦值。
#version 330
Layout(std140) uniform Materials{
Vec4 diffuse;
Vec4 ambient;
Vec4 specular;
Float shininess;
};
Layout(std140) uniform Lights{
Vec4 l_pos;
Vec4 l_spotDir;
Float l_spotCutOff;
};
In Data{
Vec3 normal;
Vec3 eye;
Vec3 lightDir;
}DataIn;
Void main()
{
Float intensity = 0.0;
Vec4 spec = vec4(0.0);
Vec3 ld = normalize(DataIn.LightDir);
Vec3 sd = normalize(vec3(-l_spotDir));
If(dot(sd, ld) > l_spotCutOff)
{
Vec3 n = normalize(DataIn.normal);
Intensity = max(0.0, dot(n, ld));
If(intensity > 0.0)
{
Vec3 eye = normalize(DataIn.eye);
Vec3 h = normalize(ld + eye);
Float intSpec = max(0.0, dot(h,n) );
Spec = specular * pow(intSpec, shininess);
}
}
colorOut = max(intensity * diffuse + spec, ambient);
}
例子的效果如下: