今天讲一个图片碎片化的效果:

canvas&css polygon实现图片碎片化 gif canvas&css polygon实现图片碎片化

这个效果主要原理就是随机产生一些点,然后让这些点组成不重叠,不重复的三角形,然后对图像进行剪裁,拼凑成完整的图像。其中的关键难点就是如何将随机的点变成不重复的最小三角形,这里用到的就是三角剖分技术。

三角剖分

三角剖分就是将一些随机的点变成不重叠的小三角形,并且最后形成的三角形有“空圆特性”,就是任一三角形的外界圆内都没有其他的点。这个"空圆特性"也是我们实现代码的主要依据。现在我们就来看看代码是如何去实现三角剖分的:

首先我们假设我们已经随机产生了4个点,第一步,我们要这些点的最大,最小边界,然后制作一个很大足以包裹住所有点的一个三角形:

background Layer 1 四个点的边界区域

很显然,现在所有的点都在三角形里面,那么当然也肯定在三角形的外界圆中。刚才我们上面讲到了一个很重要的特性:"空圆性",也就是任一三角形内不能有其他的点,也就意味着接下来我们要逐个比较三角形的外界圆和点的关系了,我们这里定下一个规则,我们从左往有遍历这些随机点。

现在还有一个很重要的问题,就是如何求三角形的外界圆,三角形的外界圆圆心其实就是三条边的中线的交点,外界圆半径就是圆心到点的距离。求外界圆的具体计算方法如下:

background Layer 1 A(x0,y0) B(x1,y1) C(x2,y2) O AB的中点坐标为((x0+x1)/2,(y0+y1)/2) AB的斜率为(y0-y1)/(x0-x1),AB中垂线和AB垂直,k1*k2=-1,因此: AB中垂线的斜率为-(x0-x1)/(y0-y1) AC的中点坐标为((x0+x2)/2,(y0+y2)/2) AC的斜率为(y0-y2)/(x0-x2),AC中垂线和AC垂直,k1*k2=-1,因此: AC中垂线的斜率为-(x0-x2)/(y0-y2) y=k1*x+b1 y=k2*x+b2 设交点为(x,y) k2*x+b2=k1*x+b1 (k2-k1)*x=b1-b2 y10=k1*x10+b1 AB中点(x10,y10) b1=y10-k1*x10 y20=k2*x20+b2 AC中点(x20,y20) b2=y20-k2*x20 求出了x,将y=k1*x+b1或y=k2*x+b2带入就可以求入y

现在我们来看第一个点,第一个点在外接圆内,违背了“空圆性”,因此这个三角形肯定是不行的,我们利用这个点和外接圆的三个点形成新的三个三角形。

background Layer 1 第一个点 在圆内,和外接圆三个点 组成新的三角形 该圆可以丢弃了

现在我们来看这三个外接圆和第二个点的关系:第二个点在圆1的外面,但是和圆1的水平距离并没有大于圆1的半径,因此以后的点还可能在圆1内部,因此圆1保留。

第二个点在圆2的外面,同时水平距离没有大过圆2半径,因此保留。第二个点在圆3内部,因此圆3要拆分。

现在来看第三个点和这些外接圆的关系:第三个点在圆1的外面,且和圆1的水平距离大于圆1的半径,因此圆1是一个合格的圆,因为它之后的点肯定在第三个点的右侧(从左往右遍历点)。

第三个点在圆2外侧,但是水平差没有大于圆2半径,保留。同理,圆3也保留。

第三个点在圆4和圆5的内部,因此圆4和圆5都要拆分,但是注意,因为圆4和圆5的共用了一边,拆分的时候要去掉这个重合的边。

现在来看一下第四个点和这些外接圆的关系:第四个点在圆2外部,但是和圆2圆心的水平差没有大于圆2半径,保留。

第四个点在圆3外部,并且和圆3圆心水平距离大于圆3半径,合格的圆。同理可知,圆4保留,圆5合格。

第四个点在圆6,7内部,因此圆6,7要拆分,注意圆6,7公用一条边,拆分要去掉重复的边。

因为第四个点是最后一个点,拆分完之后就完成了,最后我们对合格的圆和仍然存在的圆进行遍历,去掉那些辅助的圆,最后留下的那些圆所对应的点就是最后的结果。

background Layer 1

canvas&css polygon分割图片

上面讲解了三角分割的主要原理,分割成了三角形,现在就是对在这些三角形上贴图片了,在canvas中,主要是用clip进行分割贴图的,主要代码如下:

css中主要用clip:polygon进行分割的。

碎片的过度动画则是用TweenMax实现的,它可以很方便的对多个片段进行动画。其中有一个比较有意思的就是让图片从上下左右那个方向过来的判断,主要思路就是根据碎片离出发点的距离来设置不同的延迟,越远的越晚出现。

同时注意在canvas中利用will-change:transform或者perspective:500px来开启GPU加速。

最后放一个图片碎片化的效果,主要思路就是先三角分割,然后在canvas上绘制的时候吸取碎片中间点的色值,然后绘制就好了。

其他文章

0
我要评论

评论

返回
×

我要评论

回复:

昵称:(昵称不超过20个字)

图片:

提交
还可以输入500个字