注:文章译自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

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

[WebGL入门]二十三,反射光的光照效果的更多相关文章

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

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

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

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

  3. [WebGL入门]二十一,从平行光源发出的光

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

  4. [WebGL入门]二,開始WebGL之前,先了解一下canvas

    年2月)HTML5依旧处于草案阶段. HTML5支持网页端的多媒体功能和画布功能,追加了非常多全新的更合理的Tag标签.各个浏览器也都在逐渐的完好这些新的特性. Canvas对象表示一个 HTML画布 ...

  5. WebGL入门教程(二)-webgl绘制三角形

    前面已经介绍过了webgl,WebGL入门教程(一)-初识webgl(http://www.cnblogs.com/bsman/p/6128447.html),也知道了如何绘制一个点,接下来就用web ...

  6. WPF入门教程系列二十三——DataGrid示例(三)

    DataGrid的选择模式 默认情况下,DataGrid 的选择模式为“全行选择”,并且可以同时选择多行(如下图所示),我们可以通过SelectionMode 和SelectionUnit 属性来修改 ...

  7. Bootstrap入门(二十三)JS插件1:模态框

    Bootstrap入门(二十三)JS插件1:模态框 1.静态实例 2.动态实例 3.模态框的尺寸和效果 4.包含表单的模态框 模态框经过了优化,更加灵活,以弹出对话框的形式出现,具有最小和最实用的功能 ...

  8. WebGL入门教程(五)-webgl纹理

    前面文章: WebGL入门教程(一)-初识webgl WebGL入门教程(二)-webgl绘制三角形 WebGL入门教程(三)-webgl动画 WebGL入门教程(四)-webgl颜色 这里就需要用到 ...

  9. WebGL入门教程(四)-webgl颜色

    前面文章: WebGL入门教程(一)-初识webgl WebGL入门教程(二)-webgl绘制三角形 WebGL入门教程(三)-webgl动画 颜色效果图: 操作步骤: 1.创建HTML5 canva ...

随机推荐

  1. hihocode 编程练习赛17

    1. f1 score 首先了解f1 score的计算方法, 我记得是学信息检索知道的, 然后简单处理就行. 由于我写的比较麻烦, 中间处理过程引入了一些除数为0的情况,导致错了很多次.其实是很简单的 ...

  2. 我正在学英语是用learning english还是用studying english?

    学一门语言用 learn. study 表示深入研究,一般指在大学里.如果大学里的专业是英语,就可以说 study English. 1. If you study hard, you will le ...

  3. JavaScript 封装插件学习笔记(一)

    此篇只是笔记,在借鉴.参考.模仿的过程,可能不完整,请多指教! 定义插件名称要注意命名冲突,防止全局污染. 1.第一种Javascript对象命名:(Javascript语言是“先解析,后运行”,解析 ...

  4. Android Thermal-engine

    Thermal Engine Thermal 相关的东西主要在Vendor/qcom/proprietary/thermal-engine 目录下: thermal-engine.conf 文件可以用 ...

  5. 在VirtualBox上安装Solaris 10全教程(包括下载)

    您可以在博文的最下方留下评价, 也可以点击左边的 关注 来关注我的博客的最新动态. 如果文章内容对您有帮助, 不要忘记点击右下角的 推荐 来支持一下喔 如果您对博文有任何疑问, 可以通过评论或发邮件的 ...

  6. html5——过渡

    transition:1.开始状态   2.终止状态    3.过渡属性 transition: width 2s, background-color 2s;//属性,时间 transition: a ...

  7. 将MongoDB服务器设置成Windows启动服务(win10)

    如题,这个问题也百度了很久,百度还是挺给力的,但是都没能解决问题,后来在大神(原谅我不知道大神叫什么)的指导下,终于设置成功,特分享下设置过程.. MongoDB设置数据库我就不说了...额..算了, ...

  8. HDU_1848_博弈,sg函数

    Fibonacci again and again Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Jav ...

  9. mysql高可用架构mha之master_ip_failover脚本

    脚本如下:           #!/usr/bin/env perl use strict; use warnings FATAL => 'all'; use Getopt::Long; my ...

  10. 简述prototype, _proto_, constructor三者的关系

    1.prototype 感概:每个函数都有一个prototype这个属性,而这个属性指向一个对象,这个对象称为原型对象 作用: a.节约内存 b.扩展属性和方法 c.实现类与类的之间的继承 2._pr ...