13. アニメーション1:キーフレーム・運動学・キャラクタ

此処までのシリーズの絵は全て静止画でした。1台のカメラ、1つのシーン、1枚の画像です。
此の章で、いよいよ物が動き始めます。
アニメーションは沢山の画像を次々に見せるだけの物ですが、其の間で何が、どれだけ変わるかを決めるのは、其れだけで1つの技術です。
CGアニメーションがどう組み立てられているか、アニメーターが幾つかの重要なポーズだけを決めて残りをコンピュータに埋めさせる方法、回転に特別な注意が要る理由、そしてキャラクタが皮膚を動かす骨格からどう作られるかを見ていきます。

何故此れが大事なのでしょうか?
ゲームのキャラクタも、アニメ映画も、製品紹介映像のカメラワークも、全て此の章の道具で作られています。
そして数学は既に知っている物です。第4章と第5章の変換と階層、第8章のエルミート曲線・ベジェ曲線・カトマル・ロム・スプライン、そして線型代数 第13章のクォータニオンを、今度は時間をパラメータにして使います。
検定対策としては、此の章は分野5の3つのシラバス項目、CGアニメーションの構成、キーフレームアニメーション、キャラクタのアニメーションを扱います。
分野5の残りの4項目、物理ベース・リアルタイム・手続き型のアニメーションと実写映像との合成は第14章です。

13.1 アニメーションはフレームの連続

映画は本当は動いていません。
静止画の連続、つまりフレーム(コマ)を、別々の絵ではなく動きとして見える程速く見せているのです。
此れが仮現運動で、第3章(3.9節)でちらつきと一緒に紹介した視覚の性質です。知覚の他の話と合わせて第18章で又取り上げます。

1秒あたりのフレーム数がフレームレートで、fpsと書きます:

  • 24 fps:映画。1920年代の終わりから使われています。
  • 30 fps(NTSCの流れでは正確には30000/1001 ≈ 29.97)と25 fps(PAL):テレビとビデオ。
  • 60 fps(又は其れ以上):ゲームとVR。プレイヤーの操作に素早く反応する必要があるからです。

時間とフレーム

CGアニメーションはシーンを秒単位の時間 t の関数として記述し、レンダラーは其れをフレームの時刻で標本化します。
フレームレート F では、(0から数えた)フレーム n が表す時刻は

tn=nF,長さ T 秒のショットは N=T⋅F フレーム

計算例。 2.5秒のショットは24 fpsで 2.5⋅24=60 フレームです。同じショットが30 fpsでは75フレーム、60 fpsでは150フレームになります。
24 fpsのフレーム37は時刻 37/24≈1.542 秒で、1フレームの長さは 1/24≈41.7 msです。
アニメーションをフレーム番号ではなく時間の関数として持っておくからこそ、同じアニメーションを映画用に24 fpsで、ゲーム用に60 fpsでレンダリング出来ます。

1コマ打ち・2コマ打ち・3コマ打ち

手描きのアニメーションでは、全てのフレームに新しい絵を描く事は滅多にありません。
日本のテレビアニメは普通2コマ打ちか3コマ打ちで描かれます。24 fpsのフィルムの2コマ又は3コマの間、同じ絵を保持するので、1秒あたりの絵は12枚又は8枚です。

24 fpsで0.5秒の12フレームを、1コマ打ち、2コマ打ち、3コマ打ちで描いた場合。絵は其々12枚、6枚、4枚

上の2.5秒のショットは、1コマ打ちで60枚、2コマ打ちで30枚、3コマ打ちで20枚の絵が必要です。
3DCGは普通1コマ打ちで計算されます。計算で作るフレームは手描きの絵に比べて安いからです。アニメ調の3DCGでは、手描きらしく見せる為にわざと2コマや3コマでポーズを保持する事もあります。

時間の標本化

フレームをレンダリングする事は時間方向の標本化なので、第2章(2.6節)の標本化定理が当てはまります。
フレームレートに対して速過ぎる動きはエイリアシングを起こします。逆回転して見える車輪が其の例です。
時間方向のプリフィルタがモーションブラーです。仮想のシャッターが開いている間(2.3節)のシーンを平均すると、速い物体は跳ぶ代わりに其の経路に沿って流れます。
モーションブラーのある24 fpsの映画は滑らかに見え、其れが無い24 fpsのゲームはカクカクに見えます。

13.2 CGアニメーションの構成

時間と共に変えられる物

シーンの中で数値で表される物は、何でもアニメーション出来ます:

  • 変換:物体の位置、向き、大きさ(第4章と第5章のモデリング変換)。
  • カメラ:位置、向き、焦点距離又は画角、ピントの距離。
  • 光源:位置、色、強さ、スポットライトの円錐。
  • マテリアル:色、透明度、テクスチャのずらし量(流れる水のテクスチャ)。
  • 形状:頂点其の物。ブレンドシェイプ、ラティス、骨格で変形します(13.5節と13.8節)。
  • 其の他のパラメータ:風の強さ、放出するパーティクルの数、物体の表示・非表示。

アニメーションする1つ1つの数値がチャンネル(又はアニメーションカーブ)で、時間の関数です。歩くキャラクタ1体で数百本になる事も珍しくありません。

階層構造:シーングラフ

物体が互いに無関係な事は滅多にありません。
車輪は世界の中を走る車の上で回り、指は腕と一緒に動く手の上で曲がります。
CGソフトウェアはシーンを木構造、つまりシーングラフ(階層構造)として整理します。各ノードは親に対するローカルな変換を持ち、其のワールド変換は親のワールド変換に自分のローカル変換を掛けた物です:

𝐌world(子)=𝐌world(親)𝐌local(子)

此れは第4章(4.3節)の合成変換を、一番右の行列が最初に作用する形で(線型代数 第7章)、階層ごとに繰り返す物に過ぎません。
アニメーションにとっての利点は大きいです。車を走らせるには車の変換を1つアニメーションするだけで、車輪も運転手も運転手の帽子も付いて来ます。
キャラクタの骨格は、関節をノードにした同じ考え方で、13.6節で数値を使って確かめます。

制作工程

CG映画は長い工程の連鎖で作られ、アニメーションは其の真ん中にあります:

企画と絵コンテからレイアウト、モデリング、リギング、アニメーション、シミュレーション、ライティングとレンダリングを経てコンポジットと編集に至る制作工程と、此のシリーズの章

  • 企画・シナリオ:物語。
  • 絵コンテ(storyboard):ショットごとの絵に、カメラの構図、演技、タイミングのメモを添えた物。日本のアニメ制作では絵コンテが計画の中心になる書類です。
  • レイアウト・プリビズ:ショットの大まかな3D版で、カメラ、キャラクタの位置、各カットのタイミングを決めます。
  • モデリング(第7〜9章)とリギング(13.8節):キャラクタや小道具を作り、操作の仕組みを付けます。
  • アニメーション:此の章です。アニメーターがリグに時間に沿ってポーズを付けます。
  • シミュレーション・エフェクト(第14章):布、髪、流体、破壊を、アニメーションされた動きから計算します。
  • ライティング・レンダリング(第10〜12章)。
  • コンポジット(第14章と第15章):レンダリングしたレイヤーや実写映像を組み合わせて最終的な画像にします。
  • 編集・出力:カット編集、音、そして最終的なファイル又はフィルム(出力装置と記録メディアは第17章)。

ゲームも前半(アセット、リグ、アニメーションクリップ)は同じですが、後半はプレイヤーのマシンの上で毎フレーム行われます。リアルタイムアニメーションは第14章で扱います。

動きを作る4つの方法

チャンネルの値を決めるのは誰、又は何でしょうか?

手法 動きを決める物 長所 短所 章
キーフレームアニメーション アニメーターがキーポーズを決め、コンピュータが補間する 表現を完全に制御出来る、誇張した動き 手間が掛かる、物理的に正しくするのが難しい 13
モーションキャプチャ 実際の演者を計測する リアル、大量の動きを素早く作れる 整理が必要、誇張しにくい、演者の動きに縛られる 13
手続き型アニメーション 規則と関数(ノイズ、群れ、エクスプレッション) 膨大な数の物体、無限のバリエーション 細かい演出が難しい 14
物理ベースアニメーション 物理法則のシミュレーション 説得力のある布、流体、衝突 計算が重い、演出が難しい 14

実際の制作では此れらを混ぜます。キーフレームで付けたキャラクタに、キャプチャした体の動き、シミュレーションした髪、手続き型で動かす背景の群衆、と言った具合です。

13.3 キーフレームアニメーション

キーと中割り

伝統的なアニメーションでは、メインのアニメーターが重要なポーズである原画(key frame)を描き、其の間の絵である動画(in-between)を別の人が描きます。原画の間を埋める作業が中割り(in-betweening)です。
キーフレームアニメーションは、此の2つ目の仕事をコンピュータに任せます。
アニメーターはチャンネルにキー、つまり時刻と値の組を置きます。
其れ以外の全てのフレームの値は、コンピュータが補間で計算します。
上がって落ちるボールの高さなら、キーは3つで済み、間の22フレームはコンピュータが作ります。

