优化 JavaScript/React Native 中 svg 路径之间的平滑补间

cad*_*lac 8 javascript performance animation svg react-native

我目前正在将一个应用程序移植到 React Native,该应用程序将用户输入捕获为笔画,并将其动画到正确的位置以匹配 svg(如下图)。在网络中,我使用多个平滑库和 pixij 的组合来实现完美平滑的过渡,没有任何瑕疵。

使用 React Native 和 reanimated,我只能使用手动编写的函数来处理两个路径之间的插值。目前我正在做的是:

  1. 将目标 svg 转换为固定数量N的点数
  2. 平滑捕获的输入并将其转换为一系列N
  3. 循环每个坐标并在这两点之间插入值(线性插值)
  4. 通过 Catmull-Rom 函数运行结果点数组
  5. 渲染生成的 SVG 曲线

1 和 2 我可以在动画之前进行缓存,但步骤 3、4 和 5 需要在每次渲染时进行。

不幸的是,使用此方法时,在丢弃某些帧之前,我将值限制为 300 左右N作为最大点数。我还在动画结尾处看到一些我不知道如何修复的伪影。

这已经足够了,但考虑到在网络中我可以为数万个点设置动画而不丢帧,我觉得我在这里缺少一个关键的性能优化。例如,有没有办法将步骤 3 和 4 结合起来?有比 Catmull-Rom 性能更高的算法吗?

有没有更好的方法来仅使用纯 JavaScript(或者如果可能的话,使用 Swift)实现两个向量路径之间的平滑过渡?

我还能做些什么来消除最后一张照片中的伪影吗?我不确定这些在技术上被称为什么,所以我很难研究 - catmull-rom 样条线删除了其中的大部分,但我仍然在动画的尾部看到一些。

动画结束/开始状态:

动画开始状态

动画中间状态:

动画中间状态

动画开始/结束状态(带工件):

带有工件的动画结束状态

Han*_*esH 1

您可能想看看Flubber.js

另外为什么不放弃 catmull-rom 来使用简单的线性部分(可能足够详细,有 1000 多个点)

如果两者都没有帮助,或者您想要尽可能快,您可能需要利用 GPU 的能力来执行令人尴尬的并行工作流程,例如 N 大小的数组之间的插值。


编辑:

还可以考虑使用skia渲染器,它已经利用了GPU并支持完全适合您的用例的东西

import {Canvas, Path, Skia, interpolatePath} from "@shopify/react-native-skia";

//obv. you need to modify this to use your arrays 
const path1 = new Path();
path1.moveTo(0, 0);
path1.lineTo(100, 0);
const path2 = new Path();
path2.moveTo(0, 0);
path2.lineTo(0, 100);

//you have to do this dynamically (maybe using skia animations)
let animationProgress = 0.5; 

//magic already implemented for you
let path = interpolatePath(animationProgress, [0, 1], [path1, path2]);

const PathDemo = () => {
  return (
    <Canvas style={{ flex: 1 }}>
      <Path
        path={path}
        color="lightblue"
      />
    </Canvas>
  );
};
Run Code Online (Sandbox Code Playgroud)