#author("2026-10-05T18:04:27+09:00","","")
* VMD动作数据格式 [#g7461a49]
&size(13){''モーション・カメラ・照明・セルフ影のキーフレーム構造''};

#contents

** VMD とは [#m6b30781]

''VMD'' は、MMD の''時間変化データ''を格納するフォーマットです。
1 つの VMD に''5 種類のキーフレーム''を格納できます。

|~種類|~内容|~備考|
|ボーン|ボーンの位置・回転|ダンスの中身|
|モーフ|表情の変化|まばたき・口パク|
|カメラ|カメラワーク|''カメラ用として別ファイルにすることが多い''|
|照明|照明の色と向き|全編で 1〜数点|
|セルフ影|セルフシャドウの制御|—|

> '''実務上の慣習''':''モーション用 VMD とカメラ用 VMD を分ける''のが一般的です。
> 理由は単純で、''モーションを差し替えてもカメラを維持できる''からです。

** 全体構造 [#n3e118c5]

#code(){{
┌────────────────────────────┐
│ Header(マジック + モデル名)        │
├────────────────────────────┤
│ ボーンキーフレーム数 + データ        │
├────────────────────────────┤
│ モーフキーフレーム数 + データ        │
├────────────────────────────┤
│ カメラキーフレーム数 + データ        │
├────────────────────────────┤
│ 照明キーフレーム数 + データ          │
├────────────────────────────┤
│ セルフ影キーフレーム数 + データ      │
├────────────────────────────┤
│ (任意)表示・IK キーフレーム        │
└────────────────────────────┘
}}

** Header [#e2fcb475]

|~フィールド|~型|~内容|
|magic|char[30]|`Vocaloid Motion Data 0002`|
|modelName|char[20]|対象モデル名(Shift-JIS)|

*** バージョンの差異 [#eb27690a]

|~世代|~magic|~modelName|
|旧 VMD|`Vocaloid Motion Data file`(25 バイト)|char[10]|
|現行 VMD|`Vocaloid Motion Data 0002`(30 バイト)|char[20]|

> '''実装 tip''':30 バイトを読み、先頭 25 バイトが
> 「Vocaloid Motion Data file」かどうかで判別するのが一般的です。
> 旧形式は''モデル名が 10 バイト''しかない点に注意してください。

*** modelName の扱い [#made8e62]

`modelName` には''そのモーションが想定するモデル名''が入りますが、
''実際の適用時には使われません''。
MMD は''ボーン名''でポーズを適用するためです。

つまり、''modelName が違っても動作します''。
これは「初音ミク用モーションを別キャラに使う」ことを可能にしている仕様です。

** ボーンキーフレーム [#e321bc82]

|~フィールド|~型|~内容|
|boneName|char[15]|''ボーン名''(Shift-JIS)|
|frameNumber|uint32|フレーム番号|
|position|float3|位置オフセット|
|rotation|float4|''クォータニオン''|
|interpolation|byte[64]|補間パラメータ|

*** ボーン名の重要性 [#u1686496]

''VMD はボーン名でポーズを適用します''。
これは MMD の互換性の根幹です。

- ボーン名が一致 → ポーズが乗る
- ボーン名が不一致 → ''そのボーンは無視される''(エラーは出ない)

> '''帰結''':準標準ボーン名に従うことが、
> モデルとモーションの互換性を決めます。
> [[标准骨骼命名规范]] を参照。

*** ボーン名の長さ制限 [#u439a240]

`char[15]` です。つまり''日本語で最大 7 文字''、
半角英数なら 15 文字までです。
''長すぎるボーン名は切り捨てられます''。

*** position の意味 [#dae8e259]

''ボーンの初期位置からの相対移動量''です。
''すべてのボーンが移動できるわけではありません''。
移動可能なのは''移動フラグが立っているボーン''だけです。

*** rotation はクォータニオン [#qe06ee31]

''オイラー角ではありません''。順序は一般的に `(x, y, z, w)` です。

#code(){{
クォータニオン q = (x, y, z, w)
  正規化されている前提
  単位クォータニオン = (0, 0, 0, 1)
}}

> '''実装の注意''':''正規化を忘れると回転が歪みます''。
> また、''クォータニオンの符号反転''(q と -q は同じ回転)を
> 補間時に考慮しないと、''意図しない大回転''が発生します。

*** 補間パラメータ(64 バイト) [#w8daf55c]

''キーフレーム間の変化の仕方''を決めるパラメータです。
4 つのチャンネル(X / Y / Z / 回転)それぞれに
''ベジェ曲線の制御点''が格納されます。

#region(64 バイトのレイアウト)
#code(){{
オフセット 0〜1   : X 軸の X1, Y1
オフセット 4〜5   : Y 軸の X1, Y1
オフセット 8〜9   : Z 軸の X1, Y1
オフセット 12〜13 : 回転の X1, Y1
オフセット 16〜17 : X 軸の X2, Y2
オフセット 20〜21 : Y 軸の X2, Y2
オフセット 24〜25 : Z 軸の X2, Y2
オフセット 28〜29 : 回転の X2, Y2
オフセット 32〜47 : 上記 0〜15 の複製
オフセット 48〜63 : 上記 16〜31 の複製
}}
各チャンネルは 4 バイトの枠を持ちますが、''実際に使うのは 2 バイト''です。
残りは 0 埋め、または線形補間を示す値が入ります。
#endregion

> '''実装の注意''':この 64 バイトの解釈は''実装間で差異があります''。
> 自作する場合は''成熟した実装(MMD Tools 等)のコードを参照''してください。
> 数学的な意味は [[插值曲线详解]] を参照。

** モーフキーフレーム [#r5936bed]

|~フィールド|~型|~内容|
|morphName|char[15]|''モーフ名''|
|frameNumber|uint32|フレーム番号|
|weight|float|''重み(0.0〜1.0)''|

モーフキーフレームには''補間パラメータがありません''。
常に''線形補間''されます。

> '''理由''':表情の変化は線形で十分自然に見えるため、
> 補間曲線を制御する必要がないという設計判断です。

*** モーフ名の重要性 [#v0831d22]

ボーン名と同様、''モーフ名で表情を適用します''。
したがって''標準的なモーフ名''をつけておくと、
既存モーションの表情が''そのまま乗ります''。
[[面部表情与Morph]] を参照。

** カメラキーフレーム [#da72375f]

|~フィールド|~型|~内容|
|frameNumber|uint32|フレーム番号|
|distance|float|''注視点からの距離''|
|position|float3|''注視点の座標''|
|rotation|float3|''オイラー角(弧度)''|
|interpolation|byte[24]|補間パラメータ|
|viewAngle|uint32|''画角(度)''|
|perspectiveFlag|byte|0:透視投影 1:平行投影|

*** カメラの構造(重要) [#o3b1bdf9]

カメラは''注視点''と''距離''と''向き''で表現されます。
これは一般的な 3D ソフトのカメラとは''考え方が異なります''。

#code(){{
カメラ位置 = 注視点 + 距離 × 方向ベクトル
方向ベクトルは rotation(オイラー角)から算出される
}}

> '''利点''':''被写体を中心に回り込む''動きが作りやすい。
> '''欠点''':''注視点を大きく外したい''場合に扱いにくい。

*** rotation はオイラー角 [#xe0f333a]

ボーンがクォータニオンなのに対し、
''カメラはオイラー角''です。しかも''弧度(ラジアン)''です。

*** viewAngle は整数 [#ob337bd7]

''画角は uint32'' で''度''が入ります。
`30` なら 30 度です。_浮動小数点ではありません_。

*** 補間パラメータ(24 バイト) [#t902e303]

''6 チャンネル''分の補間パラメータです。

#code(){{
オフセット 0〜3   : X 軸    (X1, Y1, X2, Y2)
オフセット 4〜7   : Y 軸    (X1, Y1, X2, Y2)
オフセット 8〜11  : Z 軸    (X1, Y1, X2, Y2)
オフセット 12〜15 : 回転    (X1, Y1, X2, Y2)
オフセット 16〜19 : 距離    (X1, Y1, X2, Y2)
オフセット 20〜23 : 画角    (X1, Y1, X2, Y2)
}}

''ボーンの 64 バイトと異なり、各チャンネルが 4 バイトに圧縮''されています。

*** 平行投影 [#v17cf1e4]

`perspectiveFlag = 1` で''平行投影(Orthographic)''になります。
遠近感のない、図面的な映像になります。

** 照明キーフレーム [#i84ae9d1]

|~フィールド|~型|~内容|
|frameNumber|uint32|フレーム番号|
|color|float3|RGB(0〜1)|
|position|float3|''照明の向き''(方向ベクトル)|

> '''注意''':`position` という名前ですが、
> ''照明の位置ではなく方向ベクトル''です。
> 正規化して使われるのが一般的です。

照明キーフレームには''補間パラメータがありません''。

** セルフ影キーフレーム [#o5a98966]

|~フィールド|~型|~内容|
|frameNumber|uint32|フレーム番号|
|mode|byte|0:セルフ影なし 1:セルフ影あり|
|distance|float|''影の距離(範囲)''|

''影の範囲''を時間変化させられます。
これも補間パラメータはありません。

** 表示・IK キーフレーム(任意) [#s4024b02]

VMD 末尾に''オプション''で格納されます。

|~フィールド|~型|~内容|
|frameNumber|uint32|フレーム番号|
|visible|byte|モデルの表示状態|
|ikStateCount|uint32|IK 状態の数|
|(IK 状態)|可変|下記|

#code(){{
for (i = 0; i < ikStateCount; i++) {
    ikBoneName : char[20]
    enabled    : byte      // 0:IK オフ 1:IK オン
}
}}

> '''重要''':このチャンクは''存在しない VMD があります''。
> 読み込み時は''残りバイト数を確認''して、
> 存在すれば読む、という実装が必要です。

** エンディアンとエンコード [#b4a4ecca]

|~項目|~内容|
|エンディアン|リトルエンディアン|
|文字|''Shift-JIS''|
|パディング|char 配列は ''\0 埋め''|

> '''注意''':VMD の文字列は''常に Shift-JIS''です。
> PMX が UTF-8 / UTF-16LE を選べるのとは対照的です。
> ''日本語以外のボーン名''を使うと''文字化け''します。

** 読み書きの実装チェックリスト [#o78782f7]

#region(VMD パーサの注意点)
+ '''magic の 30 バイトを読んで世代を判定する'''
+ '''modelName の長さが世代で異なる'''(10 / 20 バイト)
+ '''ボーン rotation はクォータニオン、カメラ rotation はオイラー角'''
+ '''カメラ rotation は弧度、viewAngle は度'''(単位が混在)
+ '''モーフには補間パラメータが無い'''
+ '''照明の position は方向ベクトル'''
+ '''末尾の表示・IK チャンクは存在しない場合がある'''
+ '''文字列は Shift-JIS'''
+ '''ボーン名は 15 バイト、IK ボーン名は 20 バイト'''(長さが違う)
#endregion

** モーションの適用順序と時間 [#h6c64127]

MMD は''フレーム 0 から順に''キーフレームを評価します。

- ''そのフレームにキーがないボーン''は、''前後のキーから補間''される
- ''フレーム 0 にキーがない''場合は、''ボーンの初期姿勢''が使われる
- ''キーが 1 つもない''ボーンは''初期姿勢のまま''

> '''実務的な落とし穴''':''フレーム 0 のポーズ''が
> 意図せず「初期姿勢」になっているモーションがあります。
> これを避けるには''フレーム 0 に明示的なキー''を打ちます。

** モーションの合成 [#r35766a9]

MMD では''複数の VMD を読み込む''ことができます。

- 後から読み込んだモーションが''上書き''する
- ''ボーン単位で上書き''されるため、
  ''一部のボーンだけ別モーション''という使い方が可能

> '''活用例''':''ダンスモーション + 表情だけ別モーション''。
> 表情(モーフ)はボーンと独立しているため、
> ''モーフのみの VMD''を作って重ねる運用が一般的です。

** 関連ページ [#b625f88e]

- [[VPD姿势数据格式]] — 単一フレームの姿勢
- [[插值曲线详解]] — 補間パラメータの数学
- [[动作制作基础]] — モーションの作り方
- [[数据格式速查表]] — 一覧表

#comment(num=5,noname,below)


トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS