在组合变换的基础上,实现动画差不多是顺利成章的事情,我们只需要利用浏览器提供的 requestAnimationFrame() 不断进行变换就可以实现动画,它的实质就是变换矩阵的不断相乘 。
这里要注意:因为使用requestAnimationFrame的本质实际上是把回调函数交给浏览器来执行,具体什么时候执行,浏览器来决定,当系统负载较大,FPS比较低,可能导致requestAnimationFrame执行偏晚,导致每一帧绘制的时间间隔较长,动画不平滑流畅,所以我们把旋转角度与时间关系起来成比例关系,请看如下代码
// 顶点着色器程序
var VSHADER_SOURCE =
`attribute vec4 a_Position;
uniform mat4 u_xformMatrix;
void main() {
gl_Position = u_xformMatrix*a_Position;
}`;
// 片元着色器程序
var FSHADER_SOURCE =
`void main() {
gl_FragColor = vec4(1, 0, 0, 1);
}`;
const main = () => {
//获取绘制dom
const canvas = document.getElementById('webgl');
//获取canvas上下文
const gl = canvas.getContext('webgl');
//初始化着色器
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
return console.log('Failed to initialize shaders.')
}
const initVertexBuffers = (gl) => {
//类型化数组设置顶点坐标
const vertices = new Float32Array([0, 0.5, -0.5, -0.5, 0.5, -0.5]);
const n = 3;//点的个数
//创建缓冲区对象
const vertexBuffer = gl.createBuffer();
if (!vertexBuffer) {
console.log('Failed to create the buffer object');
return -1
}
//将缓冲区对象绑定到目标
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
//向缓冲区对象中写入数据
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
const a_Position = gl.getAttribLocation(gl.program, 'a_Position');
//将缓冲区对象分配给a_Position变量
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
//链接a_Position变量与分配给它的缓冲区对象
gl.enableVertexAttribArray(a_Position);
return n
}
const ANGLE_STEP = 45.0;
let g_last = Date.now();
let currentAngle = 0.0;
const xformMatrix = new Matrix4();
const u_xformMatrix = gl.getUniformLocation(gl.program, 'u_xformMatrix')
//旋转函数
const draw = (angle, xformMatrix, u_xformMatrix) => {
xformMatrix.setRotate(angle, 0, 0, 1);
// xformMatrix.translate(0.35, 0, 0)
gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix.elements)
//清空canvas
gl.clear(gl.COLOR_BUFFER_BIT);
//绘制一个点
gl.drawArrays(gl.TRIANGLES, 0, 3);
}
//根据时间间隔计算旋转角度
const animate = (angle) => {
console.log('angle',angle)
//计算距离上次调用经过多长时间
const now = Date.now();
const elapsed = now - g_last;
g_last = now;
return (angle + (ANGLE_STEP * elapsed) / 1000.0) % 360
}
//动画函数
const tick = () => {
currentAngle = animate(currentAngle);
draw(currentAngle, xformMatrix, u_xformMatrix);
requestAnimationFrame(tick)
}
tick()
const n = initVertexBuffers(gl);
if (n < 0) {
console.error('n<0')
return
}
//设置canvas的背景色
gl.clearColor(0.0, 0.0, 0.0, 1.0);
}
main()