FK/IK・スキニングエディタ
フォワード/インバースキネマティクスとスキニングのエディタ、Unity Foot-IK プラグイン付き
概要
コンピュータアニメーションの授業で C++ と OpenGL で書いた FK/IK とスキニングのプロジェクトです:フォワードキネマティクス、limb-based IK ソルバー、CCD IK ソルバー、そしてリニアブレンドスキニングによる自動スキンバインディング。同じコアを Unity のネイティブプラグインとしてもコンパイルして、歩くキャラクターに地形適応の Foot IK をやらせています。
フォワードキネマティクス
スケルトンはジョイントのツリーです。各ジョイントは親に対する相対変換だけを持ち、FK はルートからツリーを辿って、各ジョイントのローカル変換に親のワールド変換を掛け、グローバルな位置と姿勢を求めます。2 つの IK ソルバー、スキニング、Unity プラグインはすべてこのワールド変換を読むので、どこかのローカル回転を 1 つ変えれば、その下のサブツリー全体が動きます。
Limb-Based IK
手と足には解析的な 2 ボーンソルバーを使います。根元のジョイント、真ん中のジョイント、ターゲットが三角形を作るので、肘や膝の角度は余弦定理からそのまま出ます。根元からターゲットまでの距離はチェーンの全長でクランプします:届かないターゲットに対しては手足がまっすぐ伸びるだけで、NaN は出ません。そのあと根元のジョイントでもう一度軸角回転をかけて手足全体を振り、エンドエフェクタをターゲットに乗せます。
CCD IK
Cyclic Coordinate Descent はどんな長さのチェーンにも使えて、エンドエフェクタからルートまでの全経路も扱えます。1 パスはチェーンの先端からルート側へ戻っていきます:
- 今のエンドエフェクタの位置をターゲットの方へ回すための軸と角度を、グローバル空間で求める。
- その軸をジョイントのローカル座標系に変換する。
- クォータニオンの差分として適用し、親へ進む。
エンドエフェクタがターゲットの許容範囲に入るまでパスを繰り返します。limb ソルバーのような閉形式の保証はありませんが、背骨やしっぽのようなものを曲げられますし、先端から掃いていくので、動きが根元に集中せずチェーン全体に分散します。
スキンバインディング
バインディングでは全頂点にジョイントのウェイトを自動で割り当てます。各ジョイントは、いちばん近い頂点までの距離にユーザー指定の係数を掛けたバインディング半径を持ちます。各頂点について:
- いちばん近いジョイントを探す。
- そのジョイントから親へ向かうボーンに頂点を投影する。これでジョイントのどちら側にいるかが決まる。
- 半径の内側なら、正規化した距離でジョイントと親の間をリニアにブレンドする。外側ならどちらか一方に完全に寄せる。
この減衰がないと 2 本のボーンの影響が硬い境界で切り替わり、肘や膝に折り目が出ます。
リニアブレンドスキニング
バインド時に各ジョイントのグローバル変換の逆行列をバインド行列として保存します。これは頂点をモデル空間からそのジョイントのローカル空間へ持っていく行列です。毎フレーム、各頂点は自分への影響を足し合わせます:
newPosition = sum( weight_i * (jointGlobal_i * bindMatrix_i) * restPosition )
各項は頂点をバインドポーズからジョイント空間へ持ち込み、ジョイントの現在のポーズを通して戻します。どのボーンの動きをどれだけ受け取るかはウェイトが決めます。法線は各行列の回転成分だけを使って同じ和を通すので、メッシュが変形してもライティングは正しいままです。
Unity Foot-IK プラグイン
C++ コアは Unity のネイティブプラグインとしてコンパイルされ、起伏のある地形を歩くキャラクターを駆動します。地面に投影したガイドジョイントがキャラクターをターゲットの方へ導き、進行方向は最短弧クォータニオンで回します。毎フレーム:
- 各足の下の地形の高さをサンプリングする。
- 2 つの高さのうち低い方までルートを下げる。これで支持脚が届く範囲を超えて伸ばされることはなくなる。
- 各脚に limb IK ソルバーを走らせ、足をそれぞれの接地点まで引き下ろす。
- オプションで、各足を接地点の地形の法線に合わせて回転させる。
使用ツール
C++、OpenGL、Eigen、ImGui、Unity、CMake