动画需要循环绘制并在绘制的过程中不断改变位置,由于人眼的视觉停留看起来就像动画。
之前都用 setInterval 实现循环调用函数,但这个函数有个缺点是在 inactive 的 tab 中也会被调用影响性能。所以后来又加了一个新的方法 requestAnimationFrame(func) 这个方法会在浏览器 redraw(重绘) 页面的时候调用一次。
var tick = function () {
draw();
requestAnimationFrame(tick);
};
tick();
可以这样实现循环调用 tick 函数。一般显示器刷新频率是 60fps (frame per second), 意味着 1 秒钟刷新 60 次,1秒=1000毫秒, 1000毫秒/60 约等于 16.7毫秒 , 所以 tick 函数大约每隔 16.7 毫秒会调用一次。
// vertex shader
var VERTEX_SHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'uniform mat4 u_ModelMatrix;\n' +
'void main() {\n' +
' gl_Position = u_ModelMatrix * a_Position;\n' +
'}\n';
// fragment shader
var FRAGMENT_SHADER_SOURCE =
'void main() {\n' +
' gl_FragColor = vec4(1.0,0.0,0.0,1.0);\n' +
'}\n';
var canvas = document.getElementById("canvas");
var gl = canvas.getContext('webgl');
gl.clearColor(0.0, 0.0, 0.0, 1.0);
if (!initShaders(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)) {
alert('Failed to init shaders');
}
var vertices = new Float32Array([
0.0, 0.5,
-0.5, -0.5,
0.5, -0.5
]);
initVertexBuffers(gl, vertices);
var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix');
var ANGLE_STEP = 45.0;
var currentAngle = 0.0;
var modelMatrix = new Matrix4();
var g_last = Date.now();
function animate(angle) {
var now = Date.now();
var elapsed = now - g_last;
g_last = now;
var newAngle = angle + (ANGLE_STEP * elapsed) / 1000.0;
return newAngle %= 360;
}
function draw() {
modelMatrix.setRotate(currentAngle, 0, 0, 1);
gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 3);
}
var tick = function () {
currentAngle = animate(currentAngle);
draw();
requestAnimationFrame(tick);
};
tick();
function initVertexBuffers(gl, vertices) {
var vertexBuffer = gl.createBuffer();
if (!vertexBuffer) {
console.log('Failed to create buffer object');
return -1;
}
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(a_Position);
}
animate 函数的意思 1 秒钟大约旋转 45 度,tick 中调用了 animate , animate 也是约 16.7 毫秒调用一次