FixedUpdateとUpdateごちゃまぜでTransformをいじるとカクつく
VRの諸々もトロッコゲ―も進捗していません。
ここのところは、VRでスクリプトいじった際に、よくVectorとかQuaternionとかアニメーションとか色々必要な知識があるなと実感したので、 とりあえず3Dゲームのサンプルらしきものを見ながら勉強してます。
最近では、以下のAC4系のカメラワーク再現の記事を試してました。
カメラワーク違うだけで、だいぶスピード感というか雰囲気変わるなーと。
カメラをプレイヤーオブジェクトの子にしたり、LerpやLookAtで単に追いかけるだけだと、あそこまでスピード感はちょっと出ない気がします。
それとこの記事を読んだときの所感が、しばらく前にどこかで見た至言「ゲームを思ったように作れるようになるには、自分で考えて分析して実装することを繰り返す」ということの体現なのだなぁと、なんとなく感じました。
「AC4のカメラワークすごいけど、どうやっているのかわかんね(ᐛ) パァ」だった自分が恥ずかしいです。
とりあえず、記事ほぼそのまんまでモデルをSDユニティちゃんにして出来上がったのが以下の感じ。
一応、エフェクト入れたり、デバッグ用のオブジェクト表示してたり、ログ出してたり。 このときはGifアニメでしか録画してなくてサイズ抑えるため画質粗いですが…。
あとPlayerMove.csは記事のままではないです。CharacterController使って移動させてます。 (ついでにカメラの位置もSDユニティちゃんの前に出ないようにしています)
この記事ほぼそのままでSDユニティちゃん動かしてカメラワーク考えてた。カメラがSDユニティちゃんの前に行かないよう制限してみたけど、ちょっと頭が悪い方法だったのでやり方考えよう…
— kb(転職したい) (@job_zero) 2018年1月22日
【Unity5】AC4系のようなカメラワークを再現する - N煎ログブログ https://t.co/XGzOvyB0f3 pic.twitter.com/waxH0D6E6a
実は、これを動かすときに、PlayerMove.csを自前でやったせいで、ぶち当たった問題が動きのカクつきでした。
なんか動きがカクつく
実は動かしている過程で、動きがすごくカクつくときがありました。それが以下の動画です。
FixedUpdateとUpdateごちゃまぜでのカクつき pic.twitter.com/wzLUsg63FS
— kb(転職したい) (@job_zero) 2018年1月29日
ちなみに上の記事にあるサンプルコードを本当にそのまま適用したら、この現象は起きないです。
これが起きたのは、PlayerはUpdateで移動処理しているのに対し、それの動きに合わせて追従させているCameraRotateOriginとMainCameraをFixedUpdateで処理させていたせいです。 (上の参考記事ではプレイヤーオブジェクトの移動はFixedUpdateで行っています。)
図で表すと、以下の関係です。
最初はなんでカクついているのか、さっぱりわかりませんでした。
そのときは、Game画面ではカクついているけれど、Scene画面を見ているかぎりではSDユニティちゃんの動きがカクついているわけではなく、追従させているオブジェクトがカクついているので、最初はLerpの補間具合が粗いのかなと、 ぼやーと思ってました。
ただ、参考記事のPlayerMove.csをそのまま適用するとカクつかず、自前のPlayerMove.csにしたらカクつくので「あっ違う」となりました。
問題はFixedUpdateとUpdateのそれぞれで移動処理していたこと
この辺りは以下の記事が問題解決につながりました。
(最初はLerpについて調べて、うんうん唸っていた)
要は、FixedUpdateとUpdateの呼ばれる周期がズレているせいで、ごちゃまぜにしたら、カクつきが起きやすいようです。 こんな分かりやすい記事、書けるようになりたい。
解決する(滑らかに動いているように見せる)には、
- Rigidbody.interpolationを使うか
- Fixed TimeStepを短くしてFixedUpdateの実行周期を短くするか
というところらしいです。
(ただ、これはFixedUpdateとUpdateどちらも使わざるを得ない状況での場合っぽいです。)
どちらの選択肢も、処理コストが結構かかるので、避けられるのであれば避けた方がよさげでした。
ただ、Fixed TimeStepをかなり短くして描画ズレが起きないよう、実行周期を短くするのはレースゲームやVRゲームでは取られる手法とのことで、場合によっては今後使う場面も出てきそう。
しかしながら今回の場合は、Rigidbodyを使っていないので物理計算はほぼしておらず、そもそもFixedUpdateにする必要がなかったため、FixedUpdateではなく、Updateに統一しただけで大丈夫でした。
選択肢としても①はRigidbodyは使っていなかったので出来ないですし、②も処理コストが結構増える割に、ズレる可能性もあるなぁと…。
また、RigidbodyつけてAddForceしているときは、FixedUpdateに統一すれば大丈夫そうです。
ちなみに直った結果が以下の動画です。ついでにブログでまとめることを機に動画の撮り方とか編集調べたので、最初のGifアニメより画質UP!
FixedUpdateかUpdateのどちらかで統一 pic.twitter.com/OaGcazwUoK
— kb(転職したい) (@job_zero) 2018年1月29日
最後に、②のFixed TimeStepを短くするのを試したのが以下の動画です。結構改善してます。
(Fixed TimeStep:0.02 → 0.001)
値をかなり下げているのは、0.01にしたくらいじゃ大して改善しなかったためです。
FixedUpdateとUpdateごちゃまぜでFixed TimeStepを0.02→0.001に変更 pic.twitter.com/vm72tZLar9
— kb(転職したい) (@job_zero) 2018年1月29日
かなり改善しましたが、厳しめに目を凝らすと少しブレる瞬間があるなぁという感じです。
(追記) Fixed TimeStepを下げるなら、ディスプレイの60Hzに合わせて、1/60の倍数にすべきでした。
ただ、1/60とかにしてもやはり処理が重くなったときはブレたりしていたので、どちらかに統一するのが無難っぽいです。