ファンクションカーブとグラフエディタ

値を時間に対して描いた各チャンネルがファンクションカーブ(Fカーブ)で、此れを表示・編集する道具がグラフエディタです。
ファンクションカーブを読めるのは基本の技術です:

  • カーブの高さが値です。
  • 傾きが速さです。急なカーブは速い動き、平らなカーブは静止(ホールド)です。
  • 折れ目(傾きの急な変化)は速さの急な変化、つまりガクッとした動きです。
  • 曲がり具合が加速度です。

だからこそ第8章(8.2節)の連続性の分類が此処で効きます。C1 のカーブには速さの飛びが無く、C2 のカーブは加速度も連続です。

ステップ・線型・スムーズ補間

5つのキー、(フレーム, 値)=(0, 0)、(10, 10)、(20, 6)、(30, 6)、(40, 6)を持つチャンネルを考えます。何かが10まで上がり、6に戻って其の儘留まる動きです。

ステップ補間(定数補間とも言います):次のキーまで、各キーの値を保持します。
動きは飛び飛びになります。アニメーターはショットのブロッキング(キーポーズだけを付ける段階)や、ライトのスイッチの様に本当に切り替わる物に使います。

線型補間:隣り合うキーの間を直線で結びます。

v(t)=vi+s(vi+1−vi),s=t−titi+1−ti

フレーム15では s=0.5 で、v=10+0.5(6−10)=8 です。
カーブは連続ですが、キーで折れ目があります。速さが一瞬で変わるので、機械的に見えます。

スムーズ補間:隣り合うキーの間を3次のエルミート曲線で結びます(第8章、8.3節)。
接線には8.7節のカトマル・ロムの選び方を使います。キーでの傾きは、其の両隣のキーを結ぶ直線の傾きです。
キーが時間的に等間隔に並ぶ事は少ないので、傾きはフレームあたりで測ります。

mi=vi+1−vi−1ti+1−ti−1

そして区間上のエルミート曲線には、Δt=ti+1−ti として接線 miΔt と mi+1Δt を使います。エルミートのパラメータ s が0から1まで動く間に、t は Δt フレーム進むからです。
隣が片方にしか無い最初と最後のキーでは、此処では傾きを0にします(平らな始まりと終わり)。

計算例。 傾きはフレームあたり m0=0、m1=6−020−0=0.3、m2=6−1030−10=−0.2、m3=6−640−20=0、m4=0 です。
フレーム10から20の区間では Δt=10 なので、接線は 0.3⋅10=3 と −0.2⋅10=−2 です。
フレーム15(s=0.5)でのエルミートの重みは 0.5,0.5,0.125,−0.125 です(第8章):

v(15)=0.5⋅10+0.5⋅6+0.125⋅3−0.125⋅(−2)=8+0.375+0.25=8.625

ステップは10、線型は8、スムーズは8.625です。

5つのキーをステップ、線型、スムーズ(カトマル・ロム)で補間したカーブ。スムーズなカーブはフレーム10の後で10.15までオーバーシュートし、フレーム20の後で5.70までアンダーシュートする

オーバーシュートと接線の制御

フレーム23あたりのスムーズなカーブを見て下さい。
フレーム20から30の区間では両方のキーの値が6ですが、フレーム20の接線は −2(カーブが下がりながら到着する)で、フレーム30の接線は0です:

v(s)=6H0(s)+6H1(s)−2H2(s)=6−2(s3−2s2+s)

(H0+H1=1 を使いました。)
H2 は s=13 で最大になり、其の値は 127−29+13=427 なので、値はフレーム23.3で 6−827≈5.70 まで下がります。
6で静止する筈の物体が、先ず其の下に沈むのです。此れがアンダーシュートです。
同様に、山のキー(フレーム10)での傾きは0ではなく +0.3 なので、カーブはキーを過ぎても上がり続け、約10.15に達します。
此のオーバーシュートは、凸包性を持たない補間スプライン(8.7節)の代償です。

アニメーションツールは、此れを制御する手段をアニメーターに与えます:

  • フラット又はクランプの接線:山、谷、静止のキーの傾きを0にするので、カーブがキーを越えません(多くのツールには、此の為の「オートクランプ」の既定値があります)。
  • ブロークン接線:1つのキーでインとアウトの接線を別々にします。ボールが床に当たる様な急な変化に使います。
  • 接線ハンドル:インとアウトの接線をドラッグするハンドルとして表示します。此れは8.4節のエルミートの接線、又はベジェの内側の制御点其の物で、「ウェイト付き」ハンドルなら接線の長さも変えられます。

オーバーシュートが常に悪い訳ではありません。
わざと少し行き過ぎてから戻る動きは、アニメーションの古典的な「フォロースルー」です。アニメーターが嫌うのは、意図しない方です。

イーズインとイーズアウト

現実の物体は一瞬で動き出したり止まったりしません。手で開けるドアは、速くなってから遅くなります。
ゆっくり動き出す事をイーズイン(スローイン)、ゆっくり止まる事をイーズアウト(スローアウト)と言い、「スローイン・スローアウト」はディズニーのアニメーションの古典的な原則の1つです。
正規化した時間 u=t−t0t1−t0 で0から1へ動く場合、標準的な3次式はスムーズステップ関数です。

s(u)=3u2−2u3,s′(u)=6u−6u2

此れは新しい物ではありません。第8章のエルミート基底関数 H1、つまり両端の接線が0の、0から1へのエルミート曲線で、第11章でバリューノイズを滑らかにするのに使ったのと同じ曲線です。
速さ s′ は両端で0、真ん中で s′(0.5)=1.5 なので、最高速度は平均の1.5倍です。

計算例。 ドアが1秒、つまり24フレームで90°開くとします。
線型の動きなら、毎フレーム 90/24=3.75° ずつ回ります。
スムーズステップでは:

フレーム u s(u) 角度
0 0 0 0°
6 0.25 3(0.0625) − 2(0.015625) = 0.15625 14.06°
12 0.5 0.5 45°
18 0.75 0.84375 75.94°
24 1 1 90°

最初のフレームでは 0.46° しか回らず、真ん中のフレームでは1フレームに約 5.6°(最高速度は毎秒 1.5⋅90=135°)回り、90°に優しく収まります。
アニメーターは此れをタイミングチャート(スペーシングの図)として描きます。動きに沿って1フレームに1目盛りを打ち、遅い所では目盛りが詰まります。

左:線型、スムーズステップ、イーズイン、イーズアウトの、正規化した時間に対する進み具合。右:24フレームの各フレームでのドアの角度。線型では等間隔、スムーズステップでは両端に詰まる

他によく使うイージングカーブには、イーズインだけの u2、イーズアウトだけの 1−(1−u)2、そして其れらの3次以上の版があります。

タイミングの為のベジェ曲線

多くのツールは、1つの区間のタイミングを(時間, 値)平面上の3次ベジェ曲線として、(0,0) から (1,1) まで2つのハンドルで表します。
どのウェブブラウザにもあるCSSのトランジション ease-in-out は、内側の制御点が (0.42,0) と (0.58,1) のベジェ曲線です。
両方の座標が、曲線のパラメータ σ の3次式です:

x(σ)=3(1−σ)2σ⋅0.42+3(1−σ)σ2⋅0.58+σ3,y(σ)=3(1−σ)σ2+σ3

時間 u での進み具合を求めるには、先ず x(σ)=u を σ について解き(ニュートン法や二分法を数回)、其れから y(σ) を計算します。
計算例、u=0.25:σ≈0.2251 で x=3⋅0.6005⋅0.2251⋅0.42+3⋅0.7749⋅0.0507⋅0.58+0.0114≈0.1703+0.0683+0.0114=0.25 となり、y=3⋅0.7749⋅0.0507+0.0114≈0.129 です。
つまり時間の4分の1で、此のイージングは動きの12.9 %しか進んでおらず、スムーズステップの15.6 %より始まりが遅いのです。

経路とタイミング

道路に沿って飛ぶカメラの様に空間の中を動く物では、どこを通るかと、いつ其処に着くかを分けると便利です:

  • モーションパス:通るべき場所を通る空間曲線で、普通はカトマル・ロムかベジェのスプラインです(第8章)。
  • タイミング:経路に沿って進んだ距離を時間の関数として与えるファンクションカーブで、独自のイージングを持ちます。

落とし穴があります。スプライン自身のパラメータ u は距離を測っていないのです。
第8章8.3節のエルミート曲線 𝐜(u)=(−10u3+12u2+6u,−12u2+12u)((0,0) から (8,0) まで)を例にします。
u=0,0.25,0.5,0.75,1 で、曲線は (0,0)、(2.094,2.25)、(4.75,3)、(7.031,2.25)、(8,0) にあり、此れらの点を結ぶ弦の長さは

2.0942+2.252=3.07,2.76,2.40,2.45

