見出し画像

【unity】手作りフォグの紹介


※はじめに※

unityにデフォルトでフォグは入っています。どういう処理がされているか分かりませんが、やっていることは同じである可能性も有ります。こちらはマテリアルごとに設定できるようにしてあります。

また、今回はライティングはオフにし、あらかじめテクスチャに影を書き込む想定で作成しています。その為このサンプルでは影無しですがご了承ください。


まずはシェーダーを紹介

手っ取り早く、まずシェーダーを紹介します。

Shader "Custom/OriginalFog"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Color("Fog Color", Color) = (1.0, 1.0, 1.0, 1.0)
        _NearColor("Near Color", Color) = (1.0, 1.0, 1.0, 1.0)
        _Distance ("Distance" , float) = 1.0
    }

    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100
        
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };
            
            struct v2f
            {
                float2 uv : TEXCOORD0;
                float3 worldPos : TEXCOORD1;
                float4 vertex : SV_POSITION;
            };
            
            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _Distance;
            float4 _Color;
            float4 _NearColor;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float dist = length(_WorldSpaceCameraPos - i.worldPos);
                fixed4 addcol = fixed4(lerp(_NearColor.rgb, _Color.rgb, dist / _Distance), 1);
                fixed4 col = tex2D(_MainTex, i.uv) + addcol;
                return col;
            }
            ENDCG
        }
    }
}

そしてこのシェーダーをマテリアルに適用した描画結果がこちら

画像1

マテリアルは至って単純な設定になっています。

画像2

テクスチャはCC0 Textures様から頂いたものです。
Fog Colorはそのままフォグのカラーです。Near Colorというのが近距離のフォグの色です。サンプルではとりあえず無色にしています。色は加算合成しているので、白にすると真っ白に、黒にすればテクスチャの色がそのまま出ます。ディスタンスも単純にフォグを発生させる距離ですね。分かりやすい。

それでは細かく見てみましょう。

まずはここを見て下さい。

CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"

シェーダーを作成した初期状態では

 // make fog work
#pragma multi_compile_fog

このようなプログラムが組まれています。これによってフォグを発生させています。ここで使われている処理と、今回紹介する処理とどっちのほうが早いかは分かりません。が、なんとなく紹介しているもののほうが早いのではないかと思っています。(希望)

フォグは、目線から離れれば離れるほど濃くかかります。なぜ白くなるのか、霧がかかるのかという物理的な話は、吉田誠治様が画像付きツイートで分かりやすく解説してくれていますのでそちらをご覧になってください。(勝手に紹介してごめんなさい)

とにかくこの処理をするにはカメラのポジションを取る必要があります。そのあたりの処理はフラグメントシェーダーの部分で行っています。

float dist = length(_WorldSpaceCameraPos - i.worldPos);
fixed4 addcol = fixed4(lerp(_NearColor.rgb, _Color.rgb, dist / _Distance), 1);
fixed4 col = tex2D(_MainTex, i.uv) + addcol;
return col;

まずはWorldSpaceCameraPosでカメラポジションを取り、画面上に映るオブジェクトのワールドポジション(i.worldPos)と引き算をして「距離」としています。

次に加算合成部分です。変数名はそのままaddcolです。こちらはlerpを使って線形補完しています。線形補完の使い方は、「AからBまでを、Cによって線形補完」という公式を「lerp(A,B,C)」に当てはめます。なんか逆だなと思ったらとりあえずAとBを入れ替えたり、Cの数値をごにょごにょするといい感じになります。(適当)

とにかくここでは、ニアカラーからカラーまでを、カメラとオブジェクトとの距離によって線形補完させています。

最後に、メインテクスチャにこの色を加算合成すれば完成です。



おまけ

画像3

fixed4 col = tex2D(_MainTex, i.uv) + addcol;

ここの足し算を掛け算に変更するだけで簡単に乗算処理へ変更できます。これによってホラーな演出も楽々です。

こちらの場合はニアカラーを白に近づけ、カラー(遠いほう)を黒、または黒に近い色にすればこのようになります。

画像4

こんな感じ。

他にも緑で有毒ガスっぽくしたり、紫で毒沼っぽくしたり、赤で火災みたくしたりも出来そうですね。お好みでいじってみてください!


それでは。

この記事が気に入ったらサポートをしてみませんか?