Heim  >  Artikel  >  Web-Frontend  >  扑面而来的碎片图片3D炸裂效果初体验_html/css_WEB-ITnose

扑面而来的碎片图片3D炸裂效果初体验_html/css_WEB-ITnose

WBOY
WBOYOriginal
2016-06-24 11:18:001357Durchsuche

 之前逛园子的时候看到 ChokCoco 的爆炸效果作品:【BOOM】一款有趣的Javascript动画效果 (大神英文有没有拼错呀←.←),觉得蛮有意思的,效果如下:

 

不过觉得这个爆炸效果还是偏软了一点,没有爆炸那种碎片飞溅的感觉,一直念念不忘想要自己做一个3D效果的爆炸动效。这两天在搞一些小动画,就顺便也把3D爆炸做了出来,动画效果:

 

实现

原理很简单,就是用很多小图片拼凑成大图片,然后让小图片按照一定规律运动形成爆炸效果。这里的爆炸效果用的是 CSS3 的 3D 变换来做的,通过 js 动态改变变换参数形成动画。实现步骤简单说说:

1、图片拼凑

这一步相对简单,用的是很多 div 标签的背景图拼凑的,设置好每个 div 标签的 position 和 background-position 就可以了。这里要注意的一点就是添加 div 标签是记得要用 innerHTML 一次性全部添加进去。虽然这里没有直接显示图片,但是这里还是 new 了一个 image,并将图片拼凑放在 load 事件中执行。效果和代码分别如下(实际效果没格子线的):

  

var img = new Image();img.src = 'img/zoro.jpg';    //160*160,or you need to change wrapper's sizeimg.onload = function () {    var x = y = 0,    div = styleCtn = '',    imgWidth = this.width,    imgHeight = this.height,    pwidth = pheight = 10,    nx = Math.floor(imgWidth / pwidth),    //x方向粒子个数    ny = Math.floor(imgHeight / pheight),    //y方向粒子个数    wrap = document.getElementById('zd-wrap');                        for (var i = 0, num = nx * ny; i < num; i++) {        x = (i % nx) * pwidth;        y = Math.floor(i / ny) * 10;    styleCtn = 'left: ' + x + 'px; top: ' + y + 'px; background-position: ' + (-x) + 'px ' + (-y) + 'px;';    div = div + '<div class="bomb" style="background-image: url(' + this.src + '); ' + styleCtn + '"></div>';    }    wrap.innerHTML = div;    //添加图片};

2、爆炸效果

这一步相对难了许多,因为都是三维的运动,分为平移和翻转两种运动会简单一点。

a)平移运动:在立体空间中的爆炸应该是这样的:

  

回到平面空间应该是这样的:

  

从上图可以总结出小块的运动方向,根据小块所处的位置运动方向是不同的,左上角向左上角飞去,右下角向右下角飞去这样。这里应该有一部分小块向屏幕飞来,还有一部分远离屏幕以突出扑面而来的感觉。编程中表现各轴运动的是 translate3d,这里注意屏幕和图片的坐标关系,屏幕的 Y 轴就是现实中的垂直方向、向下为正,Z轴就是面向用户方向。运动总结起来就是:

左上角:vx

左下角:vx 0, vz随机

右上角:vx > 0, vy

右下角:vx > 0, vy > 0, vz随机

  

这里 Y 方向没有严格对半分,有一种整体向上的感觉。加速度的话模仿需要模仿重力: vxa = 0, vya = 0.5 (模仿重力),vza可以适当加点,能加强扑面而来的感觉。

b)翻转运动

翻转效果,就是 X 轴的旋转,为了效果更加逼真需要引入 Y 轴的旋转,可以忽略 z 轴的旋转。因为粒子小块的尺寸很小,所以这里不需要严格控制旋转参数,一方面简化模型,另一方面减轻浏览器负荷。当然也不必引入旋转变量了,直接用 x、y 的坐标代入也可以得到不错的翻转效果: rotateX(xdeg) rotateY(ydeg),我这里引用了 Zachstronaut 的算法:

rotateX: Math.cos(0.1 *ys) + 'radrotateY: Math.sin(0.1 * xs) + 'rad

最后设置终止条件,可以根据 粒子小块的x、y 坐标判断是否应该让其退出动画循环。

这样就实现了动画,当然还必须要开启父对象的透视属性,大概设置透视距离 300px 左右就可以了。

后话

我使用的图片尺寸为160*160,粒子尺寸为10*10,在iOS中表现优秀,移动chrome中表现的也还不错。虽然已经调用了 GPU 加速渲染,但已经到了很多国产移动浏览器的上限了,所以不建议再增加粒子数量。性能提升也做了,但是没找到好的突破点,如果你有更好的点子,请联系我!

耗时测试:

   

可以看到瓶颈在 Painting 上,再细分的话主要是图层重组,接着看一下动画过程:

可以看到在最开始的时候出现了密密麻麻的绿框,也就是这里发生了大量的 paint flashing(重绘)。再看我们一开始拼凑背景图的方法,用的是绝对定位+ left + top,这里会导致大量的重绘。虽然你可以在最开始用一个 translate3d(0, 0, 0)来限定渲染层让绿框消失,但并不会有多大的效果,因为主要耗时的是图层合成,并不是绘制。分层是必须的,我也尝试过使用 translate 去代替 left + top,但是效果并不理想,暂时没有想到更好的办法改善渲染性能……

DOM操作方面倒是可以再改善,现在动效的代码是:

 this.nodes[i].style[this.transformProperty] = 'translate3d(' + this.xs[i] + 'px, ' + this.ys[i] + 'px, ' + this.zs[i] + 'px) rotateX(' + Math.cos(0.1 * this.ys[i]) + 'rad) rotateY(' + Math.sin(0.1 * this.xs[i]) + 'rad)';

循环中每次都会操作dom,而且在设置style上还是用属性查找的方式,那这里应该是可以改善的。一是重写style,避免查找属性。二就是重写父对象div里面的innerHTML,就像开头设置背景图一样,一次更新所有粒子块。

不过我在步进调试的时候发现,除了第一次执行时会一个一个地设置粒子块的属性,后面的动画循环中都已经被浏览器优化成整体重写了,每次更新都是全体更新的,所以上面的方法貌似也不能提升太多。真的没想到其他优化的办法了,如果你有点子,请联系我!

如何使用

源码已经放到GitHub(bomb.js)上面去了,有兴趣的同学可以fork来看看,求星星!

我已经将 js+HTML+CSS 都封装好了,设置好容器之后直接引用bomb.js就可以了,如下:

<style type="text/css">    .wrapper {        width: 160px;        margin: 100px auto 0;        position: relative;        cursor: pointer;        perspective: 200px;    }</style><div class="wrapper" id="zd-wrap"></div>        <script src="js/bomb.js" type="text/javascript" charset="utf-8"></script><script type="text/javascript">    var explore = new ParticlesTemplate(),        exploreImg = new Image(),        wrapper = document.getElementById('zd-wrap');    exploreImg.src = 'img/zoro.jpg';        exploreImg.onload = function () {        explore.init(exploreImg, wrapper);        wrapper.addEventListener('click', function () {            explore.go();        }, false);    };</script>

 

就写到这了,码字不易,随手点赞哈~~~

参考资料:

1) 【BOOM】一款有趣的Javascript动画效果

2) 前端性能优化(CSS动画篇)

3) http://www.zachstronaut.com/

 

(图片出处:小周)

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn