この記事ではVCIのスクリプトで運動や回転をしたい場合に見て欲しいことを書いていきます。
#内容を3行で
- 速度は直接取る関数はない
- どう頑張っても正確には取れない
- 状況に合わせて工夫するしかない
バーチャルキャストでの速度
バーチャルキャストでは、速度を直接取ることはできないので、フレームごとに位置の差分と微小時間を使って毎度割り算するしかありません。
しかし、これが安定しなくて、どうしても値が1割くらいぶれます。見た目はスムースに移動していても、です。
なのでそのまま使うとかなり挙動がばらついてしまいます。。
VCIで速度を取るとこうなった。平均値1.007,標準偏差0.095真の値は1(m/s)ほんとに1割位ブレる、、、 pic.twitter.com/K6xcUMTwoi
— さっきのなな☆彡vket5 デフォルトキューブ (@sakkinonana) October 8, 2020
それでは困る!という方は次のような方法はいかがでしょうか。
移動平均を取る方法
安直に実装するとフレームでの速度を求める際には直前のフレームとの位置差分だけを使いますが、移動平均というのはその前の速度を記録しておいて(例えば5フレーム分くらい)、それらの平均をとって出力とします。
更新頻度が高くてもそこそこの頻度でそこそこの制度で出力できる方法です。
これでも動作が他の重い処理を伴う動作と競合しがちなものだったりすると、その周りだけ処理落ちして不正確になったりします。
長時間平均を取る方法
単純で効果が大きい方法です。1フレームごとに計算するのではなく、複数フレーム(例えば20フレーム)の差分と時間差とで速度を計算します。
弾丸のように一度放てば等速直線運動するような物体だと使いやすいです。
速度が急激に変わったりすると不正確になるのと、更新頻度が高い場合は不正確になりがちです。
フィルタリングをする方法
いわゆるカルマンフィルタですね。(細かいこと言うと移動平均もフィルタリングなので、ここでは直接速度を測らずに内部パラメーターの推定という意味で使っていますのであしからず)タイミングのズレをノイズ源として等速直線運動や一定の法則に従ったなめらかな運動では抜群の性能を出してくれます。
重力シミュレーターのようにある程度決まっている動きを期待している運動に合わせ込む方法としてはこれが適していると思われます。ただし、実装難易度が高いのと、せっかく物理演算あるのにaddforceを使ったあとの物理的挙動をいちいちハードコードしなければならないのは労力がかかるのがデメリットかも。
なんでこんな事になっているんだろう・・・?
どうやら、lua側でgetPositionとかを読んだときに即座に実行されていないっぽいです。そのせいで時間を呼び出したときと位置を呼び出したときとでタイミングがずれて(処理落ちなど含む)ばらついているようです。
unityで直接ゲームを作ったりするときにはfixed updateというものがあって、それは更新の間隔が決まっているのでその関数の中で位置などを取得するのが定石のようで、現状はバーチャルキャストではこの関数にアクセスできない模様。しばらくは上記のような方法でだましだまし使うしかないですね。。もっといい方法知っている方いらっしゃいましたら教えてくださりますとみんな喜びます。