Canvas特效之魔鬼四边形

2021-10-27 11:44:25 浏览数 (1)

像素流Peer Stream的仓库中有一个专门用于网络状态嗅探的虚幻模拟器:test/unreal.html。其中提供了3种即时视频流,分别是摄像头、屏幕录制、canvas动画,本文介绍这个canvas动画的实现原理,只有短短20行代码。

如图所示,和上一期《Shader编程之地标特效》中运行在GPU上的shader特效不同,canvas特效是运行在CPU上的,2个算法有本质区别,canvas算法的优势在于比较好理解,适合比较简单的、二维的特效。首先观察一下这个特效,它有以下特征:

  • 动画在一个圆形区域内的二维动画。
  • 若干个同心四边形(矩形框、方框)以正弦函数的规律来回旋转。
  • 边长更大的四边形质量更大,“惯性”也看上去更大,整体看来,像是中心的旋转力量带动了周围四边形的旋转。
  • 四边形的颜色是任意的不透明的饱和色,亮度适中。

首先需要一个<canvas>画板,并指定任意的宽高:

代码语言:javascript复制
<canvas id="canvas" width="500" height="500"></canvas>

接下来通过getContext函数定义它为二维画板,接着将canvas的宽和高中最小的一边作为圆形区域的直径,通过CanvasRenderingContext2D的clip方法限定圆形绘画区域,完整的代码如下:

代码语言:javascript复制
const $ = canvas.getContext("2d");
const l = Math.min(canvas.width, canvas.height) / 2;

$.strokeStyle = `hsl(${360 * Math.random()}deg 100% 50%)`;
$.lineWidth = 6;

$.beginPath();
$.arc(l, l, l, 0, Math.PI * 2);
$.clip();

(function frame(time) {
  $.clearRect(-l, -l, l * 2, l * 2);

  for (let x = 1; x <= l; x  = $.lineWidth   2) {
    $.strokeRect(-x, -x, x * 2, x * 2);
    const theta = Math.sin(x / l - time / 512) * 60;
    $.setTransform(new DOMMatrix().translate(l, l).rotate(0, 0, theta));
  }

  window.animationFrame = requestAnimationFrame(frame);
})(0);

然后我们使用CSS的hsl函数生成随机的饱和亮色,使得特效更鲜艳。在256 x 256 x 256 = 16777216种真彩色中,只有256 x 256 x 3 = 196608种饱和色,约占总数的1%,剩下的颜色都是不鲜艳的,而这1%的饱和色中又只有256 x 6 = 1536种亮色,剩下的都不够亮。所以既饱和又明亮的颜色只占总数的(256 x 6) / (256 x 256 x 256) ≈ 0.009%,在色谱上,只有一条边属于这个范围:

接下来我们要定义每一帧的函数frame(time),然后通过requestAnimationFrame来循环调用frame,并且传入当前的时刻time,我们利用这个时刻来计算当时每个四边形的旋转角度。每一帧中,先使用clearRect函数清除掉上一帧的画面,然后遍历每个四边形,矩形边框(四边形)之间保持一定的间隙,最后在正弦函数中决定这个方框的角度,角度和当前时刻和方框的边长都有关系,所以Math.sin中传入了2个变量:空间变量x(边长)和时间变量time(时刻)。最终调用strokeRect函数画出方框,就实现了魔鬼四边形特效:

0 人点赞