现实世界的光照是极其复杂的,因此WebGL的光照仅仅使用了简化的模型并基于对现实的估计来进行模拟,光照模型都是基于我们对光的物理特性的理解。
颜色
根据物理知识,不透明物体的颜色是根据其反射的色光决定的。比如树叶反射绿光,就显示绿色。如果物体反射所有的色光,就显示白色。所以光源色和物体颜色的反射运算:
vec3 lightColor = vec3(0.3, 0.4, 0.5);
vec3 thingColor = vec3(0.5, 0.4, 0.5);
vec3 resultColor = lightColor * thingColor; // = (0.15, 0.16, 0.25)
光照
环境光照
环境反射光的颜色定义公式为:
反射光的颜色 = 入射光的颜色 x 物理的颜色
漫反射光照(Diffuse Lighting)
测量这个光线与它所接触片段之间的角度。如果光线垂直于物体表面,这束光对物体的影响会最大化。为了测量光线和片段的角度,我们使用一个叫做法向量(Normal Vector)的东西,法向量(Normal Vector)是垂直于顶点表面的(单位)向量。由于顶点自身并没有表面(它只是空间中一个独立的点),我们利用顶点周围的顶点计算出这个顶点的表面。
漫反射光最后的颜色定义公式为:
漫反射光的颜色= 入射光的颜色 x 物理的颜色 x 入射角的余弦
向量a,b的点乘 = |a||b|cos<a,b>,a,b都是归一化后的向量,归一化后向量的模为1,所以向量的点乘就等于两个向量的余弦值
一个物体在光照下既发生了漫反射,又发生了环境反射,那么它最后反射光的颜色为:
反射光的颜色 = 漫反射光的颜色 + 环境反射光的颜色
顶点着色器
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;
void main() {
gl_Position =uProjectionMatrix * uModelViewMatrix * a_position;
vColor = aVertexColor;
v_normal = mat3(uModelViewMatrix) * a_normal;
}
在计算矩阵变换时需要按照规定的顺序,它是不满足乘法交换律的
clip=Mprojection⋅Mview⋅Mmodel⋅Vlocal
注意每个矩阵被运算的顺序是相反的(记住我们需要从右往左乘上每个矩阵)。
片段着色器
precision mediump float;
varying lowp vec4 vColor;
varying lowp vec3 v_normal;
//方向光的方向
uniform lowp vec3 u_light;
//方向光的颜色
uniform lowp vec3 u_lightColor;
void main() {
vec3 normal = normalize(v_normal);
gl_FragColor = vColor;
// 环境光照
vec3 ambientLight = gl_FragColor.rgb * u_lightColor;
// 漫反射光照
float light = max(dot(normal, u_light), 0.0);
vec3 diffuseLight = gl_FragColor.rgb * light;
gl_FragColor.rgb = ambientLight + diffuseLight;
}