[3D技術史 #03] DQS・PSD — 「潰れ」を騙す数学的トリック
この記事は「スキニング&リギング技術史」4部構成の第3部です。
- セグメントアニメーション — 関節がバラバラだった時代
- Linear Blend Skinning — メッシュが繋がった革命と「潰れ」の壁
- DQS・PSD(本記事) — 潰れを騙す数学的トリック
- GPU時代のリアルタイムスキニングと標準フォーマット
LBSの壁を超える2つの道
第2部で見た通り、LBS(Linear Blend Skinning)は行列を線形補間するため、大きな回転でボリュームが潰れる「キャンディラッパー現象」が起きる。
この問題に対して、2つの全く異なるアプローチが生まれた。
- DQS(Dual Quaternion Skinning) — 補間の数学そのものを変える
- PSD(Pose Space Deformation) — 潰れた結果を力技で補正する
Dual quaternion - Wikipedia
In mathematics, the dual quaternions are an 8-dimensional real algebra isomorphic to the tensor product of the quaternions and the dual numbers. Thus, they may be constructed in the same way as the quaternions, except using dual numbers instead of real numbers as coefficients.
en.wikipedia.org
Pose space deformation - Wikipedia
Pose space deformation is a computer animation technique which is used to deform a mesh on skeleton-driven animation. Common use of this technique is to deform the shape of a mesh (for example, an arm) according to the angle of the joint (in this case, the elbow) bent.
en.wikipedia.org片方は数学的エレガンス、もう片方は実用的な職人技。
どちらも現代の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度用 → 凹みを膨らませる形状)
= 自然な見た目
具体例:力こぶ
腕を曲げた時に力こぶが盛り上がる表現を考える。
- Tポーズ(基準姿勢)でのメッシュを基準とする
- 肘を90度曲げた状態で、上腕の外側が自然に膨らむ補正形状を作る
- 肘の角度に応じて、この補正形状を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 から頂点ウェイトを読み出した実体験と合わせて、「フォーマットの設計思想」を紐解く。