UnityのFowardRenderingにおけるFogの設定方法と、カスタムシェーダの書き方です。
Unity2018.3
注意点
この記事ではUnityのLighting Settingsから設定できるFog機能について説明します。
これはForward Renderingにしか対応していないのでご注意ください。
Deferredの場合はPost Processingによるポストエフェクトを使うとよさそうです。
Fog?
Fogはその名の通り霧を表現するための機能です。
空気感の演出に役立ちます。
例えばこんなSceneにFogをかけると、
こうなります。
設定方法
FogはLighting SettingsからScene毎に設定できます。
基本的にはFogにチェックを入れて色を調整するだけです。
Modeを変えるとFogの色を計算するアルゴリズムが変わりますが、これについては後述します。
カスタムシェーダに適用する
Fog周りはマクロが用意されているため、カスタムシェーダでも簡単に掛けることができます。
以下はシンプルにフォグだけを掛けたシェーダの例です。
Shader "Fog" { SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag // フォグ用のバリアントを生成 #pragma multi_compile_fog #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; }; struct v2f { float4 vertex : SV_POSITION; // フォグ用のTEXCOORDのindexを指定 UNITY_FOG_COORDS(1) }; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); // 頂点シェーダでの計算はこのマクロで UNITY_TRANSFER_FOG(o, o.vertex); return o; } fixed4 frag (v2f i) : SV_Target { fixed4 col = 1; // フラグメントシェーダでの計算はこのマクロで UNITY_APPLY_FOG(i.fogCoord, col); return col; } ENDCG } } }
説明はコメントに書いた通りです。
中身で何をしているのかをもうちょっと知りたいので、マクロの中身を次節で展開してみます。
マクロを展開してみる
前節のシェーダのマクロの中身を少し展開してみます。
Fog周りのマクロはUnityCG.cgincに定義されていました。
※ モバイルかどうかの分岐があったので、モバイル前提で展開しています
Shader "Fog2" { SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag // #pragma multi_compile_fog #pragma multi_compile FOG_EXP FOG_EXP2 FOG_LINEAR #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; }; struct v2f { float4 vertex : SV_POSITION; // UNITY_FOG_COORDS(1) float fogCoord : TEXCOORD1; }; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); // UNITY_TRANSFER_FOG(o, o.vertex); UNITY_CALC_FOG_FACTOR(o.vertex.z); o.fogCoord.x = unityFogFactor; return o; } fixed4 frag (v2f i) : SV_Target { fixed4 col = 1; // UNITY_APPLY_FOG(i.fogCoord, col); #ifdef UNITY_PASS_FORWARDADD col.rgb = lerp(fixed4(0, 0, 0, 0).rgb, col.rgb, saturate(i.fogCoord)); #else col.rgb = lerp(unity_FogColor.rgb, col.rgb, saturate(i.fogCoord)); #endif return col; } ENDCG } } }
まずマクロではないですが、#pragma multi_compile_fog
は下記の通りに書き換えました。
#pragma multi_compile FOG_EXP FOG_EXP2 FOG_LINEAR
これはFogのModeに応じた三つのバリアントを作っています。
Scene毎にModeを変えるようなことがなければshader_feature
のほうがいい気はします。
次にUNITY_FOG_COORDS(1)
はfogCoordという名前でInterpolatorを定義しているだけです。
また、頂点シェーダのマクロUNITY_TRANSFER_FOG
は展開先でUNITY_CALC_FOG_FACTOR
というマクロを読んでいます。
実はこのマクロの中でFogのMode毎の処理を分けているのですが、これは次節で説明します。
UNITY_CALC_FOG_FACTOR
はunityFogFactor
という変数に値を格納してくれるので、これをInterpolatorに代入します。
最後にフラグメントシェーダのUNITY_APPLY_FOG
です。
これはLighting Settingsで設定したFogの色と物体色を頂点シェーダで計算したunityFogFactor
で補間するだけです。
結果、unityFogFactor
の値が低いところほどFogの色が反映されます。
また、ForwardAddパスの場合は値が低いほど黒に近づき、加算効果が弱くなります。
Mode別のアルゴリズム
前節のUNITY_CALC_FOG_FACTOR
マクロをさらに展開していくとFogのMode毎のアルゴリズムが見えてきます。
まずMode毎にunityFogFactor
(以下factor)はそれぞれ以下の式で求められます。
Mode | 式 | 説明 |
---|---|---|
Linear | zはクリッピング空間の深度 startとendはLighting Settingsの値 |
|
Exponential | zはクリッピング空間の深度 densityはLighting Settingsの値 |
|
Exponential Squared | zはクリッピング空間の深度 densityはLighting Settingsの値 |
それでは一つ一つ見ていきます。
Linearは単純に、startから線形に掛かり始めてendで完全にFogの色になります。
下図はstart = 0, end = 100としたときの図です(前節の通り。この値が低いほどFogの色になります)。
Linear / start = 0, end = 100
次にExponentialです。
これはLinearよりも、奥に行けば行くほどFogが強くなります。
下はdensity = 0.06のときの図です。
Exponential / density = 0.06
densityの値を上げるとよりFogがかかりやすくなります。
Exponential / density = 0.3
最後にExponential Squaredです。
これはExponentialより手前にFogがかかりづらい感じになりそうです。
使いやすそうな気がします。
Exponential Squared / density = 0.1
こちらもdensityを上げるとFogがかかりやすくなります。
Exponential Squared / density = 0.3
以上です。