Unityお勉強メモ 「描画順」

※断片的な情報から予想してるだけだから間違ってるかもだよ。


オブジェクトの描画順を決定するのは次の4つの要素。
この順番で優先される。
1. カメラのプロパティDepth
2. Sorting Layer & Order In Layer
3. SubShader中のQueueタグ
4. カメラからの距離

Q. レイヤーは?
A. レイヤー自体は関係ない。
  ただ、カメラがどのオブジェクトを描画するかはレイヤーによって決まる。
  ※各オブジェクトは32個あるレイヤーのうちどれかひとつに属している。
   レイヤーの名前は自由に決められる。デフォルトで"TranparentFX"とか
   "Water"とか設定されてるけど、意味は無いので気にすることは無い。
   紛らわしいからデフォルトは消したほうがいいくらいだと思う。

Q. RenderTypeタグは?
A. SubShader中にはRenderTypeタグを記述できる。
  Tags {"RenderType" = "Opaque"}
  OpaqueとかTransparentとかある。
  が、これは関係ない。
  RenderTypeは、Camera.SetReplacementShaderでシェーダーを切り替えたいとき等に使われる。

  ※自分のコードでReplaced Shader機能を使ってないからといって適当に指定しないほうがいい。
    SSAOイメージエフェクトなどの組み込み機能のいくつかは、内部でこのタグを利用している。

Q. 深度バッファはどうなってる?
A. カメラで共有している。
  ただ、カメラのプロパティClear FlagでDon't Clearを選ばない限りは、毎回クリアされる。

Q. Z描いて欲しくない。もしくは深度テストしてほしくない。
A. シェーダ側で制御できる。Pass中に次のように記述する。
  ZWrite On | Off
  ZTest Less | Greater | LEqual | GEqual | Equal | NotEqual | Always


■カメラのプロパティDepth

Depthが小さいカメラから順に描画する。カメラの位置は関係ない。
カメラはCulling Maskに設定されたレイヤーのオブジェクトを描画する。
Culling Maskには複数のレイヤーを設定できる。




■Sorting Layer & Order In Layer

Unityの機能としての「スプライト」を使ってなければ関係ない。
スプライトを描画するSprite Rendererには、
プロパティとしてSorting Layer & Order In Layerを設定できる。
スプライトはSorting Layerリストの順に描画される。
Sorting Layerは自由に追加でき、好きな名前を付けて並べ替えることができる。
ただし"Default"という名前のSorting Layerは必ずどこかに存在しなければならない。
メッシュにはSorting Layerは無いが、描かれる順番は"Default"に位置する。
メッシュより前にSpriteを描きたいときは"Default"より前のレイヤーを追加すればいい。


■SubShader中のQueueタグ

各シェーダーにはQueueが設定されている。
コードではこういうふうに記述される。
Tags {"Queue" = "Transparent"}

設定できるQueueは5種類。実は内部的に値が設定されている。
このQueueの値が小さい順から描画される。

Background = 1000
Geometry = 2000(デフォルト)
AlphaTest 2450
Transparent = 3000
Overlay = 4000

2500までは不透明とみなされる→手前のオブジェから描く
2500以降は半透明とみなされる→奥のオブジェから描く

シェーダのコードをこういうふうに書くと、順番を微調整することもできる。
Tags {"Queue" = "Transparent+1"} // 他のTransparentよりもさらに後

また、2500以降だとZWriteのデフォルト値がOffになるらしい。
シェーダ書くときはZWriteに限らずオプションは全部列挙したほうが
間違いが無くて確実っぽい。
http://forum.unity3d.com/threads/why-diffuse-transparent-diffuse-alpha-1.150048/
http://tips.hecomi.com/entry/2014/03/07/005743


■カメラからの距離

各メッシュは頂点座標の存在範囲を表すバウンダリボックスを持っている。
これによりカメラ座標からの距離が判定される。
もしメッシュの中身をコードから書き換えたときは、
バウンダリボックス更新のため、Mesh.RecalculateBounds()を呼んだほうがよいだろう。








■参考にしたURL


West Hill 開発メモ [Unity][uGUI] uGUIにパーティクルや他のオブジェクトを重ねて描画する
    http://westhillapps.blog.jp/archives/43632310.html

テラシュールブログ UnityのSpriteとパーティクルとかモデルの描画順番について
    http://tsubakit1.hateblo.jp/entry/2015/01/05/233000

Unityシェーダ入門 Unityでの半透明オブジェクトの描画順序の変更
    http://unityshader.hatenablog.com/entry/2013/10/16/215145

Unityシェーダ入門 Unityシェーダ入門 #004 Replaced Shader
    http://unityshader.hatenablog.com/entry/2013/12/14/015247

Unity のシェーダの基礎を勉強してみたのでやる気出してまとめてみた
    http://tips.hecomi.com/entry/2014/03/16/233943

公式 ShaderLab :カリングと深度テクスチャ
    http://docs.unity3d.com/ja/current/Manual/SL-CullAndDepth.html

公式 ShaderLab :サブシェーダータグ
    http://translate.unity3d.com/html/ja/Manual/SL-SubshaderTags.html