h5动画相关


动画原理

这里把动画方案的实现原理分为三种。

  • 第一种是纯面向过程的动画记录方式,目前市面上主流的有Airbnb 的Lottie和腾讯最近开源的PAG,原理是通过记录动画设计师制作动画的每个元素,还有每个元素的运动过程,然后开发者再还原这些元素的运动。这个方案的优点是文件体积小,能实现大部分基础特效和变换下的动画。缺点是不支持比较复杂的特效(如3D效果等),播放性能也比较差,因为记录过程就必然有一个还原动画的计算过程,在渲染的同时还需要计算每个元素的变化过程,对比其他方案就多了一项计算的性能损耗。
  • 第二种是半面向过程半结果的动画记录方式 目前市面上主流的方案有YY的SVGA和Y2A方案,原理是记录动画设计师制作动画时用到的每一个元素,然后记录元素在每一帧的特征(形状,大小,位置,alpha等)。SVGA的优点是能支持更复杂的动画,同时播放性能也比第一种方案好许多。缺点是体积会大一些,同时也不支持复杂的特效(如3D效果等)。为什么第二种方案相比第一种方案性能上比较好,也能够支持更复杂的动画呢,这是牺牲了一部分文件体积,从而减少了计算这一环节的因素。SVGA的文件经过zlib压缩和base64编码后,压缩率能达到85%~90%
  • 第三种是记录结果方式,目前主要有PNG序列图和带透明通道的MP4方案。原理是记录每一帧每个像素点的像素值来渲染,优点是所见即所得,充分解放设计师的思想,能够支持所有设计师能设计出来的动画,包括3D动效等

总结:

  • 第一种方案 支持一般的动效,比如UI动画,场景切换动效和一些进场、得分等动效。
  • 第二种方案能支持第一种能支持的所有动效,且能够支持更复杂的动效,例如复杂的礼物动效,酷炫的坐骑动画等。
  • 第三种方案能支持所有的动效,只要设计师能设计出来的动效都支持。在体积上,也是依次递增的,第一种方案体积最小。但是在性能上刚好反过来,第一种方案性能最差,CPU和GPU占用较高。

Lottie

Lottie是Airbnb开源的一个支持 Android、iOS 以及 ReactNative,利用json文件的方式快速实现动画效果的库。

设计师可以使用 Adobe After Effects 设计出漂亮的动画之后,使用 Lottic 提供的 Bodymovin 插件将设计好的动画导出成 JSON 格式,就可以直接运用在 iOSAndroidWebReact Native之上,无需其他额外操作。

Lottie-web

Lottie-web是爱彼迎提供的针对html的lottie播放器版本

usage

npm i lottie-web --save
import lottie from 'lottie-web/build/player/lottie_light_canvas';
import JSONL from './ani/dataModal.json';

const modalRef = useRef();

modalRef.current = lottie.loadAnimation({
  container: modalRef?.current,
  renderer: 'canvas',
  animationData: JSONL,
  autoplay: true,
  loop: false,
});
<div className="rock-lottie" ref={modalRef} />

lottie的json文件

