冯氏光照模型
在现实中的光照是难以用计算机模拟的,因此我们要用简化的光照模型来对现实世界进行近似。 冯氏光照模型( Phong Lighting Model)就是其中之一。冯氏光照模型由三部分组成: 环境光( ambient)、 漫反射( diffuse)、 镜面反射( specular)。
环境光(Ambient Lighting)
在生活中,即使是黑暗的环境,世界上依旧存在着一些光照(如月光),环境光就是模拟这个的。有环境光时,物体几乎是不会黑暗的。
在OpenGL中,我们通常使用一个系数 ambient
来乘以光源的颜色作为环境光
float ambientStrength = 0.1; //环境光的强度系数
vec3 ambient = ambientStrength * lightColor; //环境光
漫反射(Diffuse Lighting)
该部分用来模拟光源对物体的方向性影响,即物体越是正对光源的面越亮,这也是冯氏光照模型中视觉最显著的分量。
上面说到,漫反射是用来模拟光源对物体的方向性的影响的,所以我们要做的就是判断光源方向与每个点的正对程度。如下图所示
假设光线方向与该点的法线夹角为 θ \theta θ ,如果 θ \theta θ 为0度,即光源正射该点,此时该光源对该点的影响达到最大化,换句话说,最亮。如果 θ \theta θ为90,则影响最小。因此,我们只需要计算出来光线方向与法线接近程度即可。利用点乘可以判断出两个向量的接近的程度。
两个单位向量的点乘结果是这两个向量夹角的余弦值。两个向量越接近,这个值越接近于1。
计算漫反射光我们需要两个数据:法向量和光线方向(光源的位置,点的位置)。
//计算出法向量和光线方向的单位向量
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(lightPos - FragPos);
//判断漫反射强度系数
float diff = max(dot(norm, lightDir), 0.0);
//计算漫反射光照
vec3 diffuse = diff * lightColor;
镜面反射(Specular Lighting)
该部分用来模拟光滑物体表面的高光。镜面反射的颜色更倾向于光照的颜色
在现实生活中,光滑物体表面的高光是会随着人的视线发生改变的,它依赖于人的观察方向。
镜面反射基于光的反射特性,如下图所示
R ‾ \overline{R} R代表光线的反射光线。 人的视线与反射光线的夹角 θ \theta θ越小,观察到的镜面反射的效果越明显。
float specularStrength = 0.5; //镜面反射强度
vec3 viewDir = normalize(viewPos - FragPos); //视线方向
vec3 reflectDir = reflect(-lightDir, norm); //反射光线
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
vec3 specular = specularStrength * spec * lightColor; //镜面反射光线
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
中的32代表高光的反射度(Shininess)。反射度越高,反射光的能力越强,高光点越小,如下图所示。
合成环境光、漫反射和镜面反射
当三个分量都计算出来后,对它们进行求和,就可以得到完整的光照了。
vec3 result = (ambient + diffuse + specular) * objectColor;
FragColor = vec4(result, 1.0);