如何在贝塞尔曲线形状上正确插入动画帧

问题描述 投票:0回答:0

我试图将动画更改为根据贝塞尔曲线具有平滑的缓入/缓出。然而,结果并不尽如人意。非常感谢您的反馈和想法如何做得更好。

以显示动画(从 GIF 中提取)的一系列 .png 文件形式提供的数据。 这包含在 github 的 data_src 目录中。 (请参阅下面的链接)。

用户界面有2个窗口:

  1. 贝塞尔曲线缓入缓出形状。
  2. 左子窗口显示原始动画帧。右子窗口显示修改后的动画帧。有一个滑块可以控制时间轴、播放、暂停和将贝塞尔曲线部署到动画帧(右侧的子窗口将相应改变)。见图1

单击部署按钮时,.png 文件序列将根据贝塞尔曲线形状调整形状 - 即先缓入后缓出。实时播放动画会显示 Ease-in,Ease-out 动作。

GitHub 链接:

https://github.com/mrglobal/bezier_easeinout。 使用的IDE是QT Creator。用 C++ 编写的代码

为简单起见,我在 bezier_curve.cpp 中提供了一些硬编码的 Ease-In 和 Ease-Out 模型。该代码不包括带有控制点的用户界面,以允许用户动态创建贝塞尔曲线。有关硬编码的 c0、p0、p1、c1 值,请参阅 Bezier_Curve::deploy_bezier_curve。

代码的主体展示了我如何遵循贝塞尔曲线形状,试图在“实时”播放时将原始动画帧序列转换为缓入/缓出序列。

更详细的代码排列结构说明请看mainwindow.cpp。我已经非常广泛地添加了评论 - 希望它们有用。注意我没有优化代码以便于理解。

贝塞尔曲线的解释如下图所示。基本上我叠加了 N 帧的动画序列(在本例中为 142 帧)。示例仅显示 4 个点以供说明。在每一点,将贝塞尔曲线的切线与下一点的切线进行比较。本质上它是沿着贝塞尔曲线上的点的切线的 dy/dx。请注意,点 0 处的第一个 dy/dx 是贝塞尔曲线上该点与 2 个端点之间的直线减去 begin angle 的切线。见下图[2]

[2] https://i.stack.imgur.com/FYiHU.png

然后将每个点的dy/dx值通过以下公式转换为帧数:

   (dy/dx in degrees)/(begin angle in degrees)

分母的原因是开始角度是偏离标准(线性线)的帧数为 0 的位置。因此(至少对我而言)将其作为分母将 dy/dx 转换为数字是有意义的框架偏离规范。

转换后的值存储为: /* * 跳度指数 = (19, -4, -3, 0.... * 其中每个数字: * +N : 跳转到第 N 帧 * 例如+19 :跳转到第 19 帧 * -N : 通过将相同的帧内容扩展 N 次来延迟前向序列 * 例如-4 扩展同一帧 4 次 * 0 : 保持顺序 * */

下一步是遍历此列表并从第一帧开始重新插入动画帧。按照示例,这将转换为动画帧序列:

+19: 帧 0 的帧图像位于帧索引 19

-4 第 1、2、3、4 帧的帧图像位于帧索引 20

-3 第 5、6、7 帧的帧图像位于帧索引 21

0 第 8 帧具有帧图像帧索引 22

结果是有问题的,因为即使在简单的缓入贝塞尔曲线上,它似乎也没有遵循平滑的过渡。此外,当存在缓入和缓出贝塞尔曲线时,这种从左到右帧图像移动的方法会超出跑道。

这是最小代码:

车架等级:

#include <QObject>
#include <QWidget>
#include <QImage>

#define NUMBER_FRAMES 142
#define INTER_FRAME_INTERVAL_MSECS 35

class Frame : public QWidget
{
    Q_OBJECT

public:
    explicit Frame(QWidget *parent = nullptr);
    int index;
    int src_index;
    int delta;
    bool overwritten;
    QString filename;
    QImage *image;

signals:

protected:
    void paintEvent(QPaintEvent *event);
};

  
animation bezier motion easeinout
© www.soinside.com 2019 - 2024. All rights reserved.