立方体旋转动画
要通过WebGL渲染出立方体旋转的动画效果,你首要了解“帧”这个概念,比如你观看的视频其实就是一帧一帧的图片连续播放的效果,只要图片刷新的频率的不是太低,人的眼睛都不会察觉,一般30~60FPS就可以。 WebGL如何产生一帧一帧的图片,这个很简单,执行一次绘制函数gl.drawArrays()
,WebGL图形系统就会通知GPU渲染管线处理顶点数据生成一帧RGB像素数据显示在屏幕canvas画布上。只要周期性保持一定的频率调用gl.drawArrays()
就可以生成一帧一帧的图片, 在这个过程中同时要利用Javascript程序更新顶点的旋转矩阵,如果顶点的位置不变化,渲染出来的都是一样的图片,自然也没有动画的效果。
浏览器提供了一个方法requestAnimationFrame()
可以实现周期性调用某个函数,主要用于动画,该方法如何使用可以查看文章《HTML5 定时器》。
在1.9节光照立方体的基础上进行更改,一方面是周期性执行绘制方法gl.drawArrays()
,另一方面以一定的旋转速度更新立方体的旋转矩阵,原来使用着色器语言定义的旋转矩阵更改为使用Javascript语句创建好再传递给顶点着色器, gl.drawArrays()
每次执行的时候,都会重新传入着色器顶点旋转矩阵数据,并渲染出来。
声明矩阵变量
/**uniform声明旋转矩阵变量mx、my**/
uniform mat4 mx;//绕x轴旋转矩阵
uniform mat4 my;//绕y轴旋转矩阵
在顶点着色器代码中使用关键字uniform
声明两个旋转矩阵变量mx
和my
,分别表示绕x轴、y轴的旋转矩阵。旋转矩阵数据和光照数据一样适用于所有的非顶点数据,使用关键字uniform
声明,不能使用attribute
关键字声明。
传入mx矩阵数据
/**从program对象获得旋转矩阵变量mx、my地址**/
var mx = gl.getUniformLocation(program,'mx');
var my = gl.getUniformLocation(program,'my');
/**绕x轴旋转45度**/
var mxArr = new Float32Array([
1,0,0,0,
0,Math.cos(Math.PI/4),-Math.sin(Math.PI/4),0,
0,Math.sin(Math.PI/4),Math.cos(Math.PI/4),0,
0,0,0,1
]);
//把数据mxArr传递给着色器旋转矩阵变量mx
gl.uniformMatrix4fv(mx, false, mxArr);
上节课定义顶点旋转矩阵使用的着色器语言,下面的案例是先在Javascript程序中使用类型数组Float32Array()
创建旋转矩阵的数据,然后使用WebGL APIgl.uniformMatrix4fv()
把数据传递给着色器。WebGL中给着色器中不同关键字声明的不同类型变量传递数据, 要使用不同的WebGL API,uniform
关键字声明的mat4
类型变量使用WebGL APIgl.uniformMatrix4fv()
,uniform
关键字声明的mat2
类型变量使用WebGL APIuniformMatrix2fv()
,uniform
关键字声明的一个浮点数使用gl.uniform1f()
传递, uniform
关键字声明的vec4
类型变量和mat4
一样使用uniform4fv(变量地址名,new Float32Array([a,b,c,d]))
传递,也可以使用uniform4f(变量地址名,a,b,c,d)
传递,attribute
关键字声明的变量使用WebGL APIgl.vertexAttribPointer()
传递。
绘制函数draw()
该绘制函数draw()
可以使用第requestAnimationFrame(draw);
代码实现draw()函数的循环调用,因为要实现立方体绕y轴旋转,所以要在draw
函数中更新my
旋转矩阵的数据,同时利用WebGL APIgl.uniformMatrix4fv()
把新的矩阵数据传递给着色器矩阵变量my, 在函数重复调用gl.drawArrays(gl.TRIANGLES,0,36);
不停绘制旋转后的顶点数据,所有需要更新的数据都要写在draw
函数中,不需要反复执行的代码写在draw
函数外,比如mx
旋转矩阵只需要执行传入一次不在改变。
/**
* 定义绘制函数draw(),定时更新旋转矩阵数据,并调用WebGL绘制API
***/
var angle = Math.PI/4;//起始角度
function draw() {
// gl.clear(gl.COLOR_BUFFER_BIT);//清空画布上一帧图像
/**
* 立方体绕y轴旋转
***/
angle += 0.01;//每次渲染角度递增,每次渲染不同的角度
var sin = Math.sin(angle);//旋转角度正弦值
var cos = Math.cos(angle);//旋转角度余弦值
var myArr = new Float32Array([cos,0,-sin,0, 0,1,0,0, sin,0,cos,0, 0,0,0,1]);
gl.uniformMatrix4fv(my, false, myArr);
requestAnimationFrame(draw);
/**执行绘制命令**/
gl.drawArrays(gl.TRIANGLES,0,36);
}
draw();