Light casters 就是光线投掷者的意思。
基础知识:
1.Directional Light(平行光)
当光源很远时,来自光源的光线彼此接近平行
直接用一个向量direction定义光源方向
struct Light {
// vec3 position; // no longer necessary when using directional lights.
vec3 direction;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
[...]
void main()
{
vec3 lightDir = normalize(-light.direction);
[...]
}
2.Point lights(点光源)
Attenuation(衰减)
这里 d 表示从片段到光源的距离。 然后为了计算衰减值,我们定义了 3 个(可配置的)项:常数项 Kc、线性项 Kl 和二次项 Kq。
实现衰减:
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
float constant;
float linear;
float quadratic;
};
配置参数:
lightingShader.setFloat("light.constant", 1.0f);
lightingShader.setFloat("light.linear", 0.09f);
lightingShader.setFloat("light.quadratic", 0.032f);
计算衰减:
float distance = length(light.position - FragPos);
float attenuation = 1.0 / (light.constant + light.linear * distance +
light.quadratic * (distance * distance));
ambient *= attenuation;
diffuse *= attenuation;
specular *= attenuation;
3.Spotlight(聚光源)
LightDir
: the vector pointing from the fragment to the light source.SpotDir
: the direction the spotlight is aiming at.(聚光源的核心方向向量)Phi
ϕϕ: the cutoff angle that specifies the spotlight's radius. Everything outside this angle is not lit by the spotlight.(cutoff angle 截止角)Theta
θθ: the angle between the LightDir vector and the SpotDir vector. The θθ value should be smaller than ΦΦ to be inside the spotlight.
实现Flashlight(手电筒)
会随玩家位置和方向变换的聚光灯
定义:
struct Light {
vec3 position;
vec3 direction;
float cutOff;
...
};
赋值:(注意:这里角度用cos值来表示,用来节省计算资源)
lightingShader.setVec3("light.position", camera.Position);
lightingShader.setVec3("light.direction", camera.Front);
lightingShader.setFloat("light.cutOff", glm::cos(glm::radians(12.5f)));
超过聚光灯范围的颜色去掉
float theta = dot(lightDir, normalize(-light.direction));
if(theta > light.cutOff)
{
// do lighting calculations
}
else // else, use ambient light so scene isn't completely dark outside the spotlight.
color = vec4(light.ambient * vec3(texture(material.diffuse, TexCoords)), 1.0);
Smooth/Soft edges(柔和边缘)
为了创建平滑边缘聚光灯的效果,我们要模拟具有inner cone内锥体和outer cone外锥体的聚光灯。 从内锥体到外锥体的边缘逐渐变暗。
要从里到外渐变暗,所以需要两个边界,从一个到另一个逐渐变暗。
Here ϵ (epsilon) is the cosine difference between the inner (ϕ) and the outer cone (γ) (ϵ=ϕ−γ). The resulting I value is then the intensity of the spotlight at the current fragment.(分母的值是 里面的边界 - 外面的边界,分子的值是 当前的角度 - 外面的边界,两者一除,角度只要一等于外面的边界,光线就直接变成0了)
实际运用:(clamp表示取0到1中间的值)
float theta = dot(lightDir, normalize(-light.direction));
float epsilon = light.cutOff - light.outerCutOff;
float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0);
...
// we'll leave ambient unaffected so we always have a little light.
diffuse *= intensity;
specular *= intensity;
...