天天看点

用html创建一个立方体,9.4 创建一个旋转的立方体 - HTML5 Canvas 实战

好了,现在真正有趣的事情开始了。本节,我们将创建一个旋转的3D立方体,该立方体具有不同颜色的表面。为了做到这一点,我们将介绍两类新的缓冲区——颜色缓冲区和索引缓冲区。

用html创建一个立方体,9.4 创建一个旋转的立方体 - HTML5 Canvas 实战

图9-3 旋转的立方体

操作步骤

按照以下步骤,使用WebGL创建一个旋转立方体:

1. 链接到glMatrix库和WebGL包装器:

2. 定义initBuffers()函数,该函数初始化立方体的位置缓冲区,颜色缓冲区,及索引缓冲区:

function initBuffers(gl) {

var cubeBuffers  =  {}

cubeBuffers.positionBuffer  = gl.createArrayBuffer([

// Front face

-1,  -1,     1,

1,  -1,    1,

1,   1,   1,

-1,    1,   1,

// Back face

-1,  -1,  -1,

-1,    1,  -1,

1,   1,  -1,

1,  -1,  -1,

// Top face

-1,    1,  -1,

-1,    1,   1,

1,   1,   1,

1,   1,  -1,

// Bottom face

-1,  -1,  -1,

1,  -1,  -1,

1,  -1,    1,

-1,  -1,     1,

// Right face

1,  -1,  -1,

1,   1,  -1,

1,   1,   1,

1,  -1,    1,

// Left face

-1,  -1,  -1,

-1,  -1,     1,

-1,    1,   1,

-1,    1,  -1

]);

//构建彩色顶点

var colors  =  [

[1,  0,  1,  1],  // Front face  - Pink

[0,  1,  0,  1],  // Back face  - Green

[0,  0,  1,  1],  // Top face  - Blue

[0,  1,  1,  1],  // Bottom face  - Turquoise

[1,  1,  0,  1],  // Right face  - Yellow

[1,  0,  0,  1] // Left face  - Red

];

var colorVertices  =  [];

for  (var n in colors)  {

var color  = colors[n];

for  (var i=0; i 

colorVertices = colorVertices.concat(color);

}

}

cubeBuffers.colorBuffer = gl.createArrayBuffer(colorVertices);

cubeBuffers.indexBuffer = gl.createElementArrayBuffer([

0,  1,  2,          0,  2,  3,        // Front face

4,  5,  6,          4,  6,  7,        // Back face

8,  9,  10,         8,  10,  11,      // Top face

12,  13,  14,       12,  14,  15,  // Bottom face

16,  17,  18,       16,  18,  19,  // Right face

20,  21,  22,       20,  22,  23      // Left face

]);

return cubeBuffers;

}

3. 定义stage()函数,该函数设置透视矩阵,把模型-视图矩阵设置到单位矩阵,平移立方体,旋转立方体,把位置缓冲区、颜色缓冲区、索引缓冲区发送到显卡,最后,因为模型的表面不是三角形,所有要调用drawElements()方法来绘制该立方体:

function stage(gl, cubeBuffers, angle){

// set field of view at  45 degrees

// set viewing range between  0.1 and  100.0 units away.

gl.perspective(45,  0.1,  100);

gl.identity();

// translate model-view matrix

gl.translate(0,  0,  -5);

// rotate model-view matrix about x-axis  (tilt box downwards)

gl.rotate(Math.PI  *  0.15,  1,  0,  0);

// rotate model-view matrix about y-axis

gl.rotate(angle,  0,  1,  0);

gl.pushPositionBuffer(cubeBuffers);

gl.pushColorBuffer(cubeBuffers);

gl.pushIndexBuffer(cubeBuffers);

gl.drawElements(cubeBuffers);

}

4. 页面加载完成后,初始化WebGL包装器对象,把着色器程序设置为“VARYING_COLOR”( 因为每个面是变量,并且依赖于颜色缓冲区、初始化缓冲区),为动画设置stage函数,然后启动动画:

window.onload  = function(){

var gl  = new WebGL("myCanvas", "experimental-webgl");

gl.setShaderProgram("VARYING_COLOR");

var cubeBuffers  = initBuffers(gl);

var angle  =  0;

gl.setStage(function(){

// update angle

var angularVelocity = Math.PI  /  4;  // radians  / second

var angleEachFrame  = angularVelocity  * this.getTimeInterval()  /  1000;

angle  += angleEachFrame;

this.clear();

stage(this, cubeBuffers, angle);

});

gl.start();

};

5. 在HTML文档的body部分嵌入canvas标签:

工作原理

本节介绍了索引缓冲区和颜色缓冲区的概念。在前两节,我们创建了一个三角形的平面,三角形平面的模型是WebGL中最容易实现的,因为它仅仅需要一个缓冲区——位置缓冲区。若要使用非三角形的面来创建一个3D模型,如立方体,就稍微有点复杂,因为我们要把立方体表示为一组三角形的面。我们可以通过创建一个索引缓冲区,把三角形映射为位置缓冲区中的顶点来实现它。

看看前面代码中的索引缓冲区中的顶点。你将会注意到前6个元素是[0, 1, 2, 0, 2, 3]。前三个元素,[0, 1, 2]指的是位置缓冲区中的第0个,第1个,第2个顶点,它们形成一个立方体正面的半个三角形。第二组元素,[0, 2, 3]相当于位置缓冲区中的第0个,第2个,第3个顶点,它们形成一个立方体正面的另外半个三角形。放在一起,这两个三角形形成立方体的正面。完整的索引缓冲区中,将包含构成立方体的6个面在位置缓冲区中顶点的映射。

除了索引缓冲区,本节还需要使用颜色缓冲区。颜色缓冲区用来定义模型各个面的颜色。本节的颜色缓冲区为立方体的6个面,定义了6种不同的颜色。跟索引缓冲区类似,颜色缓冲区用来把颜色映射到位置缓冲区中的每个顶点。某种颜色由[红, 绿, 蓝, 透明度]四个元素定义。根据位置缓冲区的定义,我们的立方体由6个面组成,每个面有4个顶点。因此,我们的元素缓冲区数组应该包含(6 个面) * (4 个顶点每个面) * (4 个元素每种颜色) = 96 个元素。

一旦我们的位置缓冲区、颜色缓冲区、索引缓冲区定义完成,剩下的就只有把每个缓冲区发送到显卡,并渲染模型了。前两节,直接使用drawArrays()方法来渲染三角形,跟前两节不同,本节我们必须使用drawElements()方法,因为我们的模型是由非三角形面组成的,需要一个索引缓冲区来把三角形面映射到模型的各个正方形的面。

相关参考

第5章 创建Animation类