です。
u の等しい刻みが2.40から3.07までの距離に当たります。u を一定の割合で進めて動かしたカメラは、理由も無く速さが4分の1以上変わってしまいます。
解決策が弧長パラメータ化で、曲線を其れに沿った距離 ℓ で表します。
其の為の式が閉じた形で書ける曲線は殆ど無いので、プログラムは表を作ります:

  1. 曲線を沢山の u で標本化し、弦の長さを足していきます。此処では累積の長さは0、3.07、5.83、8.24、10.68です。
  2. 物体を距離 ℓ の所に置くには、其の値を含む表の区間を見つけ、其の中で u を線型補間します。

合計の10.68は本当の弧長10.89の近似です。弦は常に曲線より少し短く、弦を8本にすれば既に10.84になります。
中間の距離 ℓ=10.68/2=5.34 は2番目の区間にあり、其の 5.34−3.072.76=0.822 の位置なので、u≈0.25+0.822⋅0.25=0.456 です(正確には0.4565)。0.5ではありません。

第8章のエルミート曲線。uを等間隔にした点と弦の長さ3.07、2.76、2.40、2.45、及び弧長を等間隔にした点

表があれば、タイミングのカーブが経路に沿ってどこまで進んだかを決め、経路が其れが空間のどこかを決めます。
こうしてカメラは曲がりくねった道を一定の時速50 kmで進んだり、印を付けた場所に丁度イーズアウトで止まったり出来ます。

13.4 回転の補間

位置、色、殆どのパラメータは、チャンネルごとに補間して全く問題ありません。
向きは違います。其の理由は理解しておく価値があります。

チャンネルごとのオイラー角

アニメーションツールは普通、回転を3つのオイラー角(第5章、5.3節)として、其々1本のファンクションカーブで表示します。読み易く編集し易いからです。
3つの角度を別々に補間すると、線型代数 第13章(13.1節)が数値で示した3つの問題が起きます:

  • 2つの向きの間の経路が回転の順番に依存し、一般に最短の回転になりません。
  • 角度が一周して戻ります。170°から−170°は20°の回転なのに、数値上は逆向きに340°です。
  • ジンバルロックの近く、つまり真ん中の回転が90°に達して2つの軸が揃う所では、向きの小さな変化に角度の大きな跳びが必要になり、カーブがトゲの様に跳ねます。

其の為ツールには、カーブから360°の跳びを取り除く「オイラーフィルタ」があり、関節をクォータニオン補間に切り替える事も出来ます。

何故行列を補間しないのか

回転行列は9個の数値に過ぎないのに、何故混ぜてはいけないのでしょうか?
0°と90°の2次元の回転(第4章の行列の左上の部分)を取って、半分ずつ混ぜてみます:

12[1001]+12[0−110]=[0.5−0.50.50.5]

列の長さは 0.52+0.52=0.707、行列式は 0.25+0.25=0.5 です。
此れは45°の回転に0.707倍の拡大縮小を掛けた物です。物体は正しい量だけ回りますが、動きの途中で大きさが71 %に縮んでしまいます。
0°と180°の間ではもっと酷く、12(𝐈+(−𝐈))=𝟎 となって、物体は1点に潰れます。

2つの向きの中間での行列の線型補間とslerp。0°から90°では、行列の線型補間は45°回るが0.707倍に縮む。0°から180°では1点に潰れるが、slerpは元の大きさの回転になる

一般に、回転行列の重み付き和は回転ではありません。回転全体は曲がった集合を成していて、平均すると其の内側を突っ切ってしまうのです。
後から列を正規化し直すと良くはなりますが、速さは一定にならず、180°の場合には正規化する物が何も残りません。

クォータニオンのslerp

標準的な答えは、線型代数 第13章の単位クォータニオン(四元数)です。単位軸 𝐧^ 周りの角度 θ の回転は

q=(cosθ2,sinθ2𝐧^)

で、(w,x,y,z) と書きます。単位クォータニオンは4次元の単位球面上の点です。
球面線型補間、slerpは、其の球面に沿って一定の速さで進みます(1985年にケン・シューメイクがコンピュータアニメーションに持ち込みました):

slerp(qa,qb,t)=sin((1−t)Ω)sinΩqa+sin(tΩ)sinΩqb,cosΩ=qa⋅qb

(qa⋅qb<0 なら、同じ回転を表す −qb を使って短い方を回ります。理由は線型代数の章で説明しました。)

計算例。 砲塔の向きが、あるキーでz軸周りに30°、次のキーで110°だとします。
qa=(cos15°,0,0,sin15°)=(0.9659,0,0,0.2588)、qb=(cos55°,0,0,sin55°)=(0.5736,0,0,0.8192) です。
内積は 0.9659⋅0.5736+0.2588⋅0.8192=0.5540+0.2120=0.7660 なので、Ω=arccos0.7660=40°、2つのキーの間の80°の半分です。
t=0.5 では両方の重みが sin20°sin40°=0.34200.6428=0.5321 です:

0.5321(0.9659+0.5736,0,0,0.2588+0.8192)=0.5321(1.5395,0,0,1.0780)=(0.8192,0,0,0.5736)

此れは (cos35°,0,0,sin35°)、つまり70°の回転で、30°と110°の丁度真ん中です。
t=0.25 では重みが sin30°sin40°=0.7779 と sin10°sin40°=0.2701 で、(0.9063,0,0,0.4226)=(cos25°,0,0,sin25°)、50°になります。一定の速さで、丁度4分の1進んでいます。

nlerp(正規化線型補間)は4つの数値を混ぜてから正規化します。
t=0.25 では (0.9086,0,0,0.4176) となり、50°ではなく49.37°の回転です。t=0.5 ではslerpと一致します。
アニメーションの隣り合うキーの間なら1°未満の差は見えず、nlerpの方が安いので、多くのゲームエンジンがnlerpを使います。大きな回転ではslerpの一定の速さが効きます。
2つのキーの間のslerpは、線型補間の回転版です。キーで角速度に折れ目が出来ます。
沢山の向きを滑らかに通るカーブ(カトマル・ロムの回転版)もあり、例えばシューメイクのsquadは、第8章のド・カステリョのアルゴリズムの様にslerpを入れ子にして作ります。

実際には

アニメーターはオイラー角のカーブを編集し続けますが、ゲームエンジンに渡すデータは普通クォータニオンのキーを保存します。
glTF 2.0形式(第9章)が良い例です。其のアニメーションのサンプラーは正に此の節の3つの補間、STEP、LINEAR、CUBICSPLINE(接線を保存したエルミート曲線)を持ち、仕様では回転に対するLINEARはクォータニオンのslerpを意味します。クォータニオンは (x,y,z,w) の順で保存されます。
glTFファイルはOpenGLシリーズの第13章で自分で読み込みます。

13.3節のキーの補間、ドアのスムーズステップ、そして計算例のslerpをC++で書くと次の様になります。Quatとslerpは線型代数シリーズのlinalg.hhの物です:

#include <cstdio>
#include <vector>
#include "linalg.hh"

enum class Interp { Step, Linear, Smooth };

struct Key {
  float time;  // in frames
  float value;
};

// Catmull–Rom slope at key i (value per frame); flat at the first and the last key.
float keySlope(const std::vector<Key> &k, size_t i) {
  if (i == 0 || i + 1 == k.size()) return 0.0f;
  return (k[i + 1].value - k[i - 1].value) / (k[i + 1].time - k[i - 1].time);
}

// Value of an animation channel at time t (keys sorted by time).
float evaluate(const std::vector<Key> &k, float t, Interp mode) {
  if (t <= k.front().time) return k.front().value;
  if (t >= k.back().time) return k.back().value;
  size_t i = 0;
  while (k[i + 1].time < t) ++i; // the segment k[i] .. k[i + 1] contains t
  float d = k[i + 1].time - k[i].time;
  float s = (t - k[i].time) / d; // 0 .. 1 inside the segment
  float v0 = k[i].value, v1 = k[i + 1].value;
  switch (mode) {
  case Interp::Step: return v0;
  case Interp::Linear: return v0 + s * (v1 - v0);
  case Interp::Smooth: {
    float s2 = s * s, s3 = s2 * s; // Hermite basis functions (chapter 8)
    float h0 = 2 * s3 - 3 * s2 + 1, h1 = -2 * s3 + 3 * s2, h2 = s3 - 2 * s2 + s, h3 = s3 - s2;
    return h0 * v0 + h1 * v1 + h2 * keySlope(k, i) * d + h3 * keySlope(k, i + 1) * d;
  }
  }
  return v0;
}

float smoothstep01(float u) { return u * u * (3.0f - 2.0f * u); }

int main() {
  std::vector<Key> keys = {{0, 0}, {10, 10}, {20, 6}, {30, 6}, {40, 6}};
  for (float t : {5.0f, 15.0f, 23.3333f}) {
    printf("frame %5.2f: step %g, linear %g, smooth %.4g\n", t, evaluate(keys, t, Interp::Step),
           evaluate(keys, t, Interp::Linear), evaluate(keys, t, Interp::Smooth));
  }
  for (int f = 0; f <= 24; f += 6) {
    printf("door at frame %2d: %.4g degrees\n", f, 90.0f * smoothstep01(f / 24.0f));
  }
  Quat a = Quat::fromAxisAngle({0, 0, 1}, 30.0f * 3.14159265f / 180.0f);
  Quat b = Quat::fromAxisAngle({0, 0, 1}, 110.0f * 3.14159265f / 180.0f);
  Quat m = slerp(a, b, 0.5f);
  printf("slerp(30, 110, 0.5) = (%.4f, %.4f, %.4f, %.4f)\n", m.w, m.x, m.y, m.z);
  return 0;
}

