Unityでカメラが近づくと角度によりモデル(の一部)が突然消える
カメラが近づくとモデルが突然消えた……
こうだったのが突然……
ギャー
どうすればモデルが消えなくなるか
Unityでカメラが近づきすぎるとモデルが消えるパターンとしてはまずカメラに設定してある「NearClip(CameraのClipping PlanesのNear)」が大きすぎるというのがある。特にVRなどでは顔を近づけてもギリギリまで描画して欲しいので、NearClipは小さめにする。
が、NearClipを小さめにしていても、モデル(の一部)が突然消える現象がある。
カメラが遠い場合は発生しないが、ある程度近づくとカメラの角度により突然消える。しかも再登場するときはDynamicBoneなどがボヨンボヨンするので、表示が消えていただけでなく動作自体が止まっていることがうかがえる。
これは、以下のブログの記述にある通り、「skinnedMeshRenderer」の「update whenoffscreen」をONにすればよい。
より適切な解決方法
「update whenoffscreen」をONにするのは簡単でよいのだが、名前の通り「見えないときも処理を行う」ことになってしまうのでキャラがたくさん出てくるゲームなどでは問題になる。
で、より適切な解決方法としては「skinnedMeshRenderer」の「Bounds」の「Extent」を大きくすれば良いとのこと。
update whenoffscreenはカメラ外でも常に描画処理をしてしまうので、RendererのBounds設定を見直すほうがいいかもです。https://t.co/Mbr3uiA1fr
— オノッチ (@onotchi_) 2018年8月7日
人生で3回くらいググったのでTwitterに書いておくとUnityのSkinnedMeshRendererのメッシュがカメラの位置や角度によって、まだ見えているのにカリング(Culling)されてしまうときはSkinnedMeshRendererのBoundsのExtentを大きくしような!
— izm (@izm) 2018年7月29日
(onotchiさん、izmさん、説明頂きありがとうございますm(__)m )
なんでそんなことになるのか
じゃあなんで「Bounds」の値が適切じゃない=カメラの中にいるはずなのに非表示になるような値になっちゃってるのかというと、こういうことらしい。
挙動については公式マニュアルに詳しく書いてあって一読すると便利かもです!(Bounds はメッシュ、アニメーションインポート時に計算されていて、それ以外の VR でよくある手動でボーンのトランスフォームをいじる時や、加算アニメーション再生時等に適切な値に要手動調整)https://t.co/c5x620txk4
— 凹 (@hecomi) 2018年7月31日
(さすが@hecomiさん)
オブジェクトのビジビリティはメッシュの Bounds によって決定されます (言い換えると、全体のバウンディングボリュームはあらゆる有効なカメラの視界角外にある必要があります)。ただし、アニメーションしているメッシュの実際のバウンディングボリュームは、アニメーションの再生によって変化します (例えば、キャラクターが手を頭上に伸ばすと、ボリュームの高さが増えます)。Unity は、すべてのアタッチされたアニメーションが最大のバウンディングボリュームになるときを考慮しますが、すべての使用可能な状況を予想してバウンディングボリュームを計算することは、不可能な場合があります。
以下のような状況では、ボーンや頂点が事前計算されたバウンディングボリュームの外に押し出されてしまい、問題が生じます。
ランタイム時にアニメーションを追加する場合
要するに、動きのあるモデルの場合は最初に想定したモデルのサイズよりも大きい形になってしまう。
だからカメラの中にいるのに外にいると判断されることがあると。
「Update When Offscreen」にも使い所あり?
Extentを編集するのもモデルが増えてくると大変だし、どれくらいの数字が適切なのかも難しいし、
これらの例では、2 つの解決方法があります。
Bounds (境界) を修正してメッシュの可能なバウンディングボリュームに適合するように修正します。
Update When Offscreen をスキンに対して有効にし、常にスキンメッシュをレンダリングします。
通常は、パフォーマンスに与える影響も少ないため最初の方法を選択します。ただし、パフォーマンスを重視する必要がない場合や、バウンディングボリュームを予測できない場合 (例えばラグドール物理を使用する場合) に、2 番目の方法を選択します。
とUnity公式さんも言っているので、Unityで動画を撮るだけみたいなケースでは「Update When Offscreen」を使うのも良さそうだ。