[3D技術史 #01] セグメントアニメーション — 関節がバラバラだった時代のリアルタイム3D

[3D技術史 #01] セグメントアニメーション — 関節がバラバラだった時代のリアルタイム3D

この記事は「スキニング&リギング技術史」4部構成の第1部です。

  1. セグメントアニメーション(本記事) — 関節がバラバラだった時代
  2. Linear Blend Skinning — メッシュが繋がった革命と「潰れ」の壁
  3. DQS・PSD — 潰れを騙す数学的トリック
  4. GPU時代のリアルタイムスキニングと標準フォーマット

3Dキャラクターの最初の課題:体を動かすこと

2026年の今、VRMモデルをブラウザで読み込めば、150本以上のボーンが滑らかにメッシュを変形させて、歩行モーションが破綻なく再生される。

しかし1990年代前半、リアルタイム3Dのキャラクターは「1つの繋がった体」を持っていなかった。

当時の3Dキャラクターは、頭・胴体・上腕・前腕・手・太もも・すね・足といったパーツがそれぞれ独立した剛体(Rigid Body)として存在していた。
関節で「繋がって」いるように見えるが、実際にはパーツ同士が親子関係で配置されているだけで、メッシュとしては完全に分離していた。

セグメントアニメーションの仕組み

剛体階層モデル

1つのキャラクターが10〜20個のパーツ(セグメント)に分割される。

各パーツは独立したメッシュで、親パーツとの接続点(ピボット)を基準に回転する。

胴体(ルート)
├── 頭
├── 左上腕
│   └── 左前腕
│       └── 左手
├── 右上腕
│   └── 右前腕
│       └── 右手
├── 左太もも
│   └── 左すね
│       └── 左足
└── 右太もも
    └── 右すね
        └── 右足

この構造はツリー(木構造)で、各ノードが1つの剛体パーツを表す。
ルート(胴体)から末端(手・足)へ向かって親子関係が定義されている。

FK(Forward Kinematics:正運動学)

各パーツの動きはFK(正運動学)で計算される。
親から子へ、順番に変換行列を掛けていく方式。

最終位置 = ルート行列 × 肩の回転行列 × 上腕の回転行列 × 前腕の回転行列 × 手のローカル位置

例えば「右手を上げる」アニメーションでは:

  1. 胴体のワールド行列を決める
  2. 右肩の回転行列を胴体に掛ける → 右肩のワールド行列
  3. 右上腕の回転行列を右肩に掛ける → 右上腕のワールド行列
  4. 右前腕の回転行列を右上腕に掛ける → 右前腕のワールド行列

この「親の行列に自分の回転を掛けて、子に渡す」連鎖がFKの本質。コードで書くと:

function updateBoneChain(bone, parentMatrix) {
  // 自分のローカル変換(回転・平行移動)を親のワールド行列に掛ける
  bone.worldMatrix = parentMatrix * bone.localMatrix;

  // 子ボーンに自分のワールド行列を渡す
  for (const child of bone.children) {
    updateBoneChain(child, bone.worldMatrix);
  }
}
// ルートから再帰的に呼ぶ
updateBoneChain(rootBone, identityMatrix);

この再帰的な行列の伝播は、Three.jsの updateMatrixWorld(true) が内部でやっていることと本質的に同じ。

計算コスト

FKの計算量はボーン数に対して線形 — O(n)。1990年代前半のCPU(数十MHz)でも、10〜20パーツなら毎フレーム計算できた。

行列の掛け算は4×4=16要素の積和演算で、1パーツあたり数十の乗算・加算。20パーツでも数百回の演算で済む。

当時のゲームが扱っていた頂点数は1キャラクターあたり数百〜千。
現代のVRMモデル(14万頂点)とは2桁以上違う。

少ない頂点を少ないパーツで動かす — それが当時のリアルタイム3Dの限界であり、合理的な選択だった。

剛体モデルの限界:関節の隙間問題

セグメントアニメーションには根本的な問題があった。

関節を曲げると、パーツ間に隙間が生じるか、パーツ同士が貫通する。

隙間が見える

肘を90度曲げると、上腕パーツと前腕パーツの接続部分に隙間ができる。
中が空洞であることが露呈し、キャラクターの体が「張りぼて」であることが一目で分かってしまう。

パーツが貫通する

隙間を隠すためにパーツ同士を重ねて配置すると、今度は曲げた時にポリゴンが互いに突き抜ける。
どちらの面が手前に描画されるかはZバッファの精度次第で、チラつき(Zファイト)が発生する。

対症療法

当時のゲーム開発者はこの問題に様々な対処をしていた。

  • 関節部分を太くする:
    パーツ端を膨らませて、曲げた時に隙間が見えにくくする。ただし見た目が太くなる

  • 関節の可動範囲を制限する:
    肘を90度以上曲げないようにアニメーションを制約する

  • カメラを引く:
    関節の粗が目立たないように、キャラクターを小さく映す

  • テクスチャで誤魔化す:
    関節部分を暗い色にして隙間を目立たなくする

どれも根本的な解決ではなく、「隙間が見えることを前提に、いかに目立たなくするか」という工夫だった。

当時のゲームに見る剛体モデル

バーチャファイター(1993年)

セガの『バーチャファイター1』は、リアルタイム3D格闘ゲームの先駆けだった。キャラクターは明確にパーツ分割されており、関節を曲げた時の隙間や貫通が見える。しかし当時としては「3Dで人間が動いている」こと自体が衝撃で、隙間は許容されていた。

初代プレイステーション(1994年〜)

PS1時代の3Dゲームは、ほぼ全てがこのセグメントアニメーション方式。

1キャラクターの総ポリゴン数は200〜500程度。

関節の表現は限定的で、多くのゲームが「ポリゴンの少なさ」と「関節の隙間」の両方と戦っていた。

トイ・ストーリー(1995年)

ピクサーの映画ではリアルタイムではないが、ウッディやバズの体もパーツ分割されたモデルだった。

ただしプリレンダリングなので、レイトレーシングや高品質なテクスチャで関節の粗を隠せた。

リアルタイム3Dにはその余裕がなかった。

FKの限界と逆運動学(IK)の萌芽

FKは「親から子へ」行列を掛ける方式だが、これだと末端の位置を指定して動かすのが難しい。

例えば「足をこの位置に置きたい」と思っても、FKでは腰・太もも・すねの回転を手動で調整して、結果として足がその位置に来るように合わせる必要がある。

ここで登場するのがIK(Inverse Kinematics:逆運動学)。

末端の目標位置を指定すると、関節チェーンの各回転を自動計算して末端をそこに到達させる。

IKは1960年代にロボット工学で発展した技術で、3DCGに持ち込まれたのは1980年代。

リアルタイムゲームで実用化されるのはもう少し後の話になるが、FKだけでキャラクターアニメーションを作ることの限界は、この剛体時代に既に明らかだった。

後にMMD(MikuMikuDance)がIKを標準搭載し、足IKで歩行モーションを駆動する方式を採用したのは、FKだけでは足の接地を制御しきれないという、この時代からの課題に対する解答でもある。

この時代の遺産 — 現代にも残る構造

剛体階層モデルとFKは「古い技術」だが、現代の3Dアニメーションの基盤として今も生きている。

ボーン階層はFKそのもの

VRM・PMX・glTF、あらゆる3Dフォーマットのボーン構造は、この剛体時代のFK階層と同じツリー構造を持つ。

親から子へ行列を掛けていく仕組みは何も変わっていない。

Three.jsの Object3D.updateMatrixWorld() が再帰的に子をたどるのは、1990年代のFKコードと本質的に同じ処理。

スキニングは「この上に乗った」技術

次の時代(第2部で扱う)に登場するスキニングは、剛体階層モデルを置き換えたのではなく、その上に乗った技術。

ボーンのFK階層は残したまま、パーツ分割されたメッシュを「1つの連続したメッシュ」に変え、各頂点がどのボーンからどれだけ影響を受けるかを重み(ウェイト)で定義した。

つまり剛体時代の「パーツ → ボーン」という1:1対応を、「頂点 → 複数ボーン」という多:多対応に拡張したのがスキニング。

骨格そのものは変わらない。

VRM→PMX変換で体験した「現代のFK」

VRM→PMX変換ツールを実装した際、Aスタンス化のために腕ボーンを40度回転させ、updateMatrixWorld(true) で子ボーンに伝播させた。

これはまさにFKの伝播そのものだった。親(上腕)を回転させると、子(前腕→手首→指)が全て追従する。

ただし、Three.jsの内部でthree-vrmがボーン姿勢をリセットしてしまい、指が追従しない問題に遭遇した — FK伝播が「正しく動く前提」は、現代でも実装上保証されているわけではない。

次回予告

第2部では、この剛体モデルの限界を打ち破ったLinear Blend Skinning(LBS)を扱う。

「1つの連続したメッシュを、複数のボーンで滑らかに変形させる」技術がどう登場し、どんな新しい問題(キャンディラッパー現象)を生んだのか。

そしてVRM→PMX変換で実際にLBSの行列計算を手書きした体験と合わせて解説する。

関連記事