frame  5.00: step 0, linear 5, smooth 4.625
frame 15.00: step 10, linear 8, smooth 8.625
frame 23.33: step 6, linear 6, smooth 5.704
door at frame  0: 0 degrees
door at frame  6: 14.06 degrees
door at frame 12: 45 degrees
door at frame 18: 75.94 degrees
door at frame 24: 90 degrees
slerp(30, 110, 0.5) = (0.8192, 0.0000, 0.0000, 0.5736)

検定のポイント

  • キーフレームアニメーション:アニメーターがキーを置き、コンピュータが補間で中割りを作る。
  • ステップは保持、線型はキーで速さに折れ目が出来る、スムーズ(カトマル・ロムの接線のエルミート曲線)は全てのキーを速さが連続な形で通るがオーバーシュートし得る。フラット又はクランプの接線で防げる。
  • イーズイン・イーズアウト:両端で速さが0。スムーズステップ 3u2−2u3 はエルミートの H1 で、最高速度は平均の1.5倍。
  • スプラインのパラメータは距離ではない。経路に沿って一定の速さで動かすには弧長パラメータ化が要る。
  • 一般の回転では、オイラー角や行列の要素を補間しない。オイラー角は経路がおかしくなりジンバルロックが起き、行列の混合は縮む(0°から90°で0.707倍)か潰れる(0°から180°)。クォータニオンのslerp(一定の速さ)か、nlerp(安く、小さな刻みならほぼ同じ)を使う。

13.5 形状の補間と変形

キーは角度の様な数値でなくても構いません。
キーが形状全体でも良いのです。

形状補間とモーフィング

2つの形状 A と B が同じ数の頂点を持ち、A の頂点 i が B の頂点 i に対応しているなら、各頂点を単純に補間出来ます:

𝐯i(t)=(1−t)𝐚i+t𝐛i

此れが形状補間で、此の方法で1つの形を別の形に変えるアニメーションがモーフィングです。
難しいのは式ではなく対応付けです。猫のどの頂点がティーポットのどの頂点に当たるのでしょうか?
同じベースメッシュから作った形状(2つの表情の顔)なら対応は最初から決まっていますが、無関係なモデルの間では、両方をリメッシュしたり特徴を手で対応付けたりして作る必要があります。
メッシュではなく2枚の画像の間のモーフィング(ワーピングとクロスディゾルブ)は2次元の画像処理の技法で、第15章で扱います。第12章ではイメージベーストレンダリングとして出会いました。

ブレンドシェイプ

ブレンドシェイプ(モーフターゲット、シェイプキーとも言います)は、此れを多くの形状に一度に一般化した物です。
アーティストは無表情のベースのメッシュ 𝐛 と、同じ頂点を持つ幾つかのターゲット 𝐭k をスカルプトします。笑顔、口を開く、まばたき、しかめ面…。
各ターゲットは重み wk(アニメーションするチャンネル)を持ち、結果はベースからの差分を足し合わせた物です:

𝐯=𝐛+∑kwk(𝐭k−𝐛)

計算例。 口角の1つの頂点が、ベース (2.0,1.0,0.5)、「笑顔」ターゲット (2.3,1.4,0.4)、「口を開く」ターゲット (2.0,0.6,0.6) で、重みが0.5と0.8だとします。
差分は (0.3,0.4,−0.1) と (0,−0.4,0.1) なので

𝐯=(2.0,1.0,0.5)+0.5(0.3,0.4,−0.1)+0.8(0,−0.4,0.1)=(2.15,0.88,0.53)

口を大きく開けた半分の笑顔です。口角は笑顔によって外側(x)と少し上に、口の開きによって下に動きます。
差分は足し算なので、ターゲットは自由に組み合わせられます。重みが1を超えれば形を誇張し、負の重みなら反転します。
上手く足し合わない組み合わせ(口を開けたまま笑うと変に見える事が多い)には、両方の重みが大きい時だけ効く補正シェイプ(コレクティブシェイプ)を追加します。
ブレンドシェイプはフェイシャルアニメーション(13.8節)の主力で、glTFも全てのゲームエンジンも直接サポートしています。

パスアニメーション

パスアニメーションは、物体をモーションパス(13.3節)に沿って動かし、普通は其の向きも経路に合わせます。物体の前方の軸が経路の接線 𝐜′(u)(第8章)に従い、指定した上方向のベクトルがロールを決めます。接線を視線方向にした、第5章のlookAtの組み立てと全く同じです。
道路上の車、レール上の列車、ドリーのレール上のカメラ、曲線に沿って泳ぐ魚は、全てパスアニメーションです。

フリーフォームデフォメーション

フリーフォームデフォメーション(FFD。セダーバーグとパリー、1986年)は、物体の周りの空間を変形する事で物体を変形します。
物体を制御点のラティス(格子)の中に埋め込みます。物体の各点はラティスの中で0から1のローカル座標 (s,t,u) を持ち、変形後の位置は、第8章(8.4節)のバーンスタイン多項式で作った、制御点のベジェボリュームです:

𝐗(s,t,u)=∑i∑j∑kBi(s)Bj(t)Bk(u)𝐏ijk

制御点が規則正しい格子の上にある限り、𝐗 は元の点を返します。アニメーターが制御点を動かすと、其の近くの全てが滑らかに動きます。

2次元の計算例です。長方形 (0,0) 〜 (4,2) の上の3 × 3のラティス(両方向に2次。B0=(1−s)2、B1=2s(1−s)、B2=s2)を使います。
制御点は x=0,2,4、y=0,1,2 にあります。
真ん中の制御点 𝐏11 だけを (2,1) から (2,2) へ上げます。
各点は、其の変位 (0,1) の B1(s)B1(t) 倍だけ動きます:

  • 中心 (2,1) は s=t=0.5 で、両方向とも B1=2⋅0.5⋅0.5=0.5 なので、0.5⋅0.5=0.25 上がって (2,1.25) になります。
  • 点 (1,1) は s=0.25 で、B1(0.25)=2⋅0.25⋅0.75=0.375 なので、0.375⋅0.5=0.1875 上がります。
  • 縁の点(s 又は t が0か1)は動きません。其処では B1 が0だからです。

3 × 3のFFDラティスの中の円と格子。中央の制御点を上に動かす前と後

変形は滑らかで、物体のメッシュの事を何も知らなくて良いので、点を持つ物なら何にでも使えます。呼吸するキャラクタのお腹、漫画的なスクワッシュ&ストレッチ、衝突で曲がる車などです。
DCCツールではラティスデフォーマと呼ばれます。似たデフォーマには、物体を曲げる、捻る、先細りにする物や、周りを囲む粗いケージのメッシュで変形する物があります。

13.6 スケルトンとフォワードキネマティクス

スケルトン・ボーン・関節

キャラクタはスケルトン(骨格)を通してアニメーションします。ボーンで繋がった関節(ジョイント)の階層です。
此れは13.2節のシーングラフの、関節をノードにした物です。普通は腰が根のルートで、其の変換がキャラクタ全体を世界の中で動かします。

人型のスケルトンと其の関節の階層。腰から背骨を通って頭と腕へ、腰から脚へ

各関節は、親からの固定のオフセット(基本姿勢でのボーンの長さと向き)と、アニメーションする回転を持ちます。
関節が許す独立な回転の数が、其の自由度(DOF)です:

  • 肘や膝の様なヒンジ関節:1自由度。1つの軸周りに曲がるだけです。
  • 肩や股関節の様な球関節:3自由度。
  • ルート:6自由度。位置に3、向きに3です。

関節には可動域(ジョイントリミット)も付けます。膝は一方向にしか曲がらず、範囲はおよそ0°から150°です。
典型的なゲームキャラクタの関節は30〜100個、指や顔の関節を持つ映画のキャラクタでは数百個です。

フォワードキネマティクス

フォワードキネマティクス(FK、順運動学)は、関節の角度から全ての関節の位置を、ルートから階層を下りながら計算します。各関節のワールド変換は、親のワールド変換に自分のオフセットと回転を掛けた物です。
連鎖の最後の関節、つまりどこかに届くべき関節(手、足、指先)がエンドエフェクタです。

一番簡単な例は2つのリンクを持つ平面の腕です。長さ l1 の上腕が肩で θ1 回り、長さ l2 の前腕が肘で上腕に対して θ2 回ります:

𝐌手=𝐑(θ1)𝐓(l1,0)𝐑(θ2)𝐓(l2,0)

原点に当てはめると

𝐞=(l1cosθ1,l1sinθ1)(肘)𝐡=(l1cosθ1+l2cos(θ1+θ2),l1sinθ1+l2sin(θ1+θ2))(手)

前腕の向きが θ1+θ2 なのは、其の回転が親に対する物だからです。肩を回すと前腕全体が一緒に付いて来ます。

計算例。 l1=3、l2=2、θ1=30°、θ2=45°:

𝐞=(3⋅0.8660,3⋅0.5)=(2.598,1.5)
𝐡=(2.598+2cos75°,1.5+2sin75°)=(2.598+2⋅0.2588,1.5+2⋅0.9659)=(3.116,3.432)

FKは、アニメーターが関節を1つずつポーズ付けする時(「肩を30°回し、次に肘を45°」)にやっている事であり、アニメーションされた関節の回転をワールド行列に変える為に全てのエンジンが毎フレームやっている事でもあります。
尻尾や歩く時の腕の様に振る動きには自然ですが、接触には不向きです。肩と肘の角度を回して手を丁度ドアノブの上に置くのは試行錯誤になります。

関節の配列を下りるFKをlinalg.hhで書き(親は子より前に格納するので、先頭から1回通るだけで済みます)、次の節の解析的なIKも一緒に載せます:

#include <cmath>
#include <cstdio>
#include <initializer_list>
#include "linalg.hh"

// One joint of a chain: its parent (-1 for the root), the offset from the parent's joint in the
// parent's frame, and the animated rotation about z.
struct Joint {
  int parent;
  Vec3 offset;
  float angle;
};

// Forward kinematics: world = parent's world * T(offset) * Rz(angle).
// Parents come first in the array.
void forwardKinematics(const Joint *joints, int count, Mat4 *world) {
  for (int i = 0; i < count; ++i) {
    Mat4 local = translate(joints[i].offset) * rotateZ(joints[i].angle);
    world[i] = joints[i].parent < 0 ? local : world[joints[i].parent] * local;
  }
}

// Analytic two-link IK in the plane.
// Returns false (and stretches towards the target) if the target is out of reach.
bool solveTwoLink(float l1, float l2, float x, float y, bool elbowDown,
                  float &theta1, float &theta2) {
  float c2 = (x * x + y * y - l1 * l1 - l2 * l2) / (2.0f * l1 * l2); // law of cosines
  bool reachable = c2 >= -1.0f && c2 <= 1.0f;
  c2 = std::fmax(-1.0f, std::fmin(1.0f, c2));
  theta2 = (elbowDown ? 1.0f : -1.0f) * std::acos(c2);
  theta1 = std::atan2(y, x) - std::atan2(l2 * std::sin(theta2), l1 + l2 * std::cos(theta2));
  return reachable;
}

int main() {
  const float deg = 3.14159265f / 180.0f;
  Joint arm[3] = {
    {-1, {0, 0, 0}, 30 * deg}, // shoulder
    {0, {3, 0, 0}, 45 * deg},  // elbow, 3 units along the upper arm
    {1, {2, 0, 0}, 0},         // hand (end effector), 2 units along the forearm
  };
  Mat4 world[3];
  forwardKinematics(arm, 3, world);
  for (int i = 1; i < 3; ++i) {
    Vec4 p = world[i] * Vec4{0, 0, 0, 1};
    printf("joint %d at (%.3f, %.3f)\n", i, p.x, p.y);
  }
  for (bool down : {true, false}) {
    float t1, t2;
    bool ok = solveTwoLink(3, 2, 3.1157f, 3.4319f, down, t1, t2);
    printf("IK %s: theta1 = %.2f, theta2 = %.2f (%s)\n", down ? "elbow down" : "elbow up",
           t1 / deg, t2 / deg, ok ? "reachable" : "out of reach");
  }
  float t1, t2;
  bool ok = solveTwoLink(3, 2, 6, 0, true, t1, t2);
  printf("IK (6, 0): theta1 = %.2f, theta2 = %.2f (%s)\n", t1 / deg, t2 / deg,
         ok ? "reachable" : "out of reach");
  return 0;
}

joint 1 at (2.598, 1.500)
joint 2 at (3.116, 3.432)
IK elbow down: theta1 = 30.00, theta2 = 45.00 (reachable)
IK elbow up: theta1 = 65.53, theta2 = -45.00 (reachable)
IK (6, 0): theta1 = 0.00, theta2 = 0.00 (out of reach)

13.7 インバースキネマティクス

インバースキネマティクス(IK、逆運動学)は逆向きの計算です。エンドエフェクタがどこにあるべきかが与えられた時に、関節の角度を求めます。
アニメーターが手をドアノブまでドラッグしたり、足を地面に固定したりすると、ソルバーが其れに合わせて肘や膝を曲げます。
ゲームは毎フレームIKを使って、でこぼこの地面に足を置き、梯子や武器に手を添え、キャラクタが見ている物の方へ頭を向けます。

2リンクの解析解

2リンクの腕なら、IKは学校の幾何で正確に解けます。
肩、肘、目標は、辺が l1、l2、目標 (x,y) までの距離 d=x2+y2 の三角形を作ります。
余弦定理から肘の角度が出ます:

cosθ2=x2+y2−l12−l222l1l2

(肘での三角形の内角は 180°−θ2 で、d2=l12+l22−2l1l2cos(180°−θ2) は同じ式です。)
そして肩の角度は、目標の方向から、曲がった腕が其の方向と成す角を引いた物です:

θ1=atan2(y,x)−atan2(l2sinθ2,l1+l2cosθ2)

計算例。 l1=3、l2=2 で、FKの例の手の位置 (3.116,3.432) を目標にします。
d2=3.11572+3.43192=9.708+11.778=21.485 なので

cosθ2=21.485−9−42⋅3⋅2=8.48512=0.7071⇒θ2=±45°

θ2=+45° では、atan2(3.432,3.116)=47.76°、atan2(2⋅0.7071,3+2⋅0.7071)=atan2(1.414,4.414)=17.76° なので、θ1=47.76°−17.76°=30° です。
最初に使った角度が戻って来ました。
θ2=−45° では2つ目のatan2の符号が変わり、θ1=47.76°+17.76°=65.53° です。手の位置は同じで、肘が反対側にあります。

左:l1 = 3、l2 = 2、θ1 = 30°、θ2 = 45°の腕のフォワードキネマティクス。右:同じ手の位置に対するインバースキネマティクス。届く範囲の1から5のリングの中に、肘が下と肘が上の2つの解

解は幾つあるか

計算例は典型的な状況で、cosθ2 の式から全ての場合が分かります:

  • 届かない:cosθ2>1(目標が l1+l2 より遠い)、又は <−1(|l1−l2| より近い)。解は無く、ソルバーは普通、腕を目標の方へ真っ直ぐ伸ばします。此処で届く範囲はリング 1≤d≤5 で、目標 (6,0) は其の外です。
  • 境界上(d=5 又は d=1):解は丁度1つ。腕を伸ばし切るか、畳み切った形です。
  • リングの内側:解は2つ、肘が上と肘が下です。本物の肘は一方向にしか曲がらないので、可動域が片方を選びます。
  • l1=l2 で目標が肩の位置なら、解は無限にあります。

3次元では、2リンクの腕の肘は肩と目標を結ぶ線の周りの円上のどこにでも置けるので、アニメーターは肘(又は膝)が向くべき方向をポールベクターで与えます。
格闘ゲームの脚の2次元のソルバーはOpenGL 第30章で、ポールベクター付きの腕の3次元版はOpenGL 第36章で自分で書きます。

もっと長い連鎖(背骨、尻尾、6関節のロボットアーム)は、目標が必要とするより多い自由度を持ちます。此れが冗長で、解は無限にあります。
其の場合ソルバーには追加の目標が要ります。今の姿勢に近いままでいる、可動域を守る、動きを滑らかに保つ、などです。

反復ソルバー:CCD法

閉じた式の無い連鎖では、IKを小さな段階で解きます。
一番簡単な方法はCCD法(cyclic coordinate descent、巡回座標降下法)です。最後の関節からルートへ向かって関節を順に巡り、各関節を、其処からエンドエフェクタへの線が目標を真っ直ぐ指す様に回します。エフェクタが十分近づくまで此の巡回を繰り返します。

計算例。 腕(l1=3、l2=2)はx軸に沿って真っ直ぐな状態から始まり、手は (5,0) にあります。目標は (2,3) で、手からの距離は 9+9=4.243 です。

  1. 肘((3,0)):手は方向 (2,0)、つまり0°にあり、目標は方向 (−1,3)、atan2(3,−1)=108.43° にあります。肘を108.43°回すと、手は (3+2cos108.43°,2sin108.43°)=(2.368,1.897) に移り、目標から1.162の距離になります。
  2. 肩(原点):手は atan2(1.897,2.368)=38.70°、目標は atan2(3,2)=56.31° にあります。肩を17.60°回すと、手は (1.683,2.524) に移り、目標から0.572の距離になります。

巡回の後 θ1 θ2 手 誤差
1 17.60° 108.43° (1.683, 2.524) 0.572
2 21.20° 94.73° (1.922, 2.884) 0.140
3 22.19° 91.39° (1.977, 2.966) 0.041
4 22.49° 90.42° (1.993, 2.990) 0.012

正確な答え(式から cosθ2=13−1312=0 なので θ2=90°、θ1=56.31°−33.69°=22.62°)に素早く近づいていきます。

2リンクの腕でのCCD法。開始の姿勢、肘を目標の方へ回した後、肩を回した後、4巡の後の姿勢と、残った誤差

CCD法は単純で、どんな長さの連鎖にも使えますが、先端に近い関節から先に丸まる傾向があり、結果が関節を巡る順番に依存します。
人気のある新しい方法のFABRIK(アリスティドゥとラセンビー、2011年)は、角度を回す代わりに関節の位置を連鎖に沿って行き来させて動かし、より自然に見える事が多いです。

ヤコビ行列の考え方

もっと一般的な方法はFKを線型化します。角度の小さな変化 Δ𝜽 に対して、エンドエフェクタは

Δ𝐩≈𝐉Δ𝜽

だけ動きます。ヤコビ行列 𝐉 は、各関節の角度に対するエフェクタの位置の偏微分を、関節ごとに1列ずつ並べた物です。
平面上の 𝐣 にある回転関節の列は、其の関節が回った時のエフェクタの速度で、関節からエフェクタへの線に垂直な (−(hy−jy),hx−jx) です。
上のFKの姿勢では、肩の列は (−3.432,3.116)、肘の列は (−(3.432−1.5),3.116−2.598)=(−1.932,0.518) です。
手を目標の方へ小さな Δ𝐩 だけ動かすには、逆行列(線型代数 第10章)、又は 𝐉 が正方でない時は転置や擬似逆行列で Δ𝜽 を求め、小さく1歩進み、𝐉 を計算し直して繰り返します。
此の 𝐉 の行列式は (−3.432)(0.518)−(−1.932)(3.116)=4.243 で、此れは l1l2sinθ2=6sin45° です。
腕が真っ直ぐ(θ2=0)だと行列式は0になります。腕は手を自分の長さの方向に動かせず、𝐉 は特異になり、素朴なソルバーは震えます。実際のソルバーは其の為に減衰(減衰最小二乗法)を加えます。

FKとIKを一緒に

リグは普通、1本の手足に両方を用意し、FK/IK切り替えを付けます。自由な振り(歩く時の腕)にはFK、接触(机の上の手、床の上の足)にはIKを使い、手が離れる瞬間の為に2つの間をブレンドします。

13.8 スキニング・リギング・フェイシャルアニメーション

スケルトンは目に見えません。
見えるのはメッシュ、つまりスキンで、其れがボーンに付いて行く必要があります。此れがスキニングで、メッシュをスケルトンに結び付ける事をバインドと言います。

剛体バインド

一番簡単な方法は、各頂点を丁度1本のボーンに付ける事で、剛体バインド(リジッドスキニング)と言います。
するとメッシュの各部分は、ロボットや人形の部品の様に、自分のボーンと一緒に剛体として動きます。
関節では破綻します。曲げの外側では部品の間に隙間が開き、内側では重なります。
ロボットや、最初から別々の部品で出来たキャラクタ(OpenGL 第36章の角ばった兵士)なら問題ありませんが、皮膚には向きません。

リニアブレンドスキニング

リニアブレンドスキニング(LBS。スムーススキニング、skeletal subspace deformationとも言います)では、各頂点がウェイト付きで複数のボーンに従います。
メッシュは基本姿勢、つまりバインドポーズでモデリングされ、其の時ボーン j はワールド行列 𝐁j を持ちます。
アニメーションしたポーズでは、ボーン j のワールド行列は 𝐖j です。
頂点 𝐯 を先ず 𝐁j−1 で各ボーンのローカル座標系へ運び、𝐖j でボーンと一緒に動かし、結果を平均します:

𝐯′=∑jwj𝐖j𝐁j−1𝐯,∑jwj=1,wj≥0

𝐁j−1 が一度だけ計算する逆バインド行列で、𝐒j=𝐖j𝐁j−1 がボーンのスキニング行列です。キャラクタがバインドポーズで立っている間は単位行列なので、メッシュはモデリングした場所に留まります。
関節から遠い頂点は自分のボーンにウェイト1を持ち、関節の近くではウェイトが1本のボーンから次のボーンへ滑らかに移ります。
リアルタイムエンジンは普通、1頂点あたり最大4本の影響を許します(glTFではJOINTS_0とWEIGHTS_0に4つずつ保存します)。
此のウェイトをメッシュの上に塗る作業がウェイトペイントで、リガーの仕事の大きな部分です。

第4章の同次座標の3 × 3行列を使った、2次元の計算例です。
ボーン0(上腕)は (0,0) から (2,0) まで、ボーン1(前腕)は (2,0) から先にあり、腕は半径0.5の筒です。
バインドポーズ:𝐁0=𝐈、𝐁1=𝐓(2,0)。
ポーズ:上腕は其の儘で、前腕が肘で90°上に曲がります。𝐖0=𝐈、𝐖1=𝐓(2,0)𝐑(90°)。
肘の外側の頂点 𝐯=(2,−0.5) を、ウェイト w0=w1=0.5 で考えます。

  • ボーン0:𝐒0=𝐈 なので、𝐒0𝐯=(2,−0.5)。
  • ボーン1:𝐁1−1𝐯=(0,−0.5)。𝐑(90°) は (x,y) を (−y,x) に送るので (0.5,0)、𝐓(2,0) で (2.5,0)。
  • 混合:0.5(2,−0.5)+0.5(2.5,0)=(2.25,−0.25)。

頂点は2つの剛体の位置の間に来て、隙間は消えました。
ですが肘 (2,0) からの距離を測ると、0.252+0.252=0.354 で、筒の半径0.5ではありません。
内側の頂点 (2,0.5) は (1.75,0.25) に来て、此れも肘から0.354です。
肘が細くなってしまいました。点を回転した2つのコピーを平均すると回転の中心の方へ引き寄せられるのです。13.4節の行列の線型補間と全く同じです。

90°の曲げで、外側に隙間、内側に重なりが出来る剛体バインドと、滑らかだが細くなるリニアブレンドスキニング

キャンディラッパー現象

関節がボーン自身の軸周りに捻れると、同じ効果がずっと酷くなります。ドアノブを回す前腕の様な場合です。
ボーン1がx軸周りに φ 捻れるとし、関節の位置にある筒の頂点 (2,0,0.5) をウェイト0.5と0.5で考えます。
ボーン1は其れを (2,−0.5sinφ,0.5cosφ) に動かし、混合は

𝐯′=(2,−0.25sinφ,0.25(1+cosφ)),半径=0.5cosφ2

です。
φ=90° なら (2,−0.25,0.25) で半径0.354、φ=180° なら (2,0,0) で半径0です。其の輪の全ての頂点がボーンの上に潰れます。
筒は包装したキャンディの捻った両端の様にくびれるので、キャンディラッパー現象と呼ばれます。

リニアブレンドスキニングした筒を関節で0°、90°、180°捻った物。関節での半径は0.354、0へと縮む

対策:

  • ボーンを増やす:前腕を幾つかのツイストボーンに分けて捻りを分担させ、どの関節も大きく回らない様にします。
  • 補正ブレンドシェイプ:悪いポーズで体積を戻します。
  • デュアルクォータニオンスキニング(カヴァンら、2007年):行列を混ぜる代わりに、ボーンの剛体変換をデュアルクォータニオンとして混ぜます。nlerpの様に回転を正しく混ぜるので半径が保たれます。コストは少し高く、独自のアーティファクト(曲げた関節の小さな膨らみ)があります。第2部で詳しく扱います。

GPUの上で

スキニングは頂点シェーダーで行います。エンジンは現在のポーズのスキニング行列 𝐒j をCPUで計算し(13.6節のFKに逆バインド行列を掛ける)、配列、つまり行列パレットとしてアップロードし、各頂点が自分の4本を混ぜます:

struct JointPalette {
  float4x4 skinning[64]; // S_j = W_j * inverse(B_j) for every joint
};
ConstantBuffer<JointPalette> palette;

// Linear blend skinning of one position with four joint indices and weights (summing to 1).
float3 skinPosition(float3 position, uint4 joints, float4 weights) {
  float4 p = float4(position, 1.0);
  float4 r = weights.x * mul(palette.skinning[joints.x], p)
           + weights.y * mul(palette.skinning[joints.y], p)
           + weights.z * mul(palette.skinning[joints.z], p)
           + weights.w * mul(palette.skinning[joints.w], p);
  return r.xyz;
}
layout(set = 0, binding = 1) uniform JointPalette {
  mat4 skinning[64]; // S_j = W_j * inverse(B_j) for every joint
};

// Linear blend skinning of one position with four joint indices and weights (summing to 1).
vec3 skinPosition(vec3 position, uvec4 joints, vec4 weights) {
  vec4 p = vec4(position, 1.0);
  vec4 r = weights.x * (skinning[joints.x] * p)
         + weights.y * (skinning[joints.y] * p)
         + weights.z * (skinning[joints.z] * p)
         + weights.w * (skinning[joints.w] * p);
  return r.xyz;
}
struct JointPalette {
  float4x4 skinning[64]; // S_j = W_j * inverse(B_j) for every joint
};
ConstantBuffer<JointPalette> palette;

