在上一篇文章中,我们介绍了如何使用glMatrix.js来处理3D图形里面的数学运算,主要谈到了MVP的应用。同时,我们还简单地提到了如何使用JQuery来丰富我们的WebGL应用。
本文将介绍如何使用WebGL来制作一个旋转的立方体。在这篇教程里面,我们会提到以下内容:
VBO(Vertex Buffer Object)和IBO(Index Buffer Object)
如何绘制3D立方体
VBO就是我们常说的“顶点缓冲区对象”,这个在之前的三角形教程中已经介绍过了。而IBO则是索引缓冲区对象,全称是Index Buffer Object。它主要用来保存顶点的索引数据。
如果我们不使用IBO,而直接使用VBO的话,那么要绘制一个立方体,一共需要6*6=36个顶点。而使用IBO的话,每一个面只需要4个顶点即可,因为两个相邻的三角形是共用两个顶点的。任何复杂的几何模型都可以通过指定顶点和顶点索引定义出来。
首先,让我们看一下立方体的顶点数据定义,这里我们使用的是javascript数组:
1 | var vertecies = |
每一个顶点有x,y,z三个坐标,每一个面由两个三角形组成,所以需要6个顶点。不过我们可以这里使用的是IBO来共用顶点,所以每个面只需要4个顶点即可。下面是IBO的定义:
1 | var index = [0,1,2,//front |
首先,当然是创建VBO和IBO了:
1 | //创建并绑定IBO |
接来是往这两个buffer里面填充数据,WebGL是不能直接把Js的数组传递给GPU的,必须把它们转换成WebGL规定的类型,比如Float32Array和Uint16Array。
具体的代码如下所示:
1 | //传递顶点数据给VBO |
指定vertex shader如何读取VBO和IBO里面的数据。
这次我们使用gl.vertexAttribPointer函数时需要注意,最后一个参数是读取数据时的起始偏移量。
1 | var positionLocation = gl.getAttribLocation(program, "a_position"); |
要绘制立方体,只需要调用gl.drawElements这个函数即可:
1 | gl.drawElements(gl.TRIANGLES,36,gl.UNSIGNED_SHORT,0 |
注意这个函数的第1个参数是指绘制几何图元的类型,第2个参数是指索引的个数,第3个参数一定要是gl.UNSIGNED_SHORT或者gl.UNSIGNED_BYTE中的一个,最后一个参数是指索引数据的读取起始偏移量。
这样子绘制出来的立方体它是没有颜色的,如果我们需要每一个顶点指定颜色,则还需要创建一个VBO,然后绑定这个VBO,再通过vertex shader把这个颜色数据传递过去。
如果按照传递的c/c++程序的做法,我们一般会定义一个顶点属性的结构体:
1 | typedef |
但是,js里面是不能这些定义的。我们可以直接把顶点和颜色放置在一个数组里面就行了:
1 | var vertecies = [1,-1,0,1,0,0,1, |
此时,如果使用gl.vertexAttribPointer时,strid的计算如下:
1 | var step = Float32Array.BYTES_PER_ELEMENT; |
比如,本例中,每一个顶点属性是7个数(3个顶点+4个颜色位):
1 | gl.vertexAttribPointer(positionLocation,3, gl.FLOAT, false, 7 * step ,0); |
使用requestAnimationFrame制作Animation Loop,避免使用setTimeOut方法。
1 | fpsInterval = 1000/60; |
本文源代码:传送门
这里的顶点数据我们除了使用Javascript数组来存取外,还可以使用json格式的数据。由于json可以给不同的数据命名,比如一个立方体的数据可以描述为以下json文件:
1 | { |
另外,json文件还可以使用AJAX来加载,这样我们就可以把需要绘制的顶点数据存在服务器上,需要的时候发一个AJAX请求即可。该方法特别适合于复杂模型的加载。