31 WebGL平行光下的漫反射光的计算

案例查看地址:点击这里

通过上一节的介绍,我们可以知道,平行光下的漫反射光的颜色可以由一下式子得出:

<漫反射光颜色>=<入射光颜色>x<表面基底色>x cos θ

所以,我们要计算出来漫反射的光的颜色需要三项数据:

(1)平行入射光的颜色

(2)表面的基底色

(3)入射光与表面形成的入射角  θ

但是,我们没有办法直接就确定 θ值是多少,我们必须根据入射光的方向和物体表面的朝向(即法线方向)来计算出入射角。这需要我们先确定每个表面的朝向,在指定光源的时候,再确定光的方向,来计算出入射角,并确定 θ的值。

幸运的是,我们可以通过计算两个矢量的点积,来计算着两个矢量的夹角余弦值cos  θ。点积运算的使用非常频繁,GLSL ES内置了点积运算函数(详见GLSL ES中的第11节,11 WebGL 着色器编程语言GLSL ES的内置函数)。在公式中,我们使用点符号 · 来表示点积运算。这样,cos θ就可以通过下式计算出来:

cos θ = <光线方向> · <法线方向>

所以,上面计算平行光下的漫反射的颜色的式子就可以修改成:

<漫反射光颜色> = <入射光颜色> x <表面基底色> x (<光线方向> · <法线方向>)

这里有两点需要注意:

(1)光线方向矢量和表面法线矢量的长度必须为1,否则反射光的颜色就会过暗或过亮。将一个矢量的长度调整为1,同时保持方向不变的过程称之为归一化。GLSL ES提供了内置的归一化函数,你可以直接使用。

(2)这里所谓的“光线方向”,实际上是入射方向的反方向,即从入射点指向光源方向(因为这样,该方向与法线方向的夹角才是入射角),如图。

31 WebGL平行光下的漫反射光的计算_第1张图片

法线:表面的朝向

物体表面的朝向,即垂直于表面的方向,又称法线或法向量。法向量有三个分量,向量(nx,ny,nz)表示从原点(0,0,0)指向点(nx,ny,nz)的方向。比如说,向量(1,0,0)表示x轴正方向,向量(0,0,1)表示z轴正方向。涉及到表面和法向量的问题时,必须考虑以下两点:

(1)一个表面具有两个法向量

每个表面都有两个面,“正面”和“背面”。两个面各自具有一个法向量。比如,垂直于z轴的x-y平面,其正面的法向量为z正半轴,即(0,0,1),背面的法向量为z负半轴,即(0,0,-1)。

31 WebGL平行光下的漫反射光的计算_第2张图片

在三维图形学中,表面的正面和背面取决于绘制表面时的顶点顺序。当你按照v0,v1,v2,v3的顶点顺序绘制了一个平面,那么当你从正面观察这个表面时,这4个顶点是顺时针的,而你从背面观察该表面,这四个顶点就是逆时针的。

(2)平面的法向量唯一

由于法向量表示的是方向,与位置无关,所以一个平面只有一个法向量。换句话说,平面的任意一点都具有相同的法向量。

进一步说,即使有两个不同的平面,只要朝向相同(也就是两个平面平行),法向量也相同。

31 WebGL平行光下的漫反射光的计算_第3张图片

一旦计算好每个平面的法向量,接下来的任务就是将数据传给着色器程序。以前的程序把颜色作为“逐顶点数据”存储在缓冲区中,并传给着色器。对法向量数据也可以这样做。上图所示,每个顶点对应3个法向量,就像之前每个顶点都对应3个颜色值一样。我们明白了这一点以后,就可以通过法向量获取平行光照后的颜色值了。

31 WebGL平行光下的漫反射光的计算_第4张图片




    
    
    
    Title
    









在顶点着色器中,我们实现了漫反射光颜色的计算,使用的是:

<漫反射光颜色> = <入射光颜色> x <表面基底色> x (<光线方向> · <法线方向>)

计算漫反射光颜色需要:(1)入射光颜色 (2)表面基底色 (3)入射光方向 (4)表面法线方向。其中后两者都必须是归一化的(即长度为1.0)。

在上面的案例代码中:

a_Color 变量表示表面基底色

a_Normal变量表示表面法线方向

u_LightColor变量表示入射光颜色

u_LightDirection变量表示入射光方向(是在世界坐标系下的,在javascript中归一化了,可以避免着色器每次执行都对它进行归一化)

相关的变量已经获取,下面是进行处理:

着色器部分处理:

首先对a_Normal法线变量进行归一化,虽然写的值是已经归一化过的,但是顶点着色器可不知道传入的矢量是否经过了归一化,而且这里没有节省开销的理由(法向量是逐顶点的),由于使用x,y和z三个分量就可以表示法线方向,我们需要将这三个分量提取出来,使用到了vec3()方法,然后使用内置函数normalize()函数进行归一化。

接下来,我们计算点积<光线方向> · <法线方向>。法线方向已经被归一化,光线方向在传入进来之前已经被归一化。直接使用GLSL ES提供的内置函数dot()进行点积运算。然后又使用max()函数时因为如果计算出来的数大于90度的话,就已经在背面了。我们这是计算的不透明的,所以在背面就是0。

计算出来点积后,就可以继续套用公式进行漫反射光的颜色,计算出漫反射光的rgb颜色。

最后再把rgba的a给补上,最后就把颜色给计算了出来,再把颜色通过varying变量v_Color传到片元着色器。

js部分处理:

首先就给u_LightColor赋值了光线的颜色。

然后给u_LightDirection赋值光线方向,再使用cuon-matrix.js里面封装好的函数,直接在对象上调用一下,使对象的值归一化,最后把值赋值给了u_LightDirection。

最后在颜色下面声明了一个存储法向量的Float32Array将值存储,和顶点和颜色一起赋值。

你可能感兴趣的:(漫反射,立方体,WebGL,WebGL)