立方体(每个面一种颜色)

源码下载

  思路很简单,在线框模式的立方体源码基础上直接进行更改,添加varying变量,引入顶点数据颜色,立方体6个面,每个面可以分为两个三角面绘制出来,也就是说每个面需要定义6个点,6个点需要定义36个顶点。

着色器程序

  着色器程序参考颜色插值varying的使用方法添加即可,就不再列出。

顶点数据

54       /**
55        创建顶点位置数据数组data,Javascript中小数点前面的0可以省略
56        **/
57       var data=new Float32Array([
58           .5,.5,.5,-.5,.5,.5,-.5,-.5,.5,.5,.5,.5,-.5,-.5,.5,.5,-.5,.5,      //面1
59           .5,.5,.5,.5,-.5,.5,.5,-.5,-.5,.5,.5,.5,.5,-.5,-.5,.5,.5,-.5,      //面2
60           .5,.5,.5,.5,.5,-.5,-.5,.5,-.5,.5,.5,.5,-.5,.5,-.5,-.5,.5,.5,      //面3
61           -.5,.5,.5,-.5,.5,-.5,-.5,-.5,-.5,-.5,.5,.5,-.5,-.5,-.5,-.5,-.5,.5,//面4
62           -.5,-.5,-.5,.5,-.5,-.5,.5,-.5,.5,-.5,-.5,-.5,.5,-.5,.5,-.5,-.5,.5,//面5
63           .5,-.5,-.5,-.5,-.5,-.5,-.5,.5,-.5,.5,-.5,-.5,-.5,.5,-.5,.5,.5,-.5 //面6
64       ]);
65       /**
66        创建顶点颜色数组colorData
67        **/
68       var colorData = new Float32Array([
69           1,0,0, 1,0,0, 1,0,0, 1,0,0, 1,0,0, 1,0,0,//红色——面1
70           0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,//绿色——面2
71           0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,//蓝色——面3
72           1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,//黄色——面4
73           0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0,//黑色——面5
74           1,1,1, 1,1,1, 1,1,1, 1,1,1, 1,1,1, 1,1,1 //白色——面6
75       ]);

深度测试

91       /**执行绘制之前,一定要开启深度测试,以免颜色混乱**/
92       gl.enable(gl.DEPTH_TEST);

  可以尝试把深度测试的语句注释掉,测试代码,观察视觉效果,你会看到面颜色混乱,比如立方体后面的颜色掩盖前面的颜色。执行drawArrays()方法后,GPU开始绘制图形,默认的规则是后生成的像素覆盖前面生成的像素, 绿色的面是左侧可见面,但是如果没有gl.enable(gl.DEPTH_TEST);语句,你会看到本来处于底面不可见的黑色面会把绿色面覆盖,原因很简单,你可以看到代码中黑色面的顶点数据是面5在绿色面2的后面, 黑色面和绿色面在x,y坐标上是有重叠的,黑色与绿色重叠部分会被后生成的像素覆盖。说到这里你应该明白gl.enable(gl.DEPTH_TEST);语句的作用,顶点装配、光栅化后片元是携带坐标信息的, x,y坐标对应的就是显示器平面,z值就是深度信息,执行该语句就可以识别出黑色面和绿色面的前后位置关系,所有位置靠前的会显示在屏幕上,靠后的像素会被隐覆盖掉。

  gl.enable()是WebGL的方法,该方法的功能就像它的名字一样,可以开启某项功能,参数gl.DEPTH_TEST表示深度功能。GPU是一块数字电路, 渲染管线的每一个环节都是一个带有某种功能的数字电路单元,只是有些支持可编程,有些不支持可编程,有些可以设置开启或关闭,有些完全不可设置,对于顶点、片元着色器是可以编程的,这两个处理器可以执行编译后的着色器语言, GPU深度检测功能是可设置的,默认是关闭的,再执行绘制命令之前执行代码gl.enable(gl.DEPTH_TEST);就可以打开GPU的深度测试功能。

测试

  可以把所有的颜色都改为红色,然后执行绘制,你会发现并没有立体的视觉效果,生活中单色的物体也有立体感,这好像不符合生活常识,事实上生活中即使单色的物体在一个自然的光场环境下,它的反射到你眼睛的每个像素点颜色并不是单色是有微小的差异, 即使都是红色,两个像素的红色与红色R值分量会有微小的差异。

  白、蓝、绿处于其他三个面的前面,是可见面。可以把三个面设置为红色R分别为1、0.9、0.8来测试效果。你可以发现R值差异了0.1,你会有很强的立体感,其实你可以继续使用更小的差值,来测试你的眼睛视觉变化。这其实相当于手动编写颜色值,模拟自然界光场, 如果有兴趣可以学习下一章,如何仿真真实自然界的太阳光、灯光等各种类型光线在物体表面反射光场的分布,不仅不同的面会出现R值不同,一个面上的R值也会不同,呈现某种规律的变化,比如金属在阳光下会有局部高光现象。

    /**
     创建顶点颜色数组colorData
     **/
    var colorData = new Float32Array([
        1,0,0, 1,0,0, 1,0,0, 1,0,0, 1,0,0, 1,0,0,      //红色——面1
        .9,0,0, .9,0,0, .9,0,0, .9,0,0, .9,0,0, .9,0,0,//R=0.9——面2
        .8,0,0, .8,0,0, .8,0,0, .8,0,0, .8,0,0, .8,0,0,//R=0.8——面3
        1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,      //黄色——面4
        0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0,      //黑色——面5
        1,0,0, 1,0,0, 1,0,0, 1,0,0, 1,0,0, 1,0,0,      //R=1——面6
    ]);