【Unity】マテリアルの描画がシェーダーのQueue順に処理されない原因と対策
自作シェーダーなどを使用してレンダリングを行う場合、レンダリング順序をTagsのQueueで指定しますが、特定の条件でこのレンダリング順序が無視される現象が発生したので共有。
簡潔にまとめだけ
まとめると
現象 :シェーダーで指定したレンダリングキューが無視されることがある
原因 :MaterialのCustom Render Queueに不正値が入っているため
発生条件:自作シェーダーを使用 & 自作シェーダー設定前に、他のシェーダーを割り当てていた場合
対策 :Custom Render Queueに-1を設定すればOK
おさらい レンダリング順序について
レンダリング順序は、シェーダーのTags Queueに設定された以下の順になります(なにも指定しない場合は"Geometry")。
Tags{ "Queue"="Geometry" }
・Background
・Geometry(デフォルト)
・AlphaTest
・Transparent
・Overlay
現象
しかし、特定の状況でこのQueueが無視される状況が発生します。
例えば以下の画像では、奥のチェック柄にはUnlit-Colorシェーダー(Queue=Geometry)を、手前のキューブには自作の半透明シェーダー(Queue=Transparent)を設定していますが、キューブが半端に描画されてしまい、カメラ角度によっては完全に消えてしまいます。
ちなみに自作シェーダーの中身はこんな感じです。QueueにTransparentを設定し、ZTestにAlways(深度チェックは常にOK)を指定しています。シェーダー的には、完全に描画されるはずです。
Shader "Custom/Alpha Blended" { Properties { _Color ("Main Color", Color) = (1,1,1,1) _Alpha ("Alpha", Range(0, 1)) = 1 } SubShader { Tags { "Queue"="Transparent" "RenderType"="Transparent" } Blend SrcAlpha OneMinusSrcAlpha Lighting Off ZWrite Off ZTest Always Fog { Color (0,0,0,0) } CGPROGRAM #pragma surface surf Lambert fixed _Alpha; float4 _Color; struct Input { float4 color : COLOR; }; void surf (Input IN, inout SurfaceOutput o) { o.Albedo = _Color.rgb; o.Alpha = _Alpha; } ENDCG } }
原因
結論から書くと、MaterialのCustom Render Queueが原因です。
Materialを選択した状態で、Inspectorをデバッグモードで開きます。デバッグモードは、以下の場所から開けます。
表示された項目の、Custom Render Queueに注目してください。下図だと、2000と入力されています。
実はこのCustom Render Queueがシェーダーで指定するQueueに対応していて、unityはこの数字に従ってレンダリングを行っている様子です。
Background 1000
Geometry 2000
AlphaTest 2450
Transparent 3000
Overlay 4000
何故自作シェーダーはQueue=TransparentなのにCustom Render Queueが2000になっているかというと、この自作シェーダーを設定する前に、MaterialにUnlit-Colorを設定していたからです。自作シェーダーを設定する場合、自動でCustom Render Queueを更新してくれない様子。。。
対策
対策は簡単で、Custom Render Queueに-1を設定すれば、シェーダーに書いたQueue通りに動作します。
いや、はまったはまった。Unityはこれがあるから怖い。