// Linear blend skinning of one position with four joint indices and weights (summing to 1).
float3 skinPosition(float3 position, uint4 joints, float4 weights) {
  float4 p = float4(position, 1.0);
  float4 r = weights.x * mul(palette.skinning[joints.x], p)
           + weights.y * mul(palette.skinning[joints.y], p)
           + weights.z * mul(palette.skinning[joints.z], p)
           + weights.w * mul(palette.skinning[joints.w], p);
  return r.xyz;
}

法線も行列の左上3 × 3の部分で同じ様に混ぜ(ボーンが回転と平行移動だけなら問題ありません)、正規化し直します。
スキニングした位置は、其の後第6章のいつものビュー行列と投影行列を通ります。

リギングとコントローラ

アニメーターは、関節が100個あるスケルトンの生の関節を回したりしません。
リギングで作るリグは、スケルトン、スキンのウェイト、そしてアニメーションし易いコントローラの層から成ります。手足ごとのポールベクター付きのIKハンドル、FK/IK切り替え、かかと・母趾球・つま先を順に持ち上げるフットロール、全ての指を曲げる1本のスライダー、そして「其方を向く」「くっ付いたままでいる」「回転を真似る」と言ったコンストレイント(拘束)です。
コントローラのカスタム属性で他のチャンネルをドライブする事も出来ます。例えば顔のブレンドシェイプの重みです。
アニメーターはコントローラにキーを打ち、リグが其れを関節の回転や形状に変えます。

フェイシャルアニメーション

顔は細かく次元の多い動きを必要とし、主に2つの方法でアニメーションします:

  • ブレンドシェイプ(13.5節):スカルプトした表情を重みで混ぜます。映画や高品質なゲームキャラクタで一番よく使われる方法です。
  • フェイシャルボーン:顔の中に数十個の小さな関節を置き、体と同じ様にスキニングします。保存が安くリターゲットし易いので、ゲームでよく使われます。

シェイプを整理する方法として人気があるのがFACS(Facial Action Coding System。エクマンとフリーセン、1978年)です。目に見える全ての顔の動きを、表情筋に結び付いた番号付きのアクションユニット(AU)の組み合わせとして記述します。例えばAU1「眉の内側を上げる」、AU12「口角を引き上げる」(笑顔)、AU26「顎を下げる」です。
FACSに基づくリグはアクションユニットごとにほぼ1つのブレンドシェイプを持つので、キャプチャした表情もキーで付けた表情も、どの顔でも同じ言葉で記述出来ます。

リップシンクは口の動きを台詞に合わせます。音声を音(音素)に分け、各音を口の形(口形素、viseme)に対応させ、其の形を音声に合わせてキーを打ち、滑らかな遷移で混ぜます。
日本のアニメは伝統的にとても少ない口の形(閉じ・半開き・開きの「口パク」)を使い、吹き替えの3D映画やゲームは10〜20個の口形素のセットを使い、音声から自動生成する事もよくあります。

13.9 モーションキャプチャ

モーションキャプチャ(モーキャプ)は、実際の演者の動きを記録してCGキャラクタに当てはめます。
顔と体を一緒に記録する場合は、パフォーマンスキャプチャと呼ぶ事が多いです。

システムの種類

  • 光学式、マーカー型。演者はマーカー付きのスーツを着て、スタジオの周りの沢山のカメラが其れを捉えます。各マーカーの3次元位置は、2台以上のカメラからの三角測量で求めます(第2章のカメラモデル)。パッシブマーカーは、各カメラのレンズの周りの赤外線ライトで照らされる再帰反射の球です。アクティブマーカーはLEDで、点滅で自分を識別出来ます。とても正確で速い(毎秒100フレームを大きく超える事も多い)ですが、スタジオが必要で、マーカーがカメラから隠れたり(オクルージョン)、互いに取り違えられたりします。
  • 慣性式。各体節に付けた小さなセンサー(IMU:加速度センサーとジャイロ、多くは地磁気センサーも)が其の向きを計測します。カメラもオクルージョンも無く屋外でも使えますが、位置は計測値を積分して求めるので、少しずつドリフトします。
  • マーカーレス、映像型。コンピュータビジョン(今は殆どがニューラルネットワーク)が、1台又は複数台の普通のカメラの映像からスケルトンのポーズを推定します。一番安く邪魔にならず、精度は劣りますが、急速に進歩しています。
  • 昔の機械式(角度センサー付きの外骨格)や磁気式は、今では少なくなりました。

キャプチャからアニメーションへ

生のデータは、使える様になるまで幾つかの段階を通ります:

  1. 整理(クリーンアップ):マーカーが隠れた所の欠けを(13.3節の補間で)埋め、入れ替わったマーカーを直し、ノイズを除きます。
  2. ソルブ:スケルトンをマーカーの位置に合わせます。此れは毎フレーム解くIKの問題(13.7節)です。
  3. リターゲット:動きを体型の違うキャラクタに移します。背の低いトロルや脚の長いエルフです。関節の角度をコピーするだけでは足が滑ったり浮いたりするので、床に着いた足の様な大事な拘束をIKで守ります。
  4. 編集:アニメーターが動きを調整、誇張、修正します。キャプチャの上にキーフレームのずらしを重ねる(アニメーションレイヤー)事が多いです。

動きの混合と再利用

キャプチャした動きもキーで付けた動きもクリップ(歩く、走る、跳ぶ)として保存し、組み合わせます:

  • モーションブレンディング:2つのクリップを関節ごとに重みで混ぜ、回転はslerpで補間します。クロスフェードで歩きが走りに変わります。
  • モーショングラフ(コヴァー、グライヒャー、ピギン、2002年):大量のクリップのデータベースから、1つのクリップから別のクリップへ切り替えられる程ポーズが似ているフレームを探し、可能な遷移のグラフを作ります。こうして新しい長い動きを自動的に繋ぎ合わせられます。最近のゲームは此れを「モーションマッチング」に発展させ、数フレームごとにデータベースの中から一番合うフレームを選んでいます。

ゲームが此れらのクリップをステートマシンやブレンドツリーで毎フレーム再生する方法は、第14章のリアルタイムアニメーションの話です。

検定のポイント

  • FK:関節の角度 → 位置。ルートから階層を下りて計算する。IK:望むエンドエフェクタの位置 → 関節の角度。2リンクの腕の解は0、1、又は2個(余弦定理)。長い連鎖は冗長で、反復法(CCD法、ヤコビ行列)で解く。
  • スキニング:剛体バインド(1頂点に1ボーン)は関節で割れる。リニアブレンドスキニングは複数のスキニング行列 𝐖j𝐁j−1 による位置を、和が1のウェイトで平均し、曲げや捻りで体積を失う(キャンディラッパー)。デュアルクォータニオンスキニングは体積を保つ。
  • ブレンドシェイプはベースからの差分を重み付きで足す。FFDは制御点のラティスで空間を変形する。
  • キーフレーム、モーションキャプチャ、手続き型、物理ベース:誰が動きを決めるか(アニメーター、演者、規則、物理法則)と、制御とリアルさのトレードオフ。
  • モーションキャプチャ:光学式(パッシブ又はアクティブのマーカー)、慣性式、マーカーレス。データには整理、ソルブ、リターゲットが要る。

13.10 まとめ

  • アニメーションは、時間の関数であるシーンから標本化したフレームの連続。映画は24 fps、ビデオは30又は25、ゲームは60以上。モーションブラーは時間方向のプリフィルタ。
  • 数値なら何でもチャンネルとしてアニメーション出来る。シーングラフでは 𝐌world=𝐌world(親)𝐌local により子が親に付いて行く。
  • 制作は絵コンテとレイアウトから、モデリング、リギング、アニメーション、シミュレーションを経て、ライティング、レンダリング、コンポジットへ進む。動きはキーフレーム、キャプチャ、手続き、物理から作る。
  • キーフレームはステップ、線型、又はカトマル・ロムの接線のエルミート曲線で補間する。滑らかなカーブはオーバーシュートし得て、フラット又はクランプの接線で防ぐ。イージング(スムーズステップ)とベジェのタイミングカーブが速さを形作り、弧長の表で経路に沿った動きを均一に出来る。
  • 回転:オイラー角や行列を混ぜない。クォータニオンのslerpは最短の弧に沿って一定の速さで回り、nlerpは安くてほぼ同じ。
  • 形状は形状補間、ブレンドシェイプ(ベース + 重み付きの差分)、パスアニメーション、FFDのラティスでアニメーションする。
  • キャラクタ:関節の階層。FKは角度から位置を、IKは目標から角度を求める(2リンクは解析的に、長い連鎖はCCD法やヤコビ行列の方法で)。
  • スキニングはメッシュをボーンに付ける。剛体バインドは割れ、リニアブレンドスキニングは滑らかだが曲げで細り捻りでくびれる。リグはコントローラ、コンストレイント、ブレンドシェイプを加える。顔はブレンドシェイプかフェイシャルボーン、FACSと口形素を使う。
  • モーションキャプチャは演者を光学式、慣性式、映像から記録する。データを整理、ソルブ、リターゲット、編集し、混ぜて新しい動きにする。

