动效作为产品与用户沟通的广泛形式,经历了从静态到动态,从不透明到透明,从单一到多元的进化。本文依托于业务需求,充分对比了常用的Web动效格式及其区别,调研优秀的特效播放方案,参考其原理经过改造并完成升级功能。
礼物特效是直播间及语聊房中很常见的增值玩法,用户对玩法的多样性需求也在不断地增加。近期业务上期望能够参考抖音实现定制跑车特效。用户通过个性化的选配,最终送出形式各样的礼物,从而满足用户独一无二及炫耀的心理。
抖音效果:
看到这个效果的第一反应是通过游戏引擎实现。
方案一:制作3D模型,更换每个部件,类似换装。但有几个问题:
方案二:枚举合成组合好的视频,提前生成。同时这样也是有问题的:
由此,需要我们沉下心,从头开始寻找解决方案:
Web动效有很多种,不同文件格式之间各有利弊,从业务需求角度出发选取相对较优方案是我们的目的。常见的动效格式有gif、apng、webp、lottie、svga、mp4等[3]。
Gif(GraphicsInterchangeFormat)是在1987年由CompuServe为了填补跨平台图像格式的空白发展起来的位图动画格式,具有GIF87a和GIF89a两个版本。
优点:
缺点:
使用:
但MP4有个致命的缺点:天生不支持透明度。那么,有没有什么方法可以使其带透明度播放吗?答案是肯定的。
我们知道,可以将MP4看做是数帧图片快速连续播放而成的视频,而图片中的每一个像素,均为RGBA形式(如(255,255,255,255)),RGB为红绿蓝三基色,A就是透明通道Alpha,它是一个8位灰度通道,由256级灰度来记录图像中的透明信息。
原生的MP4相当于A通道所有值都是255,均为不透明。而设计师可以通过某种方式告诉我们每一帧每一像素的透明度,Web开发者对其颜色进行透明度替换,再呈现给用户,便解决了MP4不支持透明度的问题。设计如何将每一帧每一像素告诉我们,最简单且高效的方式,便是利用AE导出同步的Alpha视频,而为了能够在Web端同步播放,设计师可以将两块视频进行拼接,合2为1。这样,一个视频中便包含了完整的RGB和Alpha信息。
Web开发者拿到MP4文件播放时,从一侧提取像素点RGB信息,从另一侧提取R通道(G/B通道亦可)信息作为对应像素点的Alpha通道值,融合为新的RGBA值,根据RGBA值将每个像素点渲染到屏幕上,实现半透明效果。
那么,Web开发者如何获取视频每帧并对每帧进行解析及使用新的RGBA值进行屏幕重新渲染呢?
能够融入自定义属性核心原理都是引入“遮罩”素材,利用遮罩与属性图片进行Porter-Duff操作,就能得到需要的形状,再将结果贴到视频对应坐标位置,就能实现最后的融合效果。
既然可以融合固定的内容,那么动态的内容(拆成多个视频部件)也是可以实现的,只需同时解码多个视频,一个基座视频,多个部件视频,每一帧绘制时取部件视频的部分贴到对应坐标位置即可。参考以上两个优秀案例的实现原理,先完成AlphaVideoPlayerJs的基础功能,再此基础上完成多视频的叠加融合。
代码主要由video与render两部分组成。
//vertexshaderprecisionlowpfloat;uniformsampler2Du_Sampler;varyingvec2v_Video_Texture_Position;varyingvec2v_Alpha_Video_Texture_Position;voidmain(){gl_FragColor=vec4(texture2D(u_Sampler,v_Video_Texture_Position).rgb,texture2D(u_Sampler,v_Alpha_Video_Texture_Position).r);}//fragmentshaderattributevec4a_Position;attributevec2a_Video_Texture_Position;attributevec2a_Alpha_Video_Texture_Position;varyingvec2v_Video_Texture_Position;varyingvec2v_Alpha_Video_Texture_Position;voidmain(){gl_Position=a_Position;v_Video_Texture_Position=a_Video_Texture_Position;v_Alpha_Video_Texture_Position=a_Alpha_Video_Texture_Position;}既然使用Canvas2D占用CPU过高,那么可以试试性能更好的WebGL。WebGL(WebGraphicsLibrary)基于OpenGL,允许浏览器访问使用计算机上的GPU进行图形化渲染,为canvas绘制提供硬件3D加速。经过测试,动效播放时CPU使用率显著降低。
遵循最小化配置、开箱即用的原则,默认只需配置渲染DOM和视频地址即可使用。
多纹理渲染原理:根据要渲染的video的个数,动态模板生成片元着色器代码一个video对应一个uniform,再将多个uniform取到的颜色依次叠加混合,赋值给gl_FragColor
uniformsampler2Du_sampler0;uniformsampler2Du_sampler1;uniformsampler2Du_sampler2;voidmain(void){//u_sampler0取样器对0号纹理进行采样//识别每一帧需要透明的区域,并设置为透明vec4color0=vec4(texture2D(u_sampler0,v_texCoord).rgb,texture2D(u_sampler0,v_texCoord+vec2(0.5,0)).r);//u_sampler1取样器对1号纹理进行采样vec4color1=vec4(texture2D(u_sampler1,v_texCoord).rgb,texture2D(u_sampler1,v_texCoord+vec2(0.5,0)).r);//u_sampler2取样器对2号纹理进行采样vec4color2=vec4(texture2D(u_sampler2,v_texCoord).rgb,texture2D(u_sampler2,v_texCoord+vec2(0.5,0)).r);floatblendFactor=color1.a;//使用mix函数混合两个颜色得到新的颜色。3个参数分别是颜色1,颜色2,以及混合比例,依次混合多个纹理,得到最终要渲染的颜色。//使用当前纹理的上一层问题alpha值作为混合比例vec4finalColor=mix(color0,color1,blendFactor);floatblendFactor1=color2.a;vec4finalColor1=mix(finalColor,color2,blendFactor1);gl_FragColor=finalColor1;}最终效果:
单部件视频:
4个单独的mp4播放器播放CPU占用大约是11%-13%
一个多纹理视频播放器播放4个mp4视频,CPU占用大约是7%-9%,性能提升大约是30%