镜面光照
镜面光照(Specular Lighting)依据光的方向向量和物体的法向量计算。
我们通过反射法向量周围光的方向计算反射向量。然后我们计算反射向量和视线方向的角度,如果之间的角度越小,那么镜面光的作用就会越大。它的作用效果就是,当我们去看光被物体所反射的那个方向的时候,我们会看到一个高光。观察向量是镜面光照的一个附加变量,我们可以使用观察者世界空间位置(Viewer’s World Space Position)和片段的位置来计算。之后,我们计算镜面光亮度,用它乘以光的颜色,在用它加上作为之前计算的光照颜色。
顶点着色器
attribute vec4 a_position;
uniform mat4 u_worldViewProjection;
attribute vec4 aVertexColor;
//法向量的变量
attribute vec3 a_normal;
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
varying lowp vec4 vColor;
//将法向量从顶点着色器传递到片元着色器的变量
varying lowp vec3 v_normal;
varying lowp vec3 v_fragpos;
void main() {
gl_Position = uProjectionMatrix * uModelViewMatrix * a_position;
vColor = aVertexColor;
v_normal = mat3(uModelViewMatrix) * a_normal;
v_fragpos = vec3(uModelViewMatrix * a_position);
}
其中v_fragpos 为计算片段的位置(Position),通过把顶点位置属性乘以模型矩阵(Model Matrix,只用模型矩阵不需要用观察和投影矩阵)来把它变换到世界空间坐标,输出到片段着色器中。
片段着色器
precision mediump float;
varying lowp vec4 vColor;
varying lowp vec3 v_normal;
//方向光的方向
uniform lowp vec3 u_light;
//方向观察者的坐标
uniform lowp vec3 u_eyePos;
//方向光的颜色
uniform lowp vec3 u_lightColor;
varying lowp vec3 v_fragpos;
void main() {
vec3 normal = normalize(v_normal);
gl_FragColor = vColor;
// 环境光照
vec3 ambientLight = gl_FragColor.rgb * u_lightColor * 0.1;
// 漫反射光照
float light = max(dot(normal, -u_light), 0.0);
vec3 diffuseLight = gl_FragColor.rgb * light;
// 高光
float specularStrength = 0.5;
vec3 eyeDir = normalize(u_eyePos - v_fragpos);
vec3 reflectDir = reflect(u_light, normal);
float spec = pow(max(dot(eyeDir, reflectDir), 0.0), 32.0);
vec3 specular = specularStrength * spec * u_lightColor;
vec3 specularLight = gl_FragColor.rgb * specular;
gl_FragColor.rgb = ambientLight + diffuseLight + specularLight;
}
specularStrength 是镜面强度,eyeDir为视线的向量,spec是计算视线方向与反射方向的点乘(确保它不是负值),然后得到它的32次幂。这个32是高光的发光值(Shininess)。一个物体的发光值越高,反射光的能力越强,散射得越少,高光点越小。你会看到不同发光值对视觉(效果)的影响。
冯氏光照
冯氏光照模型的主要结构由3个分量组成:环境(Ambient)、漫反射 (Diffuse)和镜面(Specular)光照。
gl_FragColor.rgb = ambientLight + diffuseLight + specularLight;