カメラとアニメーション — 指数関数となめらかさ
中継カメラが馬群をなめらかに追いかける仕組みを、微分方程式とその解 (指数関数) で説明します。「毎フレーム 1 割近づける」というよくある書き方が、なぜ画面によって速さが変わってしまうのか、そしてどう直すのか。
- 線形補間 (lerp) の意味
- 「毎フレーム一定の割合で近づく」書き方がフレームレートに依存してしまう理由
- 微分方程式 と、その厳密解から導く係数
- 半減期と時定数
- 時間の上限 (0.05 秒) や更新の間引きなど、映像を安定させる小さな工夫
線形補間 (lerp)
2 つの値 と の間を、割合 () だけ進んだ点は
です。 なら のまま、 なら に一致します。3D のカメラは毎フレーム、現在の位置 を目標の位置 (集団の横) へ lerp で少しずつ近づけています。
よくある書き方の問題 — 速さがフレームレートで変わる
いちばん簡単なのは、毎フレーム同じ割合 (たとえば ) だけ近づける書き方です。 フレーム後には、残りの距離が
になります。問題は「1 秒が何フレームか」が画面によって違うことです。1 秒後の残りは
- 30 fps:
- 60 fps:
- 144 fps:
同じプログラムなのに、144Hz のモニターではカメラが 30 fps のときよりはるかに速く動いてしまいます。
時間で考える — 微分方程式
「フレームごと」ではなく「時間ごと」に動きを決めるため、連続的な時間 での変化を考えます。
「目標までの残りに比例した速さで近づく」という式です ( は近づく速さの係数、単位は 1/秒)。残り と置くと となり、これは「自分の大きさに比例して減る」量なので、解は指数関数です。
1 フレーム ( 秒) の間にこの式どおり動かすには、残りを 倍にすればよいので、lerp の係数を
にします。アプリの中継カメラは です。
const k = 1 - Math.exp(-real * 2.5);
this.camPos.lerp(pos, this.t === 0 ? 1 : k);フレームレートに依存しない証明
秒と 秒の 2 フレームで進んだときの残りは
で、「 秒を 1 フレームで進んだ場合」と完全に同じです。指数関数の という性質のおかげで、フレームの区切り方 (= フレームレート) に関係なく、時刻 での位置が同じになります。
半減期と時定数
残りが半分になるまでの時間 (半減期) は を解いて
また 秒を 時定数 と呼び、この時間で残りが になります。中継カメラは「0.3 秒ほどで半分、1 秒で 9 割以上追いつく」速さで動いている、ということです。
さらに深く注視点の係数 1.6k は近似
カメラが見る点 (注視点) は Math.min(1, k * 1.6) で動かしています。これは厳密な ではありませんが、 が小さいとき
なので、ほぼ「 の指数関数的な追従」になります。注視点を位置より速く動かすのは、画面の中心に馬群を早く収めるためです。
映像を安定させる小さな工夫
1 フレームの時間に上限をつける
const real = Math.min(this.clock.running ? this.clock.getDelta() : 0, 0.05);ブラウザのタブを裏に回すと、描画が止まり、戻ったときに「前のフレームから 10 秒たった」ことになります。そのまま計算するとレースが一瞬で進み、ゴールの判定も飛んでしまうので、1 フレームの時間を最大 0.05 秒 (20 fps 相当) に制限しています。
脚の速さを走る速さに合わせる
h.act.timeScale = Math.max(0.35, h.v / 15);駆け足 (Gallop) のアニメーションの再生速度を、馬の速度 (m/s) に比例させています ( で等速)。地面を滑っているように見えない、という見た目のための調整です。
速度の平滑化
h.v += (v - h.v) * 0.2;フレームごとの速度 はガタガタするので、指数移動平均 (毎回 2 割だけ新しい値に寄せる) でならしています。こちらはフレームごとの固定係数なので、厳密にはフレームレートに依存しますが、見た目への影響は小さいため簡単な形にしています。
順位表の更新を間引く
左上の順位表 (HTML) は毎フレームではなく、0.12 秒に 1 回 (約 8 回 / 秒) だけ作り直しています。HTML の作り直しは 3D の描画より重いことがあり、人の目には 8 回 / 秒で十分滑らかに見えるからです。
- lerp は 。固定の だとフレームレートで速さが変わる
- の解は指数関数。1 フレームで にすると、どの画面でも同じ動き
- がフレームレート非依存の理由
- → 半減期 0.28 秒
- 1 フレームの時間の上限、脚の速さの同期、速度の平滑化、順位表の間引きで映像を安定させる
あるゲームが 60 fps を前提に毎フレーム で近づけていました。同じ動きをどのフレームレートでも再現するには、 をいくつにすればよいですか。
答えを見る
60 fps で となる を求めます。 より 。以後は を使います。
のカメラが、目標までの距離の 90% を進むのは何秒後ですか。
答えを見る
より 秒。