注:文章译自http://wgld.org/,原作者杉本雅広(doxas)。文章中假设有我的额外说明。我会加上[lufy:],另外,鄙人webgl研究还不够深入。一些专业词语。假设翻译有误。欢迎大家指正。
各种各样的光照
反射光的概念
从平行光源发出的扩散光的光照,通过光的方向(光向量)和面的方向(面法线向量),来计算这个面的扩散程度,从而实现光照。
光照最强的地方就是模型的颜色,反之,没有被光照到的地方。就会变成暗色。
可是,像金属那样的质感,就是光泽的表现。仅仅用扩散光就不够了。
为什么呢。光照最强的部分,也仅仅只是是显示了模型的原来的颜色,要想表现出光泽。则须要表现一下高亮这种强光效果。
改动顶点着色器,仅仅通过扩散光尽管也能够实现高亮效果,可是大部分场合都会感觉不自然。这是由于扩散光是不会考虑视线的。扩散光,仅仅是考虑光的方向和面的方向。而反射光。则会考虑观看模型的视线和光的方向,表现出的高亮部分会很的自然。
表示视线的向量和表示光的向量,再加上面法线向量,能够算出反射光的强度。想一下的话,就是从光源发出的光。撞到模型上发生反射,反射的光的方向假设正好和视线一致的话,这就是最强光了。例如以下图所看到的:
像这样模拟反射光。就不得不进行高负荷的计算。
这里,有一个手法,能够用比較简单的处理来得到类似的结果,就是通过光向量和视线向量的中间向量来求反射光的类似效果。
使用中间向量得到的反射光的近似处理。首先求出光向量和视线向量的中间向量,然后求中间向量和面法线向量的内积,从而决定反射光的强度。
和面法线向量的内积在之前也做过了吧。
在平行光源的计算的时候,就计算了光向量和面法线向量的内积。
和这个处理流程是一样的,这次求一下中间向量和面法线向量的内积。
这样。就能够简单的模拟反射光的效果了。
顶点着色器的改动
attribute vec3 position;
attribute vec3 normal;
attribute vec4 color;
uniform mat4 mvpMatrix;
uniform mat4 invMatrix;
uniform vec3 lightDirection;
uniform vec3 eyeDirection;
uniform vec4 ambientColor;
varying vec4 vColor; void main(void){
vec3 invLight = normalize(invMatrix * vec4(lightDirection, 0.0)).xyz;
vec3 invEye = normalize(invMatrix * vec4(eyeDirection, 0.0)).xyz;
vec3 halfLE = normalize(invLight + invEye);
float diffuse = clamp(dot(normal, invLight), 0.0, 1.0);
float specular = pow(clamp(dot(normal, halfLE), 0.0, 1.0), 50.0);
vec4 light = color * vec4(vec3(diffuse), 1.0) + vec4(vec3(specular), 1.0);
vColor = light + ambientColor;
gl_Position = mvpMatrix * vec4(position, 1.0);
}
这样。就更能体现强光的反射效果。另外,减少求幂的次数,则会将该部分的亮点覆盖的范围会变大,要实现局部闪烁等效果的时候。适当的对求幂的次数进行控制就能实现了。
改动javascript代码
// 将uniformLocation存入数组
var uniLocation = new Array();
uniLocation[0] = gl.getUniformLocation(prg, 'mvpMatrix');
uniLocation[1] = gl.getUniformLocation(prg, 'invMatrix');
uniLocation[2] = gl.getUniformLocation(prg, 'lightDirection');
uniLocation[3] = gl.getUniformLocation(prg, 'eyeDirection');
uniLocation[4] = gl.getUniformLocation(prg, 'ambientColor');
// 视图×投影坐标变换矩阵
m.lookAt([0.0, 0.0, 20.0], [0, 0, 0], [0, 1, 0], vMatrix);
m.perspective(45, c.width / c.height, 0.1, 100, pMatrix);
m.multiply(pMatrix, vMatrix, tmpMatrix); // 平行光源的方向
var lightDirection = [-0.5, 0.5, 0.5]; // 视点向量
var eyeDirection = [0.0, 0.0, 20.0]; // 环境光的颜色
var ambientColor = [0.1, 0.1, 0.1, 1.0]; // (中间部分代码略) // uniform变量的写入
gl.uniformMatrix4fv(uniLocation[0], false, mvpMatrix);
gl.uniformMatrix4fv(uniLocation[1], false, invMatrix);
gl.uniform3fv(uniLocation[2], lightDirection);
gl.uniform3fv(uniLocation[3], eyeDirection);
gl.uniform4fv(uniLocation[4], ambientColor);