サークル獏の佐藤敏 Unityとか備忘録

サークル獏の佐藤敏がUnityとかで知ったTipsを書いておく備忘録です。

Unityでカメラが近づくと角度によりモデル(の一部)が突然消える

カメラが近づくとモデルが突然消えた……

f:id:VinSatoo:20180813150726p:plain:w150
こうだったのが突然……
 
f:id:VinSatoo:20180813150522p:plain:w150
ギャー
 

どうすればモデルが消えなくなるか

Unityでカメラが近づきすぎるとモデルが消えるパターンとしてはまずカメラに設定してある「NearClip(CameraのClipping PlanesのNear)」が大きすぎるというのがある。特にVRなどでは顔を近づけてもギリギリまで描画して欲しいので、NearClipは小さめにする。

が、NearClipを小さめにしていても、モデル(の一部)が突然消える現象がある。
カメラが遠い場合は発生しないが、ある程度近づくとカメラの角度により突然消える。しかも再登場するときはDynamicBoneなどがボヨンボヨンするので、表示が消えていただけでなく動作自体が止まっていることがうかがえる。

これは、以下のブログの記述にある通り、「skinnedMeshRenderer」の「update whenoffscreen」をONにすればよい。

testaa.ryorika.com
 
 

より適切な解決方法

「update whenoffscreen」をONにするのは簡単でよいのだが、名前の通り「見えないときも処理を行う」ことになってしまうのでキャラがたくさん出てくるゲームなどでは問題になる。
で、より適切な解決方法としては「skinnedMeshRenderer」の「Bounds」の「Extent」を大きくすれば良いとのこと。



(onotchiさん、izmさん、説明頂きありがとうございますm(__)m )
 
 

なんでそんなことになるのか

じゃあなんで「Bounds」の値が適切じゃない=カメラの中にいるはずなのに非表示になるような値になっちゃってるのかというと、こういうことらしい。


(さすが@hecomiさん)

docs.unity3d.com

オブジェクトのビジビリティはメッシュの Bounds によって決定されます (言い換えると、全体のバウンディングボリュームはあらゆる有効なカメラの視界角外にある必要があります)。ただし、アニメーションしているメッシュの実際のバウンディングボリュームは、アニメーションの再生によって変化します (例えば、キャラクターが手を頭上に伸ばすと、ボリュームの高さが増えます)。Unity は、すべてのアタッチされたアニメーションが最大のバウンディングボリュームになるときを考慮しますが、すべての使用可能な状況を予想してバウンディングボリュームを計算することは、不可能な場合があります。

以下のような状況では、ボーンや頂点が事前計算されたバウンディングボリュームの外に押し出されてしまい、問題が生じます。

ランタイム時にアニメーションを追加する場合

要するに、動きのあるモデルの場合は最初に想定したモデルのサイズよりも大きい形になってしまう。
だからカメラの中にいるのに外にいると判断されることがあると。
 
 

「Update When Offscreen」にも使い所あり?

Extentを編集するのもモデルが増えてくると大変だし、どれくらいの数字が適切なのかも難しいし、

これらの例では、2 つの解決方法があります。

Bounds (境界) を修正してメッシュの可能なバウンディングボリュームに適合するように修正します。
Update When Offscreen をスキンに対して有効にし、常にスキンメッシュをレンダリングします。
通常は、パフォーマンスに与える影響も少ないため最初の方法を選択します。ただし、パフォーマンスを重視する必要がない場合や、バウンディングボリュームを予測できない場合 (例えばラグドール物理を使用する場合) に、2 番目の方法を選択します。

とUnity公式さんも言っているので、Unityで動画を撮るだけみたいなケースでは「Update When Offscreen」を使うのも良さそうだ。

不要パーツを消す「何もしない透明なUnityシェーダー」

バッドノウハウっぽいけれど、3D初心者は初心者らしく初心者的なノウハウを書いていこうかと。

既存のモデルを使うとき、「このパーツは要らないなあ」とか思うことがある。

  • そのパーツがUnity上で独立したGameObjectになっていれば非表示するだけで済む。
  • だが、1つのMeshの中に複数パーツがまとめられているとそうもいかない。
  • Blenderとかに行ってMeshをいじる必要がある。
  • ヘタするとその過程で色々壊れて面倒なことになる。

で、「何もしない透明なUnityシェーダー」を適用してしまう。最初からマテリアルが分けられていればこのシェーダーを使ったマテリアルを適用するだけで済む。
仮に必要なパーツと要らないパーツが同じマテリアルの間にまたがっていても、Blenderでマテリアルの塗り分けをするだけならモデルが壊れる可能性は低い。
(もちろんチャンとMeshを消すのと比べて重くなることは予想されるので、速度にシビアな局面では使えないと思われる)

Shader "Custom/VoidShader" {
SubShader{
Colormask 0 Zwrite Off
Pass{}
}
}

多分もっと簡単な書き方があるのだろうけど、とりあえずこれで動く。
より軽い書き方があったら教えて下さい。

よりシンプルなのを教えて頂いたので、そっちで。

引っ張ってきたUnityシェーダーがinvalid subscript uv2 エラー

Unityで以前作ったStandardを改変したシェーダーを別のプロジェクトに持ち込んだら、


invalid subscript 'uv2' at /Program Files/Unity/Editor/Data/CGIncludes/UnityStandardMeta.cginc(21) (on d3d11)

というエラーが出た。
これは、そのシェーダーをProjectウィンドウで右クリックして「Reimport」すればいいらしい。

https://www.reddit.com/r/Unity3D/comments/8kjzdf/standard_shader_invalid_subscript_uv2_error/