本篇博客主要讨论在OpenGL的着色器中实现光照明模型。在我们组的项目中,采用Phong模型来解决光线与材质相互作用的问题。
首先简单介绍下Phong照明模型。如下图所示
其中,向量n是表面在p点处的法向量。向量v是从p点指向观察者的向量。L是从点p指向点光源的向量(对于非点光源,向量L可以是点p指向拓展光源上任意一点的向量)向量r的方向是根据是向量l的方向按照反射定律计算出的出射光线的方向。换句话说,向量r的方向由向量L和向量n决定。对于模型中的任意一点来说,向量L,向量n和向量v都是已知的,需要我们计算的只有向量r。
Phong光照模型考虑了光线和材质间的三种作用:漫反射,镜面反射和环境光反射。
根据Phong光照模型,某一点的光线强度可以表示为
其中,La,Ld,Ls分别为环境光反射光强,漫反射光强和镜面反射光强。Ra,Rd,Rs分别环境光反射率,漫反射光反射率和镜面反射率。
这里省略推导过程,直接给出Phong模型的结论
其中,d代表从光源到p点的距离,a b c均为代表距离衰减的常数。α代表材质的高光系数(这个高光系数只与材质有关)
以上是标准的Phong反射模型,为了减少计算量,我们小组采用了改进的Phong模型。
半角向量h位于向量l和向量v正中间。改进后,我们可以用n·h代替r·v。这样,我们就避免了对于每个点都需要计算向量r。
下面贴出着色器的实现代码。
#version 330 core
// input variables from vertex shder.
in vec3 v_position;
in vec3 v_normal;
// Automatic parameters.
uniform vec3 g_camera_position;
// Automatic parameters for lighting.
struct LightProperties {
vec3 ambient;
vec3 color;
vec3 direction;
};
const int MAX_LIGHTS = 1;
uniform LightProperties g_lights[MAX_LIGHTS];
uniform int g_light_count;
// Material parameters for phong shading.
uniform vec3 m_diffuse = vec3(0.5, 0.5, 0.5);
uniform vec3 m_specular = vec3(0.0, 0.0, 0.0);
uniform float m_shininess = 0;
// output variable about fragment color.
out vec4 frag_color;
void main() {
vec3 ambient = vec3(0.0);
vec3 diffuse = vec3(0.0);
vec3 specular = vec3(0.0);
for (int i = 0; i < g_light_count; i++) {
// Get the i-th light.
LightProperties light = g_lights[i];
vec3 light_direction = -normalize(light.direction);
vec3 normal = normalize(v_normal);
// Calculate the ambient component.
ambient += m_diffuse * light.ambient;
// Calculate the diffuse component.
diffuse += m_diffuse * light.color * max(0, dot(normal, light_direction));
vec3 view_direction = normalize(g_camera_position - v_position);
vec3 half_vector = normalize(light_direction + view_direction);
// Calculate the speculat component.
specular += m_specular * light.color * pow(max(0, dot(normal, half_vector)), m_shininess);
}
vec3 color = min(ambient + diffuse + specular, vec3(1.0f));
frag_color = vec4(color, 1.0);
// frag_color = vec4(1.0f, 1.0f, 1.0f, 1.0f);
}
几个uniform变量,g_camera_position表示摄像机的坐标值(将用来计算phong模型中的向量v),m_diffuse,m_specular分别为漫反射反射率和镜面反射反射率。(在绝大多数情况下,漫反射反射率和环境光反射反射率都相同,本段代码中m_diffuse也代表环境光反射的反射率)
m_shinness代表了材质的高光系数
分别计算出该点的环境光分量,漫反射光分量和镜面反射光分量ambient,diffuse和specular。三者的和即为该点的光线值。