13.11 用語

English 日本語
frame, frame rate フレーム(コマ)、フレームレート
apparent motion 仮現運動
on twos, on threes 2コマ打ち、3コマ打ち
motion blur モーションブラー
structure of CG animation CGアニメーションの構成
channel チャンネル
scene graph, hierarchy シーングラフ、階層構造
storyboard 絵コンテ
keyframe animation キーフレームアニメーション
key キー
key frame, in-between 原画、動画
in-betweening 中割り
interpolation (step, linear) 補間(ステップ補間、線型補間)
function curve, graph editor ファンクションカーブ(Fカーブ)、グラフエディタ
overshoot オーバーシュート
ease-in, ease-out イーズイン、イーズアウト
motion path モーションパス
arc-length parameterization 弧長パラメータ化
gimbal lock ジンバルロック
quaternion クォータニオン(四元数)
spherical linear interpolation (slerp) 球面線型補間(slerp)
shape interpolation, morphing 形状補間、モーフィング
blend shape, morph target ブレンドシェイプ、モーフターゲット
path animation パスアニメーション
free-form deformation (FFD), lattice フリーフォームデフォメーション(FFD)、ラティス
character animation キャラクタのアニメーション
skeleton, bone, joint スケルトン、ボーン、関節(ジョイント)
root ルート
degree of freedom 自由度
forward kinematics (FK) フォワードキネマティクス(順運動学)
inverse kinematics (IK) インバースキネマティクス(逆運動学)
end effector エンドエフェクタ
law of cosines 余弦定理
pole vector ポールベクター
cyclic coordinate descent (CCD) CCD法
Jacobian ヤコビ行列
skinning, binding スキニング、バインド
rigid binding 剛体バインド
linear blend skinning リニアブレンドスキニング
bind pose, inverse bind matrix バインドポーズ、逆バインド行列
weight, weight painting ウェイト、ウェイトペイント
candy-wrapper artifact キャンディラッパー現象
dual quaternion skinning デュアルクォータニオンスキニング
rigging, rig, controller リギング、リグ、コントローラ
constraint コンストレイント
facial animation, FACS フェイシャルアニメーション、FACS
lip sync, viseme リップシンク、口形素
motion capture モーションキャプチャ
optical, inertial, markerless 光学式、慣性式、マーカーレス
retargeting リターゲット
motion blending, motion graph モーションブレンディング、モーショングラフ

13.12 課題

  1. ★ 3.5秒のショットがあります。24、30、60 fpsでは其々何フレームで、24 fpsの2コマ打ちでは絵が何枚要りますか?フレーム90は、24 fpsと60 fpsで其々何秒の時刻に表示されますか?
  2. ★ あるチャンネルにキー(0, 0)、(12, 6)、(24, 12)(フレーム, 値)があり、傾きはカトマル・ロムで、最初と最後のキーは平らです。フレーム6と18の値を、ステップ、線型、スムーズの各補間で求め、フレーム6ではスムーズなカーブが線型より下に、フレーム18では上にある理由を傾きから説明して下さい。
  3. ★★ y軸周りの回転の2つのキーが20°と140°です。両方のクォータニオンを求め、t=0.25 でのslerpとnlerpを計算し、其々の回転角を答えて下さい。次に2つの3 × 3回転行列を半分ずつ混ぜ、結果の行列式を計算して下さい。物体に何が起きますか?
  4. ★★ 腕の長さが l1=4、l2=3 です。目標 (2,6) に対するIKの解を2つとも求め、其々をFKで確かめて下さい。目標 (6,5)、(0.5,0.5)、(0,7) のうち届くのはどれで、解は幾つありますか?
  5. ★★★ リニアブレンドスキニングで、ボーンの軸から距離 r の頂点がウェイト 1−w と w を持ち、2本目のボーンが φ 捻れるとします。混ぜた頂点の軸からの距離が r(1−w)2+w2+2w(1−w)cosφ である事を示し、w を動かした時の最小値を求めて下さい。そして、先に2つの回転を(重み w のslerpで)混ぜてから頂点を回す方法では、決して縮まない理由を説明して下さい。

選択問題

問1 ★ 次のうち、キーフレームアニメーションについて正しい物はどれか。

あ コンピュータがキーポーズを作り、アニメーターが中割りを手で描く。
い カトマル・ロムの様に全てのキーを滑らかに通る補間では、2つのキーの間の値がキーの値の範囲を超える事がある。
う キーを線型補間すると、全てのキーで速さが連続になる。
え ステップ補間は、動きを出来るだけ滑らかにする為に使う。
お イーズイン・イーズアウトは、丁度キーの所で速さを最大にする。

問2 ★ 次のうち、キャラクタアニメーションにおける運動学について正しい物はどれか。

あ フォワードキネマティクスは、エンドエフェクタの位置から関節の角度を計算する。
い 長さ3と2の2リンクの平面の腕は、根元自身を含め、根元から距離5以内の全ての点に届く。
う インバースキネマティクスは、目標がどこであっても必ず丁度1つの解を持つ。
え CCD法は、余弦定理によってどんな連鎖の正確な関節の角度も1段階で求める。
お インバースキネマティクスは、望むエンドエフェクタの位置から関節の角度を計算する。2リンクの平面の腕では、届く目標に対して一般に2つの解(肘が上と肘が下)がある。

問3 ★★ 次のうち、回転の補間とスキニングについて正しい物はどれか。

あ リニアブレンドスキニングでは、頂点は其のボーン達のスキニング行列が与える位置の重み付き平均に動かされ、関節を大きく曲げたり捻ったりすると皮膚の体積が失われる事がある。
い 2つの回転行列の要素を重み0.5と0.5で混ぜると、必ず回転行列になる。
う ジンバルロックはクォータニオンの問題で、オイラー角では起きない。
え 2つの単位クォータニオンの間のslerpは、補間の真ん中で最も速く、両端で最も遅く回る。
お 各頂点が丁度1本のボーンに従う剛体バインドでは、関節で割れの無い滑らかな皮膚になる。

13.13 実践課題

紙の上で、物に手を伸ばす腕を2つの方法でアニメーションし、其の頂点を1つスキニングします。
方眼紙、定規、分度器、鉛筆、2色のペン、電卓を用意して下さい。

腕は上腕 l1=4 と前腕 l2=3 で、肩は原点にあります(1単位 = 2 cm)。
フレーム0では腕はx軸に沿って真っ直ぐで、手は A=(7,0) にあります。
フレーム24では手が B=(3,4) になければなりません。
動きはスムーズステップでイーズイン・イーズアウトします。

  1. Bのキーポーズ。 余弦定理で B に対するIKを解き(解は2つ)、肘が下の解(θ2>0)を選んで、定規と分度器で2つのキーポーズを描いて下さい。
  2. タイミング。 フレーム0、6、12、18、24について、u=f/24 とイージングした割合 s=3u2−2u3 を計算します。
  3. 方法1:関節の角度を補間する(FK)。 5つのフレームの其々で θ1=sθ1B、θ2=sθ2B とし、FKで手の位置を計算してプロットします。5つの手の位置を1色目のペンで結びます。
  4. 方法2:手の位置を補間する(IK)。 各フレームで手の目標を 𝐩=A+s(B−A) とし、IK(肘が下)を解いて腕を描きます。5つの手の位置を2色目のペンで結びます。
  5. 比べる。 2つの手の経路を説明して下さい。コップに手を伸ばす手にはどちらを使い、歩く時に振る腕にはどちらを使いますか?
  6. 頂点を1つスキニングする。 バインドポーズ(腕はx軸に沿って真っ直ぐ)で、肘の外側の (4,−0.5) に頂点があり、上腕のウェイトが0.5、前腕のウェイトが0.5です。𝐁0=𝐈、𝐁1=𝐓(4,0)、𝐖0=𝐑(θ1)、𝐖1=𝐑(θ1)𝐓(4,0)𝐑(θ2) を使い、フレーム24での位置をリニアブレンドスキニングで計算して、図に印を付けて下さい。

自分で確かめる方法:

  • 段階1:|B|=5 なので cosθ2=0 になります。2つの解の其々でFKを計算すると (3,4) に戻り、描いた腕の長さを測ると4と3になる筈です。
  • 段階3と4:両方の経路が A から始まり B で終わります。方法2では全ての手の点が A から B への直線上にあり、届く範囲 1≤d≤7 の中にあり(従って全てのIKの段階に解があり)、各IKの解のFKが其の目標に戻ります。方法1の経路は曲がっていて、キーの間では其の直線上にありません。
  • 段階2〜4:手の位置はフレーム0と24の近くに詰まり、フレーム12の周りで間隔が開きます。13.3節のタイミングチャートと同じです。フレーム12(s=0.5)では、方法1の角度は丁度 θ1B と θ2B の半分です。
  • 段階6:肘が90°曲がっているので、スキニングした頂点は肘から 0.5cos45°≈0.354 の距離にある筈です(13.8節)。


コメント(0)

まだコメントはありません。