[3D技術史 #03] DQS・PSD — 「潰れ」を騙す数学的トリック

[3D技術史 #03] DQS・PSD — 「潰れ」を騙す数学的トリック

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

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

LBSの壁を超える2つの道

第2部で見た通り、LBS(Linear Blend Skinning)は行列を線形補間するため、大きな回転でボリュームが潰れる「キャンディラッパー現象」が起きる。

この問題に対して、2つの全く異なるアプローチが生まれた。

  • DQS(Dual Quaternion Skinning) — 補間の数学そのものを変える
  • PSD(Pose Space Deformation) — 潰れた結果を力技で補正する

片方は数学的エレガンス、もう片方は実用的な職人技。

どちらも現代の3Dで現役の技術。

Dual Quaternion Skinning(二重四元数スキニング)

クォータニオンの復習

DQSを理解するには、まずクォータニオン(四元数)の性質を押さえる必要がある。

クォータニオンは3D回転を (x, y, z, w) の4成分で表す。

オイラー角(XYZ回転)と違ってジンバルロックが起きず、球面上で滑らかに補間(Slerp)できる。

クォータニオン q = (x, y, z, w)
  - (x, y, z) = 回転軸 × sin(θ/2)
  - w = cos(θ/2)
  - ノルムは常に1(単位クォータニオン)

VRM→PMX変換でも、VMDのボーン回転データはクォータニオンで格納されていた。walk.vmdの左腕キーを解析した時、(qx, qy, qz, qw) = (0.11, 0.19, -0.30, 0.93) といった値が入っており、これをオイラー角に変換して「Z軸に-42度」と特定した。

重要なのは、クォータニオンの補間は回転を保持するということ。2つの回転の中間値を取っても、結果は必ず「回転」であり、スケールが縮んだりしない。LBSが行列を線形補間して潰れたのは、行列の加算が回転の性質を壊すから。クォータニオンならそれが起きない。

二重四元数(Dual Quaternion)とは

通常のクォータニオンは「回転」だけを表す。3Dアニメーションでは回転に加えて平行移動も必要。

ここで登場するのが二重四元数(Dual Quaternion)。

二重四元数 dq = q_r + ε × q_d
  - q_r = 回転部分(通常のクォータニオン)
  - q_d = 平行移動部分(回転と平行移動を同時にエンコード)
  - ε = 二重数の単位(ε² = 0 という性質を持つ)

4×4行列が「回転+平行移動+スケール」を16要素で表すのに対し、二重四元数は「回転+平行移動」を8要素で表す。スケールは含まないが、スキニングでは通常スケール変換は使わないので問題ない。

DQSのアルゴリズム

LBSとDQSの違いは、補間する対象が行列かデュアルクォータニオンかだけ。

LBS:  変形後位置 = Σ (ウェイト_i × ボーン行列_i × 元位置)    ← 行列の加重平均
DQS:  変形後位置 = normalize(Σ (ウェイト_i × DQ_i)) × 元位置  ← DQの加重平均→正規化

決定的な違いは normalize

DQの加重平均を取った後に正規化(ノルムを1に戻す)することで、結果が常に「回転+平行移動」の範囲に収まる。

LBSのようにスケールが縮んでゼロ行列になることが原理的に起きない。

これがDQSがボリュームを保持する理由。

180度の捻りでも、中間の頂点はキャンディ状に潰れず、回転の中間値として滑らかに変形する。

DQSのコード

概念を擬似コードで示す。

function dqsSkinning(vertex, boneIndices, boneWeights, boneDualQuats) {
  // 各ボーンの二重四元数をウェイトで加重平均
  let blendedDQ = DualQuat.zero();
  for (let i = 0; i < 4; i++) {
    const w = boneWeights[i];
    if (w === 0) continue;
    const dq = boneDualQuats[boneIndices[i]];
    // 符号の反転チェック(最短経路補間のため)
    if (dot(blendedDQ.rotation, dq.rotation) < 0) {
      blendedDQ = blendedDQ.add(dq.scale(-w));
    } else {
      blendedDQ = blendedDQ.add(dq.scale(w));
    }
  }
  // 正規化 → 常に有効な剛体変換になる
  blendedDQ = blendedDQ.normalize();
  // 二重四元数で頂点を変換
  return blendedDQ.transformPoint(vertex);
}

「符号の反転チェック」がLBSにはない処理。

クォータニオンは q-q が同じ回転を表すため、加算時に符号を揃えないと最短経路で補間されない。

この処理を忘れると、関節が逆回りに動く不具合が出る。

DQSの弱点

DQSにも弱点はある。

  • 膨らみ(Joint Bulging):
    LBSが「潰れる」のに対し、DQSは逆に関節部分が膨らむことがある。ボリュームは保持されるが、保持されすぎて不自然に太くなる場合がある。

  • 計算コスト:
    LBSより若干重い。行列の加算(16要素)に対し、DQは8要素で軽そうに見えるが、正規化と変換の計算が入るため、実測ではLBSの1.2〜1.5倍程度。

  • 既存パイプラインとの互換性:
    ほとんどの3Dエンジン・フォーマットがLBS前提で設計されているため、DQSを導入するにはシェーダーの書き換えが必要。glTFもVRMもLBS前提。

Pose Space Deformation(PSD)

力技で直す

DQSが「数学を変える」アプローチなら、PSDは「結果を力技で直す」アプローチ。

考え方はシンプル:

特定のポーズで発生する変形の崩れを、あらかじめ用意した補正形状(Corrective Blend Shape)で上書きする。

通常のLBS結果(肘90度曲げ → 内側が凹む)
  + 補正モーフ(肘90度用 → 凹みを膨らませる形状)
  = 自然な見た目

具体例:力こぶ

腕を曲げた時に力こぶが盛り上がる表現を考える。

  1. Tポーズ(基準姿勢)でのメッシュを基準とする
  2. 肘を90度曲げた状態で、上腕の外側が自然に膨らむ補正形状を作る
  3. 肘の角度に応じて、この補正形状を0〜100%でブレンドする
肘 0度   → 補正なし(Tポーズのまま)
肘 45度  → 補正50%適用(少し膨らむ)
肘 90度  → 補正100%適用(完全な力こぶ)
肘 135度 → 別の補正形状に切り替え

この仕組みはモーフターゲット(ブレンドシェイプ)の応用。

VRMの表情モーフ(笑顔・怒り等)と同じ仕組みで、表情の代わりに関節の補正に使う。

PSDの利点と限界

利点:

  • LBSのパイプラインをそのまま使える(シェーダー変更不要)
  • アーティストが見た目を直接コントロールできる
  • 筋肉の盛り上がり、衣服のしわなど、物理的に正確な変形を作れる

限界:

  • 補正形状を全関節×全角度で用意すると、データ量が膨大になる
  • アーティストの手作業が増える(自動化が難しい)
  • 想定外のポーズ(2つの関節が同時に極端に曲がるなど)では補正が効かない

MMDの腕捩りボーン — PSD的な発想

MMDにはPSDの仕組みはないが、腕捩りボーンが似た役割を果たしている。

上腕の捻りを1本のボーンで受けるとキャンディラッパーが起きる。
そこで捻り成分だけを「腕捩1」「腕捩2」「腕捩3」に分散し、各ボーンの回転角を小さくすることで潰れを軽減する。

VRM→PMX変換ツールでこの腕捩りボーンを実装しなかったのは、VRMのウェイトを捩りボーンに再分配する必要があるため。

VRMの上腕にウェイトされた頂点を、「上腕」「腕捩1」「腕捩2」「腕捩3」に位置ベースで按分する必要があり、汎用的に正しく行うのが難しかった。

ただし歩行程度のモーションでは腕の捻りが小さいため、捩りボーンなしでも実用上問題なかった。

LBS・DQS・PSD の使い分け

現代のゲームや映像制作では、3つの技術が場面に応じて使い分けられている。

LBS(線形ブレンドスキニング)
  - 最も軽量、GPU実装が容易
  - ほぼ全てのゲームエンジン・フォーマットが標準サポート
  - 関節の曲げが小さい場合は十分な品質
  - glTF / VRM / PMX は全てLBS前提

DQS(二重四元数スキニング)
  - ボリューム保持が必要な場合(キャラクターの腕捻り等)
  - UnityやUnreal Engineでシェーダーオプションとして選択可能
  - VRChat等のアバター系アプリで採用例あり

PSD(ポーズ空間変形)
  - 映画・シネマティクス等の高品質な変形
  - ゲームでも主要キャラクターの肩・股関節に限定使用
  - Unreal Engine の Pose Driver / Unity の Blend Shape が相当

リアルタイム用途(ゲーム・WebXR)ではLBSが圧倒的に主流。

DQSはオプション、PSDはハイエンド向け。

VRM→PMX変換ツールがLBSだけで実用レベルに達したのは、この「LBSで十分な場面が大半」という現実を反映している。

次回予告

第4部では、スキニング計算がCPUからGPUへ移行した歴史と、その結果生まれたデータ構造の制約(なぜ1頂点あたり4ボーンなのか)、そして現代の標準フォーマット(glTF / USD)がスキニングデータをどう保持しているかを扱う。

VRM→PMX変換で JOINTS_0 / WEIGHTS_0 から頂点ウェイトを読み出した実体験と合わせて、「フォーマットの設計思想」を紐解く。