#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)