MMD on WebGL カメラとライトと表情のモーションに対応(あと補間曲線について)
タイトルの通りです。VMD を読み込んだり、CoffeeScript で全部書きなおしてたりしたら時間がかかってしまいました。
- http://edv.sakura.ne.jp/mmd/ (10月16日現在、開くと動き始めるはずです)
ここからが本題。
補間曲線について
MMD の補間曲線はベジエ曲線で、ベジエ曲線に必要な4つの点のうち、最初と最後が固定されている。すなわち、
こんな感じ。
を表す4つの数字は VMD ファイルに0から127までの整数として記録されていて、これらを127で割ってそれぞれの座標とする。
また、例えば登録されているキーフレームが10と20だったとして、13番目のフレームを描画したいとすると、 となる。
この5つの数字からまず を求め、次に
を求めるのだが、
を求めるためには三次方程式を解かなければいけない。
幸いにして、この は常に(
によらず)単調増加らしい。厳密に証明したわけではないが、MMD の補間曲線のところでバツ印をどのように動かしても、
と
について「いったん上がってまた下がる」ということが無いことから推測できる。
が単調増加であると仮定すると、
を満たす
はひとつしか無く、二分法やニュートン法で求められる。
自分は収束が早いとされるニュートン法ではなく、二分法を使った。その理由は以下のとおり。
まず仮に を1/2と置き、
を計算し、それが正ならば
から1/4を引いて、負ならば1/4を足して、再度
を計算する。このように1/8, 1/16, 1/32…と進んでいくのだが、求められる精度は1/65536もあれば十分だと思うので、15回ほどの繰り返せば十分に収束したとみなすことができる。二分法の収束が遅くても、高々15回ぐらいの繰り返しなので問題ない。
なんせ10分の動画でも 10 min * 60 sec * 30 fps = 18000 frames しかないので、10分の動画の最初から最後までを一つのベジエ曲線で補間したとしても、隣り合うフレーム同士は1/18000の精度でしか離れてないことになる。
そんなわけでアルゴリズムを載せておく。
function interpolateBezier(x1, x2, y1, y2, x) { var t = 0.5, s = 0.5; for (var i = 0; i < 15; i++) { var ft = (3 * s * s * t * x1) + (3 * s * t * t * x2) + (t * t * t) - x; if (ft === 0) break; // Math.abs(ft) < 0.00001 でもいいかも if (ft > 0) t -= 1 / (4 << i); else // ft < 0 t += 1 / (4 << i); s = 1 - t; } return (3 * s * s * t * y1) + (3 * s * t * t * y2) + (t * t * t); }
MMDAgent はニュートン法でやってるみたい。Chrome と Opera と IE9 ではそっちのほうが早かった。Firefox では逆。と言っても100万回で200ミリ秒ぐらいの違いしかないけど→http://jsfiddle.net/km96k/
ところで、カメラモーションの場合は補間用のパラメータが24個( のペアが「X軸移動」「Y軸移動」「Z軸移動」「回転」「距離」「視野角」について、この順番にそれぞれ)あるのだけど、
ボーンの場合はパラメーターが64個あって、これはどういう内訳になってるんだろう?
あった。VMDメモ 針金のブログ/ウェブリブログ(というか数字眺めてたら分かった。なんでこんなふうになってるんだろ)


