アニメーションにおいて、イージングは細かい味付けをするのに重要です。
代表的なイージングとして、
Sine
Cubic
Quint
等がありますが(詳しくは https://easings.net/ja 参照)、より細かい表現をするために Drift
というイージング関数を考案・実装しました。
なにが出来るのか
ある点まではイージング的な動きをし、ある点からは等速直線運動をして目的地に達する、という動きを表現できます。(最初がイーズアウトの時は)加速した後その勢いで滑っているように見えるので、Drift
という名称をつけました。
単一のイージング関数ではなく、運動が切り替わるポイントごとにイージング関数の形が変わります。そのグラフをまとめたものが以下になります。
(●は等速直線運動に切り替わるポイント)
同様の動きを実装したり計算したりしている人は絶対にいると思いますが、理論的な背景をまとめたものはないので、ここで私がそれをまとめて、ドリフトと名付けたいと思います(既にこういう名前がある、というものがあったらすいません)。
実装の気持ち
経過時間割合を $t (0 \leq t \lt 1)$ 、到達割合を $r (0 \leq r \lt 1)$ とします。
イージング関数は $r =f(t)$ という陽関数として定義することができます。
等速直線運動に移るまでの時間割合を $x$、その時の到達割合を $y$ とします。
後半の等速直線運動はけっこう簡単に求められます。
$(x,y)$ と $(1,1)$ を結ぶ直線になるので、
r = \frac{1-y}{1-x}(t-1) + 1 \\
= \frac{t-ty+y-x}{1-x}
問題は前半で、後半に滑らかにつながるようなイージング を実装する必要があります。
この関数を $g(t)$ とすると、
r = \left\{
\begin{array}{ll}
g(t) & (t \lt x)\\
\frac{t-ty+y-x}{1-x} & (x \leq t)
\end{array}
\right.
となります。
ベジェ曲線
「滑らかにつながらせる」ために、ベジェ曲線を使うことを考えます。
イラレとかでよく使われるベジェ曲線は、正確には 3 次のベジェ曲線であり、他にもベジェ曲線は色々あるのですが、今回もこれを使うのがわかりやすいので以降は 3 次のベジェ曲線をベジェ曲線と呼ぶことにします。
ベジェ曲線は、ハンドルと接線の傾きが一致するという性質があるので、
- 始点 $P_0$ ... $(0,0)$
- 始点ハンドル $P_1$ ... $(0,0)$
- 終点ハンドル $P_2$ ... $(x,y)$ と $(1,1)$ を結んだ直線とグラフの軸の交点
- 終点 $P_3$ ... $(x,y)$
というベジェ曲線を書けば要求を満たせます。
$P_2$ の位置は、
P_2 =
\left\{
\begin{array}{ll}
(0,\frac{y-x}{1-x}) & (y > x)\\
(\frac{x-y}{1-y},0) & (y < x)
\end{array}
\right.
となります。
ベジェ曲線は媒介変数 $q$ を用いると、
B = (1-q)^3 P_0 + 3(1-q)^2 q P_1 + 3(1-q)q^2 P_2 + q^3 P_3
なる $B$ を $0 \leq q < 1$ の範囲で動かした時の軌跡となります。この媒介変数を解いて、$r = g(t)$ という陽関数の形に直す必要があります。$P_0$ と $P_1$ は $(0,0)$ なので無視してもよいですが、それでも 3 次式が残ります。
二分探索
一般に 2 次以上の媒介変数を解析的に解くのは難しいですが、今回は単調性があるので二分探索を用いて高速に、ある $t$ に対する $q$ を求めることができます。許容誤差のオーダーを $\frac{1}{N}$ とすると、総当りでは $O(N)$ の計算量がかかりますが、二分探索であれば $O(\log{N})$ で済むので、厳しい許容誤差(より正確な値)でも高速に求めることができます。$q$ が決定できれば、$r$ は媒介変数を用いて直に計算できます。
以上の処理をプログラムに直したものが以下になります。
def Drift(t, x, y):
if x == 1 and y == 1:
return t
if x > y:
hy = 0
hx = (x-y)/(1-y)
else:
hx = 0
hy = (y-x)/(1-x)
if t >= x:
return (t-t*y+y-x)/(1-x)
else:
ng = 0
ok = 1
while abs(ng-ok) > 1e-10:
mid = ng + ok
mid /= 2
criteria = 3*(1-mid)*mid*mid*hx + mid*mid*mid*x
if criteria >= t:
ok = mid
else:
ng = mid
return 3*(1-ok)*ok*ok*hy + ok*ok*ok*y
結論
- イージングの表現力を高めるためにドリフトを考案
- ベジェ曲線を用いてドリフトを実装
- ベジェ曲線の計算を、二分探索を利用して高速化