# 动画

实现一个动画也是比较简单的,就是不断擦除和重新绘制图形,并且在每次重新绘制的时候进行改变其角度就实现了动画。

我们还是用之前的三角形进行实现一个旋转三角形,在一定的时间去重新修改旋转角度,来实现动画效果。

在设置旋转之前,我们需要设置背景色,而不是在进行绘制之前设置背景色,记住在 webgl 中,设置好的背景色在重设之前一直有效。

实现旋转的关键代码如下:

// 旋转速度(度/秒)
var ANGLE_STEP = 45.0;

function main() {

  // 设置顶点位置
  var n = initVertexBuffers(gl);

  // 设置 canvas 背景色
  gl.clearColor(0.0, 0.0, 0.0, 1.0);

  // 获取 u_ModelMatrix 变量的存储位置
  var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix');

  // 三角形的当前旋转角度
  var currentAngle = 0.0;
  // 模型矩阵 Matrix4 对象
  var modelMatrix = new Matrix4();

  // 开始绘制三角形
  var tick = function() {
    // 更新旋转角
    currentAngle = animate(currentAngle);
    // gl 绘制三角形的上下文
    // n 顶点个数
    // currentAngle 当前的旋转角度
    // modelMatrix 根据当前的旋转角度 currentAngle 计算出的旋转矩阵,存储在 matrix4 对象中
    // u_ModelMatrix 顶点着色器中同名的 uniform 变量的存储位置,modelMatrix 变量江北传递至此处
    draw(gl, n, currentAngle, modelMatrix, u_ModelMatrix);
    // 请求浏览器调用 trick
    requestAnimationFrame(tick, canvas);
  };
  tick();
}

function initVertexBuffers(gl) {
  var vertices = new Float32Array ([
    0, 0.5,   -0.5, -0.5,   0.5, -0.5
  ]);
  // 顶点的个数
  var n = 3;
  // 创建缓冲区对象等代码
  return n;
}

function draw(gl, n, currentAngle, modelMatrix, u_ModelMatrix) {
  // 设置旋转矩阵  setRotate 是计算出一个旋转矩阵,绕着 z 轴
  modelMatrix.setRotate(currentAngle, 0, 0, 1); 
  // 将旋转矩阵传输给顶点着色器
  gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);

  // 清除 canvas
  gl.clear(gl.COLOR_BUFFER_BIT);

  // 绘制三角形
  gl.drawArrays(gl.TRIANGLES, 0, n);
}

// 记录上一次调用函数的时间
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;
}

setRotate 是封装的一些方法,

avatar

avatar

# requestAnimationFrame 方法

在实现定时渲染的时候并没有没有 setInterval 函数,因为 setInterval 函数不管浏览器标签页是否被激活,他都会反复执行里面的代码。会增加浏览器的负荷。 而 settimeout 是通过设定间隔时间来不断改变图像位置,达到动画效果。但是容易出现卡顿、抖动的现象;原因是:1、settimeout任务被放入异步队列,只有当主线程任务执行完后才会执行队列中的任务,因此实际执行时间总是比设定时间要晚;2、settimeout的固定时间间隔不一定与屏幕刷新时间相同,会引起丢帧。 requestAnimation 方法只有当标签页处于激活状态的时候才会生效,requestAnimationFrame 是新引入的方法;他主要作用是请求浏览器在将来某时刻回调函数 func 以完成重绘,我们应道在回调函数最后再次发起该请求。优势:由系统决定回调函数的执行时机。60Hz的刷新频率,那么每次刷新的间隔中会执行一次回调函数,不会引起丢帧,不会卡顿。你无法指定重复调用的间隔,回调函数会在浏览器需要网页的某个元素(第二个参数)重绘时被调用,此外还需要注意,在浏览器成功地调用了一次回调函数后,想要再次调用它,就必须要再次发送请求,因为前一次请求已经结束。

如果想要取消其你去,需要使用 cancelAnimationFrame() 函数:

cancelAnimationFrame(requestId) 取消由 requestAnimationFrame() 发起的请求,参数 requestId 为指定 requestAnimationFrame() 的返回值;

评 论:

更新: 11/21/2020, 7:00:56 PM