之前写了谈谈文字图片像素化,主要是为了将文字和图片像素化后的坐标提取出来,而本篇所讲即为像素化后的粒子化过程。
先上一个简单的demo -> 粒子化demo,本篇的目的就是为了讲解怎样做这样的简单demo(大牛请无视);同时会介绍一些优秀的demo供大家参考。
主要思路
首先我们谈谈粒子化的主要思路。
像素化后(不知道怎样像素化,参考谈谈文字图片像素化),我们得到了所需图像或者文字的具体坐标,我们将它们形象地用一个个的粒子表示(这里用了圆形),得到的坐标即是粒子的最终位置。粒子的初始位置在哪里?粒子从初始位置到最终位置的运动又是如何?这些是我们可以自由发挥的。所以粒子化过程究其根本,就是怎样表示粒子的运动过程。
基本准备
css部分:
body {margin:0; padding:0; wdith:100%; height: 100%}
canvas {display:block; background-color:#000}
js部分:
window.canvas = document.createElement('canvas');
document.body.appendChild(window.canvas);
canvas.height = window.height = window.innerHeight;
canvas.width = window.width = window.innerWidth;
像素化过程简单描述就是将所需的文字fillText到画布上或者将图片drawImage到画布上(设置一个离屏的canvas),然后利用getImagedata这个api将像素点提取出来。值得注意的是getImagedata并不会获取背景点的像素,所以canvas的背景使用怎样的颜色并不会影响像素点的提取。
一般像素点的提取是根据某个像素点rgba的a值进行判断,a值的取值是0~255(rgba当做颜色属性赋值时a的取值是0~1),通常做法是判断a值非0或者半透(>125)。这里我也做了个简单的测试,当color值取black或者#000时,a值如下:
粒子化效果一般在黑夜最漂亮,所以背景我一般设置成黑色。如果要更带感,需要一点阴影效果。
其实很简单,调整一下透明度即可。比如这样:
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title> </title> <style type="text/css"> body {margin:0; padding:0; wdith:100%; height: 100%} canvas {display:block; background-color:#000} </style> </head> <body> <script src='http://sandbox.runjs.cn/js/sandbox/jquery/jquery-1.8.3.min.js'></script> <script src='http://hanzichi.github.io/game/Vector.js'></script> <script> // window.onload = function() { window.canvas = document.createElement('canvas'); document.body.appendChild(window.canvas); canvas.height = window.height = window.innerHeight; canvas.width = window.width = window.innerWidth; window.ctx = canvas.getContext('2d'); // } var x = 0, y = 0; setInterval(function() { ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'; ctx.fillRect(0, 0, width,height); x+=5; y+=5; ctx.beginPath(); ctx.fillStyle = 'red' ctx.arc(x, y, 5, 0, Math.PI * 2); ctx.fill(); }, 1000 / 60) </script> </body> </html>
当然用globalAlpha也是一样的。
将粒子放入运动场中,我们可以赋予它一些属性,比如速度,加速度,位移等等,而这些属性都可以用矢量来表示。
粒子运动
之前我说过,以上皆是铺垫,运动才是粒子化的关键。因为粒子最终要汇聚成一定的形状,所以运动的某一段的终点已知,那么粒子怎样能运动到对应的位置?
我们从最简单的直线运动说起。
谈谈文字图片像素化中用的demo就是直线运动 -> 像素化
如何用js描述一个直线运动?首先我们要明白在怎样的情况下物体会做直线运动?学过物理我们知道速度和加速度在一条直线时,物体做直线运动。
那么很简单,已知粒子的终点,随机粒子的起点,速度方向就确定了(起点指向终点),如果有必要,还可以设置加速度。
仅仅做直线运动或许视觉效果太差,曲线运动会不会产生更好的视觉效果?
什么情况下物体会做曲线运动?速度和加速度不在一条直线时,比如抛物运动。
先看这个demo:
demoHome(W·Axes) 我们取它的第一个过程进行分析,实际上就是一个二维的曲线运动。和抛物运动的不同之处是,加速度方向指向粒子的终点,为的是能够准确达到终点位置。W.Axes的另一个粒子demo也大同小异:
粒子化,相比于前一个demo只是改变了粒子的初始位置和初始速度,以及粒子运动顺序。
我们尝试着来完成一个demo。
前面说到,为了能使粒子能到达指定的位置,我们给了粒子一个指向指定位置的加速度,在粒子的每一帧运动中,可以将该加速度分解到x和y轴分别进行计算。比如这样:
update: function() {
var v = this.pos2.minusNew(this.now);
var angle = v.getAngle();
this.v.x = (this.v.x + this.a * Math.cos(angle) / 1000 * 60) * 0.96;
this.v.y = (this.v.y + this.a * Math.sin(angle) / 1000 * 60) * 0.96;
this.now.x += this.v.x;
this.now.y += this.v.y;
}
a表示粒子的加速度值,/1000*60表示每帧的速度增加,*0.96模拟能量损失。这样的运动的话粒子通过曲线运动就能到达指定位置。
模拟屏幕左上角到屏幕中心的曲线运动:
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title> 粒子运动 </title> <style type="text/css"> body {margin:0; padding:0; wdith:100%; height: 100%} canvas {display:block; background-color:#000} </style> </head> <body bgcolor='#000'> <script src='http://hanzichi.github.io/common/vector.js'></script> <script src='http://hanzichi.github.io/common/common.js'></script> <script> window.canvas = document.createElement('canvas'); document.body.appendChild(window.canvas); canvas.height = window.height = window.innerHeight; canvas.width = window.width = window.innerWidth; window.ctx = canvas.getContext('2d'); window.vpx = width / 2; window.vpy = height / 2; var ball = { pos2: new Vector2(width/2, height/2), now: new Vector2(0, 0), r: 5, color: getRandomColor(), v: new Vector2(10, 0), a: 10, draw: function() { ctx.clearRect(0, 0, width, height); ctx.beginPath(); ctx.fillStyle = this.color; ctx.arc(this.now.x, this.now.y, this.r, 0, Math.PI * 2); ctx.fill(); }, update: function() { var v = this.pos2.minusNew(this.now); var angle = v.getAngle(); this.v.x = (this.v.x + this.a * Math.cos(angle) / 1000 * 60) * 0.96; this.v.y = (this.v.y + this.a * Math.sin(angle) / 1000 * 60) * 0.96; this.now.x += this.v.x; this.now.y += this.v.y; } }; setInterval(function() { ball.draw(); ball.update(); }, 1000 / 60); </script> </body> </html>
当然你也可以自己设置运动函数,不过我觉得这样比较方便而已。
有时为了效果我们需要设计一个缓动,什么是缓动?就是速度越来越小的运动。
或许涉及到x和y轴同时变化的运动太过复杂,我们假设一个物体沿着x轴正方向运动,并且物体运动速度越来越小,即为缓动。
最简单的缓动如下:
update: function() {
var v = this.pos2.minusNew(this.now);
v.scale(0.05);
this.now.add(v);
}
稍微复杂点的缓动v-s图像可以设计成二次函数或者三角函数,因为某点的切线的斜率即为速度,而切线斜率越来越小即为速度越来越小。
三维和二维环境下的粒子化其实大同小异,不了解三维的话可以参考
rotate 3d基础试着实现一个球体的3d旋转demo。
关于创意
其实粒子化本身并不难,难的是创意。这里稍微介绍几个有创意的demo。
codepen上的一个demo,代码很长,其实实现思路也大同小异,就是变着花样的粒子的运动。
同样只是粒子的运动,只是多了点创意,构造了动态文字效果。
总结
文字图片粒子化其实就是粒子系统的一部分,不妨可以从最简单的一个粒子系统开始,一步步实现一个简单的粒子化demo。
觉得不尽兴,可以参考下面更多文章: