JSON

虚拟现实(VR)模拟仿真行业资讯 第三维度

字号+ 作者:H5之家 来源:H5之家 2016-01-20 18:00 我要评论( )

WebGL教程15: 镜面高光和载入JSON模型,在这节课中,我们将会引入从第7课开始介绍的冯氏反射模型中的最后一个部分:镜面高光——在一个光泽表面上闪光的部分。镜

    来源:

    HiWebGL译者声明:因为译者个人方便的原因,我们将原教程中的第三方图形库由glMatrix改为Oak3D实现,这不影响到Demo的最终效果和实现,也不影响到WebGL的讲解和学习。原教程正文中相应的代码和讲解也为做了相应修改!本教程由HiWebGL翻译整理,转载请注明出处!

    关于Oak3D:Oak3D是一套简单易用、性能优越的WebGL Javascript Library。您可以在他们的主页找到更多信息。Oak3D主页:

    欢迎来到WebGL教程的第14课。在这节课中,我们将会引入从第7课开始介绍的冯氏反射模型中的最后一个部分:镜面高光——在一个光泽表面上闪光的部分。镜面高光会让你的场景看起来更加真实。

    下面的视频就是我们这节课将会完成的最终效果。   


    你会看到一个旋转的“犹他茶壶”,旋转的同时你会看到在茶壶中部偏左的部分和茶壶盖子的帽上会有常亮的高光,另外当茶壶的壶嘴和把手与光源成特定角度时,偶尔也会有高光出现。你可以使用canvas下面的复选框来切换是否开启镜面高光,是否开启光源、切换3个不同的纹理状态,分别是不使用纹理、默认的电镀金属纹理(根据CC协议,感谢Arroway Textures提供),最后为了好玩,我们还加上了一个地球的纹理(感谢European Space Agency/Envisat提供),不过茶壶形状的地球看起来实在是太猎奇了。

    下面我们来看看它是怎么工作的……

    惯例声明:本系列的教程是针对那些已经具备相应编程知识但没有实际3D图形经验的人的;目标是让学习者创建并运行代码,并且明白代码其中的含义,从而可以快速地创建自己的3D Web页面。如果你还没有阅读前一课,请先阅读前一课的内容吧。因为本课中我只会讲解那些与前一课中不同的新知识。

    另外,我编写这套教程是因为我在独立学习WebGL,所以教程中可能(非常可能)会有错误,所以还请风险自担。尽管如此,我还是会不断的修正bug和改正其中的错误的,所以如果你发现了教程中的错误,请告诉我。

    有两种方法可以获得上面实例的代码:在实例的独立页面中选择“查看源代码”;或者点击这里下载我们为您准备好的压缩包。

    得到了源代码之后,请在编辑器中打开。这次我们从代码顶部开始,然后顺着慢慢往下看。这样的好处是我们可以先看到本科中最有趣的部分,也就是片元着色器。在开始之前,还要说一下本课代码和第13课中的一个区别,那就是我们摒弃了逐顶点光照的代码。说实话,逐顶点光照不能很好处理镜面高光(因为看起来非常斑驳),所以我们不再使用它了。
 
    好了,首先你会看到逐片元光照的片元着色器代码。和通常一样,代码先定义了浮点级别的精确度,声明了varying变量和uniform变量。在uniform变量中,我们将点光源的颜色分成了2个变量来分别储存,一个是漫反射的颜色,另一个是镜面高光的颜色。请注意第17行和第26、27行。

9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29       vTransformedNormalvPosition;   uniform float uMaterialShininess;   uUseLightinguUseTextures;   uniform vec3 uAmbientColor;   uPointLightingSpecularColoruPointLightingDiffuseColor;   uniform sampler2D uSampler;

    没必要解释太多,你可以在页面中手动设定它们的值。让我们接着往下看着色器部分的主函数,首先要做的事情就是判断光照是否开启,这段代码和之前的一样。

32 33 34 35 36 lightWeightinguUseLighting) { lightWeighting

    下面我们开始处理光照,好戏就要上演了!

37 38 39 40 41 uPointLightingLocation normal vTransformedNormal);   uShowSpecularHighlights) {

    这儿到底怎么了呢?和往常一样,我们为逐片元光照计算出光照方向;然后将片元的法线向量归一化,这还是和往常一样——切记,顶点法线在经过线线性插值之后,得到的片元法线的长度会改变,所以我们必须进行归一化处理!但是这次,我们会比较多地使用归一化之前的线性插值的结果,所以我们将其储存在一个本地变量中。然后,我们定义了一个变量用来储存由镜面高光所带来的额外的亮度。如果镜面高光没有开启,显然它的值应当是0;反之,我们就要计算它了。

    那么,究竟是什么决定了镜面高光的亮度呢?你也许还记得,在第7课中我们解释冯氏反射模型的时候曾经说过,镜面高光其实就是光线像照到镜子上一样,照到物体表面然后反射出来的部分。

    镜面反射(Specular):这就像镜子一样,反射光将按照和入射角相同的角度反射出来。这种情况下,你看到的物体反射出来的光的亮度,取决于你的眼睛和光反射的方向是否在同一直线上;也就是说,反射光的亮度不仅与光线的入射角有关,还与你的视线和物体表面之间的角度有关。镜面反射通常会造成物体表面上的“闪烁”和“高光”现象,镜面反射的强度也与物体的材质有关,无光泽的木材很少会有镜面反射发生,而高光泽的金属则会有大量镜面反射。

    计算镜面反射亮度的方程式如下:

    (Rm · V)α

    其中Rm是发生镜面反射时反射光的方向的单位向量,V是观察方向的单位向量,α是一个描述光泽度的常量,常量的值越大,光泽度越高。你也会还记得,两个向量的点积就是它们之间夹角的余弦值。这样的话,如果光线直接反射到观察者的眼睛中,那根据方程式计算出的结果是1(也就是说Rm和V是平行向量,夹角为0,而0的余弦是1),然后随着光线与视线方向的夹角慢慢变大,镜面反射的亮度也会慢慢地进行一个渐变。当施加α次幂之后,实际上会“压缩“镜面高光的效果,在某个点上,当两个向量平行时,计算结果仍然是1,但该点周围的亮度会迅速下降。你可以试着在Demo页面中调整光泽度常量的值,调的大一些,比如512,你就会明白了。

    好了,有了以上的准备,我们首先要做的就是计算出观察方向V和反射光方向Rm。让我们先来看看看V,因为它很简单。在第10课中提到过,我们的场景是基于eye space构造的。也就是说,我们的相机位于原点(0,0,0),看向Z轴的负半轴,X轴的坐标越往右越大,Y轴的坐标越往上越大。从原点到空间中的任何一点的方向,就等于该点的坐标值所表示的向量。那么同样的,反过来,从任何一点看向原点的观察方向,就是该点坐标值的负值。我们对顶点坐标进行线性插值,得到了片元的坐标,储存在vPosition变量中,然后对其取负值,然后归一化使其长度为1,这样我们就得到了观察方向的单位向量V。

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • WebGL教程:第14课,镜面高光和载入JSON模型

    WebGL教程:第14课,镜面高光和载入JSON模型

    2015-10-03 14:05

网友点评
l