ノンリニアアニメーションはプログラムやゲーム、アニメーションなどで広く使われていますが、どのように実装すればよいのでしょうか?
非線形アニメーション上の点は、st イメージ上では非線形です。つまり、線形関数ではなく、どこでも連続した曲線です。
この曲線はシミュレートできるため、ここではベジェ曲線を使用します。
1. 基本的な紹介
ある時刻 ts において、AE/AB=BF/BC=EG/EF
平面内に点 A、B、C があり、線分 AB、CB 上にそれぞれ移動点 E、F があり、E、F とその始点 (A、B) の間の距離が、一定時間内の線分の割合が同じである 直線上には線分EF上に点Gがあり、その仕組みはEやFと同じであり、点Gの運動軌跡が形成されると考えられる曲線
これが二次ベジェ曲線です
2 番目、線形補間
OK、 G ポイントの軌道をシミュレートして曲線シミュレーションを完了する という、私たちが何をするのかについてはすでに基本を理解しています。
このタスクを完了するには、G 点の軌跡を取得する必要があり、単一チップの動きを記述する関数が必要です。
ラープ関数
平面デカルト座標系 yOx 上に 2 つの固定点 AB があり、点 E は線分 AB 上を移動する移動点です。
w=AE/AB の場合、w∈[0, 1.0]
ベクトル OE=OA+AE を取得しやすい
∵AE=waB
∴OE=OA+waB
つまり、次の構造の場合、点 E=A+w(BA)=A-wA+wB=(1-w)A+wB
f(A, B, w)=(1-w)A+wB という関数があります。
この関数は、線分 AB 上の移動点 E の 1 秒以内の移動を記述します (w は時間、w∈[0, 1.0])。
この関数は線形補間と呼ばれ、lerp(A, B, t) と表されます。
第三に、G 点の軌道を見つけます。
線形補間点の運動状態を記述するユニバーサル関数が基本的に完成しました。次に、それを使用して G 点の運動軌跡を完成させます。
E=lerp(A, B, t) 、F=lerp(B ,C, t)
t は 0 ~ 1 秒の間でモーションを記述する時間であり、各線形補間点の w (重み重み、AE/AB=BF/BC=EG/EF) とみなすこともできるため、モーションの等価性を保証します。各線分挿入点について ----t=0 で同時に移動し、t=1 で同時に停止
同様に、G=lerp(E, F, t)
これで、G ポイントの軌跡を取得する準備が整いました。
E=lerp(A, B, t)
F=lerp(B,C,t)
G=lerp(E, F, t)
G=lerp(lerp(A, B, t) , lerp(B ,C, t), t)
=> G=lerp((1-t)A+tB, (1-t)B+tC, t)
=(1-t)[(1-t)A+tB]+t[(1-t)B+tC]
=(1-t)^2 A+2t(1-t)B+t^2 C
これは2 次ベジェ曲線方程式であり、3 次ベジェ曲線方程式も同様です。
C++ でシミュレートしてみましょう。
コードは以下のように表示されます。
G 点の軌跡は 21 行目、IDE は Red Panda C++、環境は Win11、描画ライブラリは EGE
効果:
まあ、一般的に言えば、効果は悪くありません。
次に、曲線方程式を使用して、非線形性の計算を開始できます。
4、ノンリニアアニメーション
ここでは例として二次ベジェ曲線を取り上げます。
非線形効果を実現したい場合は、キャラクターの移動速度を非線形にする必要があります(ナンセンス)
物体の速度が時間とともに変化しても(加速度が変化しても) v/t=a≠C
ベジェ曲線を A を原点とする vt 座標系に置きます。Ay=Cy とします。明らかに、これは非線形動画です。
赤い線は取得された G 点の軌跡です
赤い線に関数 g(t) というラベルを付けます。
そうすれば、単純な微分知識から知ることができます
キャラクター動作加速度 a=v/t=lim(Δt→0) g(t+Δt)/Δt
ステップ サイズは限られており、アニメーションをあまり正確にする必要はないため、ここでは Δt=step (ステップ サイズ、プログラムでは 0.001 に設定しています) とします。
すると加速度 a=(Gy-G'y)/(Gx-G'.x)
ここでの G' は、前のステップの G の位置を指します (最後のユニットはステップ内にあることがよくあります)。
このようにして、2次ベジェ曲線による加速度の変化が 完成しました。
これは、これを使用してオブジェクトが移動する瞬間的な速度 (加速度) を変更できることを意味し、オブジェクトの速度は移動に伴って時間の経過とともに連続的に変化します。
このように、非線形性を実現するには、オブジェクトのモーション速度の加速度を各リフレッシュに追加するだけで済みます。
効果が表示されない
コードは以下のように表示されます。
自分でコピーしてみてください。
#include<bits/stdc++.h>
#include<ege.h>
#define get_key(k) (GetAsyncKeyState(k)&0x8000)
using namespace std;
using namespace ege;
float t = 0, step = 0.01;
ege_point A, B, C;
ege_point G = {0.0, 0.0}, nG = {100000, 1};
float v = 0.0, x = 1280, y = 240, r = 10;
float wt = 1, wv = 0.1; //wt偏移调整加速度和曲线相关性 wv速度缩放值
int main() {
A = {0, 480}, B = {240, 0}, C = {480, 480};
initgraph(2560, 480);
getch();
setcolor(YELLOW);
while (t < 1) {
G = {(1 - t)*(1 - t)*A.x + 2 * t*(1 - t)*B.x + t*t * C.x, (1 - t)*(1 - t)*A.y + 2 * t*(1 - t)*B.y + t*t * C.y};
float delta = (G.y - nG.y) / (G.x - nG.x);
nG = G;
t += step;
Sleep(0);
cleardevice();
circle(x, y, r);
v += (wt * delta);
x += (v * wv);
cout << "delta_v " << v << endl;
}
system("pause");
return 0;
}
五、結論
このチュートリアルでは、問題の発見→問題の抽象化→モデルの構築→問題の解決→実践的な応用という プロセスを経て、これが私たちの共通の進歩です。
また、問題を扱う際には、加速度、関数、導関数、方程式などの知識を使用します。これは、問題を包括的に適用して解決する能力において、重要な飛躍となります。