{
    "v": "5.6.10", // 使用bodymovie插件的版本
    "fr": 32, // 帧速率
    "ip": 0, // 合成开始时间
    "op": 64, // 合成持续时间
    "w": 750, // 合成宽度
    "h": 1334, // 合成高度
    "nm": "合成 1", // 合成名
    "ddd": 0, // 是否3d图层
    "assets": [ // 使用的资源
        {
            "id": "image_0", // 使用的资源id
            "w": 750, // 当前图片资源的宽
            "h": 1334, // 当前图片资源的高
            "u": "images/", // 当前图片导出后在使用bodymovie导出后的文件夹
            "p": "img_0.jpg", // 当前图片资源路径
            "e": 0 // e=0 后将拼接u+p作为图片路径,e=1 不使用u,直接使用p的路径。
        }
   ],
   "layers": [ // 图层
    {
            "ddd": 0, // 是否是3d图层
            "ind": 1, // 当前图层所在的索引
            "ty": 2, // 2代表图片图层
            "nm": "img_0.jpg", // 源名称
            "cl": "jpg", // 后缀
            "refId": "image_0", // 使用assets中的id
            "sr": 1, // 图层 =>时间=>时间伸缩
            "ks": { // 图层 => 变换
                        "o": { // 透明度
                    "a": 1, // 是否是关键帧
                    "k": [ // 如果是关键帧时是数组
                        { // 每一个关键帧位置的配置信息
                            "i": { "x": [0.833], "y": [0.833] }, // 当前贝塞尔曲线的入值,这个是在lottie中写死的值
                            "o": { "x": [0.167], "y": [0.167] }, // 当前贝塞尔曲线的出值,这个是在lottie中写死的值
                            "t": 0, // 当前关键帧开始时间 
                            "s": [60] // 开始的opacity 
                        },
                        { // 第二个关键帧的配置信息
                            "i": { "x": [0.833], "y": [0.833] },
                            "o": { "x": [0.167], "y": [0.167] },
                            "t": 25,
                            "s": [100]
                        }, // 第三个关键帧的配置信息
                        {
                            "i": { "x": [0.833], "y": [0.833] },
                            "o": { "x": [0.167], "y": [0.167] },
                            "t": 30,
                            "s": [100]
                        }, // 第四个关键帧的配置信息
                                                { "t": 50, "s": [50] }
                    ],
                    "ix": 11 // Property Index. Used for expressions。表达式标记。还没研究到这个怎么用
                },
            "r": { // 旋转
                "a": 0, // 是否是关键帧, 0代表不是关键帧
                "k": 0, // 不是关键帧时为number,旋转角度为0
                "ix": 10 // Property Index. Used for expressions。表达式标记
             }, 
             "p": { // 位置
                "a": 1, // 是关键帧
                "k": [
                       {
                            "i": { "x": 0.833, "y": 0.833 }, // 当前贝塞尔曲线的入值,这个是在lottie中写死的值
                            "o": { "x": 0.167, "y": 0.167 }, // 当前贝塞尔曲线的出值,这个是在lottie中写死的值
                            "t": 0, // 开始时间
                            "s": [-375, 675, 0], // 当前关键帧位置,横坐标-375,纵坐标675, 不是3d图层,z方向为0
                            "to": [125, 0, 0], // In Spatial Tangent. Only for spatial properties. Array of numbers. 入值 还不知道空间切线在AE中是个什么鬼
                            "ti": [-125, 0, 0] // Out Spatial Tangent. Only for spatial properties. Array of numbers. 出值 还不知道空间切线在AE中是个什么鬼
                      },
                      { 
                        "i": { "x": 0.833, "y": 0.833 },
                        "o": { "x": 0.167, "y": 0.167 },
                        "t": 25,
                        "s": [375, 675, 0],
                        "to": [0, 0, 0],
                        "ti": [0, 0, 0]
                     },
                     {
                        "i": { "x": 0.833, "y": 0.833 },
                        "o": { "x": 0.167, "y": 0.167 },
                        "t": 30,
                        "s": [375, 675, 0],
                        "to": [125.167, 0, 0]
                        "ti": [-125.167, 0, 0]
                    },
                    { "t": 50, "s": [1126, 675, 0] }
                ],
               "ix": 2 // Property Index. Used for expressions.
            },
            "a": { // 锚点
              "a": 0, // 不是关键帧
              "k": [375, 667, 0], // 锚点值
              "ix": 1 // Property Index. Used for expressions.
            }, 
            "s": { // 缩放比例
              "a": 0, // 不是关键帧
              "k": [100, 100, 100],  // // 缩放比例值
              "ix": 6 // Property Index. Used for expressions.
            } 
         },
        "ao": 0, // 是否自动跟踪
        "ip": 0, // 开始帧
        "op": 64, // 持续帧长
        "st": 0, // 开始时间
        "bm": 0 // 混合模式
         }
    ],
    "markers": []
}

然后我们可以通过修改json文件,来修改我们的lottie资源

import JSONL from './ani/dataModal.json';

JSONL.assets[9].p = 'xxxurl';
JSONL.assets[8].p = 'xxxurl';
JSONL.assets[5].p = 'xxxurl';
JSONL.assets[4].p = 'xxxurl';
JSONL.assets[7].p = 'xxxurl';
JSONL.assets[6].p = 'xxxurl';

modalRef.current = lottie.loadAnimation({
  container: modalRef?.current,
  renderer: 'canvas',
  animationData: JSONL,
  autoplay: true,
  loop: false,
});

参考


文章作者: Hello
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Hello !
 上一篇
WebGL WebGL
WebGL简介WebGL是一种JavaScript API,用于在不使用外挂程式的情况下在任何相容的网页浏览器中呈现交互式2D和3D图形[3]。WebGL完全整合到浏览器的所有网页标准中,可将影像处理和效果的GPU加速使用方式当做网页Can
2023-06-12
下一篇 
SSR SSR
SSR渲染SSR简介SSR:server side render 当前端为vue、react这种spa应用时,非常不利于SEO,各种路由的跳转也变得复杂,并且在首屏渲染时间上也花费了大量时间。在整体架构部署上,还需要利用各种web服务(如n
2023-04-12
  目录