立方体旋转动画

  要产生立方体旋转的动画效果,你首要了解“帧”这个概念,比如你观看的视频其实就是一帧一帧的图片连续播放的效果,只要图片刷新的频率的不是太低,人的眼睛都不会察觉,一般30~60FPS就可以。 WebGL如何产生一帧一帧的图片,这个很简单,执行一次gl.drawArrays(),WebGL图形系统就会通知GPU渲染管线处理顶点数据生成一帧RGB像素数据显示在屏幕上。只要周期性保持一定的频率调用gl.drawArrays()就可以生成一帧一帧的图片, 在这个过程中同时要利用Javascript程序更新顶点的旋转矩阵,如果顶点的位置不变化,渲染出来的都是一样的图片,自然也没有动画的效果。

  浏览器提供了一个方法requestAnimationFrame()可以实现周期性调用某个函数,主要用于动画,该方法如何使用可以关注《HTML5定时器》

  在光照立方体的基础上进行更改,一方面是周期性执行绘制方法gl.drawArrays(),另一方面以一定的旋转速度更新立方体的旋转矩阵,原来使用着色器语言定义的旋转矩阵更改为使用Javascript语句创建好再传递给顶点着色器, gl.drawArrays()每次执行的时候,都会重新传入着色器顶点旋转矩阵数据,并渲染出来。

声明矩阵变量

  在顶点着色器代码中使用关键字uniform声明两个旋转矩阵变量mx和my,分别表示绕x轴、y轴的旋转矩阵。旋转矩阵数据和光照数据一样适用于所有的顶点数据,使用关键字uniform声明,不能使用attribute关键字声明。

19   /**uniform声明旋转矩阵变量mx、my**/
20   'uniform mat4 mx;'+//绕x轴旋转矩阵
21   'uniform mat4 my;'+//绕y轴旋转矩阵

传入mx矩阵数据

  上节课定义顶点旋转矩阵使用的着色器语言,下面的案例是现在Javascript程序中使用类型数组Float32Array()创建旋转矩阵的数据,然后使用uniformMatrix4fv()方法传递给着色器。WebGL中给着色器中不同关键字声明的不同类型变量传递数据, 要使用不同的WebGL API方法,uniform关键字声明的mat4类型变量使用uniformMatrix4fv()方法,uniform关键字声明的mat2类型变量使用uniformMatrix2fv()方法,uniform关键字声明的一个浮点数使用gl.uniform1f()传递, uniform关键字声明的vec4类型变量和mat4一样使用uniform4fv(变量地址名,new Float32Array([a,b,c,d]))传递,也可以使用uniform4f(变量地址名,a,b,c,d)传递,attribute关键字声明的变量使用方法vertexAttribPointer()传递。

  第134行代码中uniformMatrix4fv()方法的第一个参数是旋转矩阵mx的地址,第二个参数是布尔值,表示是否进行转置,第三个参数maxArr表示一个包含16个元素的类型数组。

  PI是Javascript内置对象Math的一个属性,Math.PI表示弧度π;sin()、cos()都是Math对象的方法,使用Math.sin()、Math.cos()求解角度的正弦值、余弦值。

54       /**从program对象获得旋转矩阵变量mx、my地址**/
55       var mx = gl.getUniformLocation(program,'mx');
56       var my = gl.getUniformLocation(program,'my');
126      /**绕x轴旋转45度**/
127      var mxArr = new Float32Array([
128          1,0,0,0,
129          0,Math.cos(Math.PI/4),-Math.sin(Math.PI/4),0,
130          0,Math.sin(Math.PI/4),Math.cos(Math.PI/4),0,
131          0,0,0,1
132      ]);
133      //把数据mxArr传递给着色器旋转矩阵变量mx
134      gl.uniformMatrix4fv(mx, false, mxArr);

绘制函数draww()

  该绘制函数可以使用第155行代码的requestAnimationFrame(draw)方法实现draww()函数的循环调用,因为要实现立方体绕y轴旋转,所以要在draw函数中更新my旋转矩阵的数据,同时利用方法uniformMatrix4fv()传递给着色器, 在函数重复调用gl.drawArrays(gl.TRIANGLES,0,36);不停绘制旋转后的顶点数据,所有需要更新的数据都要写在draww函数中,不需要反复执行的代码写在draw函数外,比如mx旋转矩阵只需要执行传入一次不在改变。

135  /**
136   * 定义绘制函数draw(),定时更新旋转矩阵数据,并调用WebGL绘制API
137   ***/
138  var angle = Math.PI/4;//起始角度
139  var angleSpeed = Math.PI/3000;//角速度Math.PI/3000弧度每毫秒
140  var T0 = new Date();//上次时间
141  function draw() {
142  gl.clear(gl.COLOR_BUFFER_BIT);//清空画布上一帧图像
143  /**时间计算**/
144  var T1 = new Date();//本次时间
145  var t = T1-T0;//时间差(t的单位ms)
146  T0 = T1;//把本次时间赋值给上次时间
147  /**
148   * 立方体绕y轴旋转
149   ***/
150  angle += t*angleSpeed;//时间差乘以角速度
151  var sin = Math.sin(angle);//旋转角度正弦值
152  var cos = Math.cos(angle);//旋转角度余弦值
153  var myArr = new Float32Array([cos,0,-sin,0,  0,1,0,0,  sin,0,cos,0,  0,0,0,1]);
154  gl.uniformMatrix4fv(my, false, myArr);
155  requestAnimationFrame(draw);
156  /**执行绘制命令**/
157  gl.drawArrays(gl.TRIANGLES,0,36);
158  }
159  draw();