VMDの補間曲線64バイトの読み方|Z移動と回転のx1は1行目に無い
VMDのボーンのキーフレームには、4項目(X移動・Y移動・Z移動・回転)の補間曲線が64バイトで入っています。「先頭16バイトだけ読めばよい」と説明されることが多いのですが、実物を数えると、1行目のうち2バイトは本当の値ではありませんでした。そこを読むと、回転の緩急が変わります。
このサイトの再生と書き出しは、2026-10-07からこの読み方に直しています。 それまでは three.js と同じく1行目を読んでいて、自前の書き出しもZ移動と回転の x1 を0で書いていました。
64バイトの並び
1つの曲線は3次ベジェの制御点2つ (x1, y1)・(x2, y2) で、値は0〜127です(127が1.0)。4項目ぶんで16個の値になり、1行目にはこう並びます。
| 1行目の位置 | 中身 |
|---|---|
| [0]〜[3] | x1(X移動・Y移動・Z移動・回転の順) |
| [4]〜[7] | y1(同じ順) |
| [8]〜[11] | x2(同じ順) |
| [12]〜[15] | y2(同じ順) |
2〜4行目は、1行目を1バイトずつ左へずらした写しです。実物で確かめると、写しが1行目と食い違う場所は1行目の [2]・[3] の写しにあたる5か所([17]・[18]・[32]・[33]・[48])だけで、ほかは全件一致していました。
1行目の [2]・[3] は全部0
実物30本・255,380件のキーで、1行目の 2と 3は1件残らず0でした。一方、2行目の写しにあたる [17] は143,385件、[18] は134,552件で、0以外の値を持っています。
どちらが本当の値かは、MMDが新しいキーに入れる「直線」を見ると分かります。実物でいちばん多かった64バイト(68,138件)は次のとおりです。
20, 20, 0, 0, 20, 20, 20, 20, 107,107,107,107,107,107,107,107
20, 20, 20, 20, 20, 20, 20,107, 107,107,107,107,107,107,107, 0
20, 20, 20, 20, 20, 20,107,107, 107,107,107,107,107,107, 0, 0
20, 20, 20, 20, 20,107,107,107, 107,107,107,107,107, 0, 0, 0X移動とY移動は (20, 20)-(107, 107) で、対角線上の直線です。1行目の0を信じると、Z移動と回転だけ (0, 20)-(107, 107) という直線でない曲線になります。写しの20を読めば、4項目とも同じ直線になります。Z移動と回転の x1 は、写しの [17]・[18] から読むのが正しいと判断しました(MMDが1行目の2バイトを何に使っているかは、ここでは確かめていません)。
- 残りの写しも同じ値を持っています([32]=[17]、[33]=[48]=[18])
- 64バイトがすべて0のキーも37,189件ありました。制御点が (0, 0)-(0, 0) の曲線は直線になるので、読み方で結果は変わりません
three.jsのMMDLoaderは0の方を読む
three.js(r171)の MMDLoader は、項目 i の x1 を interpolation[i] から読みます。X移動・Y移動はそれで正しいのですが、Z移動と回転は常に x1 = 0 として補間されます。
どれくらい変わるかを、実物30本で見積もりました。同じボーンの隣り合うキーの組は250,950あり、1フレームしか離れていない組を除いて、回転の曲線が食い違う組が124,560ありました。補間の進み具合の差の最大値に、2つのキーの間の回転角を掛けた値で見ると次のとおりです。
| 回転のずれ(見積もり) | 値 |
|---|---|
| 中央値 | 1.29° |
| 上位10% | 10.0°以上 |
| 上位1% | 44.2°以上 |
| 最大 | 83.2° |
| 5°を超える組 | 25,544 |
MMDの既定の直線でも、x1 を0で読むと進み具合が最大0.070(区間の22%あたり)ずれます。作者が回転の緩急を付けたキーほど差が大きくなり、ダンスの止め・溜めの位置がずれて見えます。Z移動の位置のずれは、ほとんどが0で、最大3.56ユニットでした。
直し方
- 読むとき: Z移動と回転の x1 だけ [17]・[18] から読む。ほかの14個は1行目のままでよい
- three.jsに渡すとき: VMDのバイト列を写し、各キーの [2]・[3] へ [17]・[18] の値を入れてから MMDLoader に渡す。three.js のコードには手を入れずに済みます
- 書くとき: 上のMMDの64バイトをそのまま使う。1行目をずらして写すと、1行目の0が写しにも入り、MMDで読み直したときにZ移動と回転が直線でなくなります
カメラのキーの補間曲線(24バイト)はずらし書きをしていない別の並びなので、この話は当てはまりません(カメラVMDの中身)。