[WebGL入门]二十三,反射光的光照效果

翻译 2014年10月06日 21:47:31

注:文章译自http://wgld.org/,原作者杉本雅広(doxas),文章中如果有我的额外说明,我会加上[lufy:],另外,鄙人webgl研究还不够深入,一些专业词语,如果翻译有误,欢迎大家指正。



本次的demo的运行结果

各种各样的光照

上次,以及上上次,介绍了通过顶点着色器来实现光照效果。
最开始介绍了从平行光源发出的光,上次介绍了平行光源的缺点,以及对应这个缺点的方法,就是环境光源。
这次是光照处理的第三篇,进一步介绍反射光照。
反射光和它的名字一样,就是模拟光的反射。通过反射光,可以让3D场景更加的真实。
具体点儿说,反射光可以让模型呈现出光泽,就像金属那样,有光滑质感的表面。所以反射光的作用是很大的。
顺便说一下,specular直接翻译的话,是镜面反射,就是像镜子那样反射的意思。

反射光的概念

从平行光源发出的扩散光的光照,通过光的方向(光向量)和面的方向(面法线向量),来计算这个面的扩散程度,从而实现光照。光照最强的地方就是模型的颜色,反之,没有被光照到的地方,就会变成暗色。

但是,像金属那样的质感,就是光泽的表现,只用扩散光就不够了。为什么呢,光照最强的部分,也只不过是显示了模型的原来的颜色,要想表现出光泽,则需要表现一下高亮这样的强光效果。

修改顶点着色器,只通过扩散光虽然也可以实现高亮效果,但是大部分场合都会感觉不自然。这是因为扩散光是不会考虑视线的。扩散光,只是考虑光的方向和面的方向。而反射光,则会考虑观看模型的视线和光的方向,表现出的高亮部分会非常的自然。

表示视线的向量和表示光的向量,再加上面法线向量,可以算出反射光的强度。想一下的话,就是从光源发出的光,撞到模型上发生反射,反射的光的方向如果正好和视线一致的话,这就是最强光了。如下图所示:


像这样模拟反射光,就不得不进行高负荷的计算。这里,有一个手法,可以用比较简单的处理来得到相似的结果,就是通过光向量和视线向量的中间向量来求反射光的类似效果。

使用中间向量得到的反射光的近似处理,首先求出光向量和视线向量的中间向量,然后求中间向量和面法线向量的内积,从而决定反射光的强度。

和面法线向量的内积在之前也做过了吧。在平行光源的计算的时候,就计算了光向量和面法线向量的内积。和这个处理流程是一样的,这次求一下中间向量和面法线向量的内积。这样,就可以简单的模拟反射光的效果了。



顶点着色器的修改

这次和上次一样,全都在顶点着色器中进行计算,将最终计算的颜色情报传给片段着色器。
>顶点着色器的代码
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);
}
这次没有增加attribute变量,而是增加了表示视线向量的uniform变量eyeDirection,视线向量并不是每个顶点情报都不同,所有的顶点都是一致的处理,所以使用了uniform修饰符。
和平行光源发出的扩散光原理一样,使用模型坐标变换矩阵的逆矩阵来对视线向量进行变换,变换之后的视线向量和光向量的中间向量保存到halfLE中,然后和面法线向量求内积,进行光反射计算。
这里新出现了一个内置函数,就是给变量specular赋值的时候的时候使用的函数pow,这个函数是用来求幂的,比如2的平方,2的三次方等计算。
因为反射光是为了体现强光照射,根据内积得到的结果进行求幂运算,然后限制结果范围。由内积得到的结果用clamp函数将范围限制在0.0 ~ 1.0,求幂之后,小的数,会变的越来越小,而最强光的状态就是1,无论求多少次幂,也依然是1。

反射光根据求幂运算,让弱光的效果更弱,而强光的效果则不变。这样,就更能体现强光的反射效果。另外,降低求幂的次数,则会将该部分的亮点覆盖的范围会变大,要实现局部闪烁等效果的时候,适当的对求幂的次数进行控制就能实现了。
反射光的强度系数的使用和环境光的原理相同,所以颜色部分也使用加法运算,最终的颜色计算公式如下。
颜色=顶点颜色 * 扩散光 + 反射光 + 环境光
注意只有顶点颜色和扩散光的计算是乘法。

修改javascript代码

接着修改主要的代码部分。
顶点着色器做了几个比较复杂的修改,但是修改并不算多,主要是利用uniform变量来传入视线向量的处理。
>取得uniformLocation的处理
// 将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');
取得正确的uniformLocation之后,再定义视线向量并传给着色器。基本上,把在生成视图坐标变换矩阵的时候所指定的镜头的坐标,当作视线向量就可以了。(镜头的注视点是原点)
>视线向量的定义和写入
// 视图×投影坐标变换矩阵
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);
视线向量在着色器中是有三个元素的vec3,所以用uniform3fv函数传给着色器。这次的demo和光向量是一样的,所以视线向量也在持续循环的时候处理。

总结

好了,反射光相关的知识已经基本理解了吧。
与目前为止所涉及到的算法相比,今天的算法也不算难,就是,计算从光源发出的光向量和视线向量之间的半向量,然后与面法线向量求内积,所以相对的负荷也不大。但是,这只是在一定程度上模拟了反射光的效果,并不是非常严格的反射光的计算。
从渲染的结果来看,圆环体已经变的非常漂亮了,实际的效果,请参考文章最后给出的链接。
下一回,介绍一下高氏着色和补色着色
用扩散光,环境光以及反射光渲染的demo
http://wgld.org/s/sample_011/


转载请注明:转自lufy_legend的博客http://blog.csdn.net/lufy_legend

33 WebGL运动中的物体的光照效果(逆转置矩阵)

很多场景中,物体有可能会动,观察者的视角也很有可能会改变,我们必须考虑这种情况。首先,我们先看一下物体变动时,法向量的情况: ~平移变换不会改变法向量,因为平移不会改变物体的方向。 ~旋转变换会改...
  • qq_30100043
  • qq_30100043
  • 2017年06月08日 11:42
  • 328

[WebGL入门]二十四,补色着色

这一次分别说了高氏着色和补色着色两种着色,高氏着色的优点是计算量比较低,而和补色着色相比的话,渲染效果不太自然。 补色着色正好相反,计算量很高,但是渲染效果非常完美。 到底选择那种方法,取决于模型的顶...
  • lufy_Legend
  • lufy_Legend
  • 2014年10月11日 21:55
  • 5056

30 WebGL光照的概念

光照原理: 现实世界中的物体呗光纤照射时,会反射一部分光。只有当反射光纤进入你的眼睛时,你才能够看到物体并辨认出它的颜色。比如,白色的盒子会反射白光,当白光进入你的眼睛时,你才能看到盒子是白色的。 在...
  • qq_30100043
  • qq_30100043
  • 2017年06月05日 10:42
  • 461

[WebGL入门]二十五,点光源的光照

用点光源的光照,概念基本上和平行光源一样。根据获取光向量和顶点的法线及视点向量的内积来添加阴影。和平行光源的不同之处,简单的说就是光向量是否是一个固定值。点光源使用的是模型坐标变换后的顶点的位置和光源...
  • lufy_Legend
  • lufy_Legend
  • 2014年10月13日 00:22
  • 6156

WEBGL学习【十一】光照模型

HTML> html lang="en"> head> title>Listing 7-3 and 7-4, Texturing and Lighting With the Phong Ref...
  • m0_37981569
  • m0_37981569
  • 2017年11月12日 22:28
  • 69

一、WebGL入门的开始

一直对WebGL很感兴趣,但一直没时间学习,现在总算有了点时间。这也是鄙人第一次写博客,写的得不好望指正。 我比较喜欢先看效果,再分析代码。 代码如下: webgl-lesson1 ...
  • a23366192007
  • a23366192007
  • 2016年01月15日 19:15
  • 930

二、WebGL入门,基本开发流程

WebGL的标准来自于OpenGLES2.0,而OpenGLES2.0来自于纯可编程管线技术,有别与以前OpenGL的固定管线技术,可编程管线技术更加灵活,效率更高,但是对开发人员的要求更高。比如:以...
  • a23366192007
  • a23366192007
  • 2016年01月17日 15:43
  • 1175

五、WebGL入门,shader剖析

WebGL用的shader语言是glsl(OpenGL Shading Language), shader的主要工作有: 1. 利用视图和投影矩阵对点的位置进行变化 2. 如果需要利用法线的时候...
  • a23366192007
  • a23366192007
  • 2016年01月20日 19:41
  • 2250

webgl——实现物体描边效果

终于把手头的事结束了,可以有时间来研究研究技术~作为一名3D开发人员,仅仅使用现有的引擎来开发项目不免有些浮于表面,多研究研究底层的实现更利于对3D开发整体的把控~于是我决定最近开始研究webgl一些...
  • srk19960903
  • srk19960903
  • 2017年06月28日 20:45
  • 430

【WebGL】茶壶和光照

一、实验目的和要求   在OpenGL观察实验的基础上,通过实现实验内容,掌握OpenGL中消隐和光照的设置,并验证课程中消隐和光照的内容。   二、实验内容和原理   使用WebGL完成...
  • lishichengyan
  • lishichengyan
  • 2017年12月17日 19:37
  • 122
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:[WebGL入门]二十三,反射光的光照效果
举报原因:
原因补充:

(最多只允许输入30个字)