接近年底,工作繁多,缺失精力,所以停更了一段时间。但正是因为投入到工作当中,去解决棘手的问题,反而可以学习到很多新东西。今天我就来分享一下我的项目碰壁经历与总结。热腾腾、新鲜出炉的一线干货~
一、案例背景:为什么弃Lottie投SVGA
耍家任职于一家电商产品公司。双十一大促近在眼前,我们想通过大量的动效来营造平台的活动氛围。
因为近些年Lottie的风行,前端动效落地的成本比以前低了许多,不论是动画视觉效果、前端事件绑定、动效文件大小控制等等方面,Lottie让UI设计师在动效上的发挥空间得到了进一步的扩展。我们团队之前实施动效落地,也是一直采用的Lottie方案。(我之前也总结过Lottie的一些入门事项,可移步《了解图标规范,用Lottie动画让图标落地》)
WEEX唯客交易所是全球交易深度最好的合约交易所之一,位居CMC交易所流动性排名前五,订单厚度、价差领先同行,微秒级撮合,零滑点、零插针,最大程度降低交易成本及流动性风险,让用户面对极端行情也能丝滑成交。
但这次想达到的动效效果和之前的不太相同。这一次因为关系到双十一大促活动,我们想让动效风格更加夸张、惊喜。导致我们在运用Lottie的过程中,遇到了诸多问题。
后来经过各方面的请教与调研,这次我们准备转战SVGA方案。
网络上关于SVGA的资料不少,但大多数不涉及到真实项目场景的细节还原。所以我准备分享实例,好好讲一讲我为什么最终选择SVGA,以及如何执行、如何解决在这个过程中遇到的问题的。
这都是我本人一步一个坑踩出来的经验!希望能够帮助到你。
二、辛路历程
这次我们在Lottie上遭遇碰壁,原因是因为Lottie矢量动画不支持部分AE直出的样式效果,导致我们必须考虑以序列帧的方式去实现动画。
我们在AE中制作好的成果,导出json后在本地解析预览,效果不尽人意。到各端真机上演示还会再损失掉更多的样式效果。(原因是因为Lottie在不同环境中所支持的AE参数有所差异)
以津贴红包动效为例。为了给用户带来红包的惊喜、喜庆氛围,前期我构思的动效是希望尽量带有冲击感。拟3D的效果可以让红包的出现看上去更加真实,并且在红包飞出过程中使用了发光效果。
WEEX交易所宣布将于今夏上线其全球生态激励通证WEEX Token(WXT)。WXT被设计为WEEX交易所生态系统的基石,作为动态激励机制,主要用于激励WEEX交易平台社区的合作伙伴、贡献者、先驱和活跃成员。
WXT仅开放代理、渠道等合作伙伴折扣认购,未来零售投资者可通过新用户注册、交易挖矿、参与平台活动等方式获得WXT奖励。
前期我们为了避免走进「序列帧动画」的胡同,基于我们团队在Lottie方面所具备的经验,我们希望尽量通过Lottie所支持的AE属性来实现矢量动画,这样在文件大小、性能上都能够得到把控。
例如,我们知道Lottie是不支持AE效果器所直接填加的效果的。于是对于发光效果,我们并没有直接采用「效果-发光」去实现,而是通过「高斯模糊+内发光+投影」的方式,从视觉上去模拟发光。也期许这样简单的图层样式,能够被Lottie解析。
但通过Bodymovin导出json后进行本地预览,出现了这样的状况:内发光、投影效果和高斯模糊都丢失了。效果非常生硬?
甚至到了真机演示上,3D效果竟然也丢失了。完全没法投入落地使用。
为了兼容所有的样式效果,我们最终只好将动效输出为序列帧,通过Lottie去一帧一帧播放(还是踏上了这条路…)。最终这样的方式导致Lottie输出后,包内所包含的img位图文件总量达到了数兆之多…
为了找到一个不管从视觉效果还是文件大小上都能主动把控的技术方案。于是我盯上了SVGA。
三、SVGA初体验
在此我就不再做过多的SVGA背景说明了,网上一查一大堆。我盯上SVGA的原因是因为,许多直播礼物的浮夸动效都是用序列帧+svga方案落地的,应该符合我们这次的项目要求。
通过最初的探索发现,SVGA和Lottie其实很类似。你可以直接制作矢量动画输出svga文件,当然,SVGA也有它所不支持的AE属性。你也可以通过序列帧去输出svga文件,这一点和Lottie就有所差异了。
熟悉Lottie的朋友应该知道,当动效中包含位图元素时,Lottie会生成两个文件:一个json代码文件+一个img文件夹,这也是为什么我之前用Lottie去做序列帧时,整个文件包的大小达到了几兆之多的原因,大部分都是因为一张一张的图片堆积起来的。
而通过SVGA,只会生成一个svga后缀文件,代码和位图元素都被集成在了一起。
第一次接触SVGA的我,掉进了惯性思维的陷阱。无脑地以为SVGA就是专门为做序列帧动画而诞生的。所以直接上手把整个动画合成都导出成了序列帧动画。最后输出的文件依然超超超级大…
一定是我哪里出了什么问题…于是我开始了漫漫探索优化的道路。
四、走起来了!走起来了!
虽然无可避免地走上了「序列帧动画」这条路,但为了优化动画文件大小,我们开始思考,如何尽可能地减少序列帧的帧数。让序列帧动画尽量少,让矢量动画尽量多。
最终我们决定将红包动画拆分为两个部分:「红包飞出部分」+「等待开启部分」。
因为「等待开启部分」所涉及到的动效参数,都比较基础,缩放、旋转、透明度这类基础属性,是SVGA矢量动画肯定能够解析的。所以对于这一部分我们把元素全部进行了拆解,最后输出的矢量动画文件,只有几十k。
而「红包飞出部分」,我将作为本次讲解的案例,分享给大家。讲一讲我的操作与实现过程需要注意的事项。
步骤一:制作动效并导出序列帧
制作动效的部分,是属于AE使用范畴的内容了,我在此不做过多赘述。做好动效后,把合成添加至渲染序列,然后选择导出为序列帧。
步骤二:压缩序列帧文件并导入
从这一步开始,你就要做好思考如何优化svga文件大小的准备了。导入序列帧之前,务必先对所有的序列帧文件进行压缩(或者你的动效文件中有位图元素,也务必先对位图进行压缩)。元素文件大小将关乎你最终svga文件的大小。
SVGA和Lottie不一样的地方就在于,SVGA是将位图集成在svga文件当中的,而Lottie则是把json和位图分离开。Lottie可以在导出后,再对位图进行文件大小优化;而SVGA最好是在事先就对位图进行大小优化。我一般使用tinypng来压缩位图。
在项目面板中「右键-导入-文件」,选择序列帧文件夹。
步骤三:制作序列帧动画并导出
五、该如何优化svga大小
我几乎把网上流传的各种优化svga文件大小的方式都试了个遍。
最终我发现,对SVGA序列帧帧动画大小影响最关键要素始终都是位图文件的大小。任何方式的最终落脚点,都是在直接或间接地优化位图文件。
方法一:控制文件尺寸
尺寸越大文件越大,即使是alpha通道中的透明像素,也会影响位图文件的最终大小。所以控制动画素材文件的尺寸,是优化svga文件大小的方式之一。
如果动画的展示不需要全屏,尽量缩小动画区域。如果动画展示是全屏,建议尺寸可设置为680*1209,基本可以满足所有分辨率的移动设备。
这里提出一个避坑点:「控制尺寸」是指在制作动画时,就需要对画板尺寸进行控制。而不是二次导入序列帧后,再去改变合成的尺寸。在这个时候改变合成尺寸,约等于只是在改变动画的可视区域,对最后导出的svga文件并没有影响。
举个例子:序列帧的原尺寸为400px*400px,原本输出的svga动画大小为90k。在保持序列帧尺寸不变的情况下,经过我的实验,就算我在二次序列帧合成中改变合成的尺寸为1px*1px,输出的svga动画大小依旧会是90k!只是动画的可视区域变成了1px*1px。原因是因为,实际上svga文件中包含的源位图文件是一样的。只有在制作动画时,导出300px*300px的序列帧,才能够真正优化到svga文件哦!
方法二:降低帧率
相信大多数人喜欢用24fps或30fps制作动画,也就是每1秒钟的动画,将会产生24张或30张序列帧文件。
经过其他同行的验证,说14fps其实也基本可以满足动画的视觉要求。也就是说,同样为1秒的动画,只会产生14张序列帧文件。从源头上减少位图文件数量。
但我自己有做尝试,14fps对于我们项目所需要的动画来说会稍显卡顿,所以最终选择了放弃。
具体的动画要具体分析,其实也不妨可以尝试15-20fps之间的帧率,来寻找动画效果与文件大小的平衡。
方法三:手动抽帧
和降低帧率的原理一样,「手动抽帧」也是从源头上减少位图数量。
我查资料的时候发现有同行使用过「每隔一帧抽一帧」、「每隔两帧抽一帧」、「每隔三帧抽两帧」的方式,我为了保证动画的连贯性,最终还是选用的「每隔一帧抽一帧」的方式。
?这里有一个躲坑点:因为一般我们做一个动画,时长是提前明确的,抽帧之后会导致动画时长缩短(例如「每隔一帧抽一帧」会导致动画时长缩为之前的1/2)。所以为了保证动画时长不变,我们抽帧之后要手动降低帧率。
举个例子:因为「总帧数=帧率*时长」,在一个帧率为24fps的合成中,1s的动画,就会有24张序列帧文件。我们选择「每隔一帧抽一帧」的方式,保留了12张序列帧文件。在时长1s不变的前提下,我们需要用12fps帧率来重新新建一个合成导出svga文件。
方法四:降低分辨率
其实说到这里,大家也该悟到了,想控制svga的大小,其实就是在想方设法控制位图文件的总大小。
通常我做动画,都是在@2x下制作位图元素。但如果前面的方式都尝试了之后,发现你的svga文件还是过大,你还可以选择在@1x下制作素材。缺点是在高分辨率设备上的画质会有所降低。
以上所有方法都要视具体动画,具体分析,筛选最为合理的优化方式。当然你还可以探索其他各种方式来进行svga大小的优化,只要记住宗旨是:减小位图文件总大小,一定还有其他更多的方式。也欢迎交流!