Altitude Fog shader for Unity

The island on the left side cuts off in a rather ugly fashion. The one on the right seems to fade into the depths. That is the look we are after.

The island on the left side cuts off in a rather ugly fashion. The one on the right seems to fade into the depths. That is the look we are after.


When you submerge an object in water you expect it to become more and more obscured as it sinks further into the depths. As far as I can see, this is usually accomplished in Unity3D with a fullscreen image-effect like the global fog standard asset. But that only works in the pro-version of Unity, and I want something that works in the free version. This post shows my solution.

In Unity3D, you can implement your own custom fog on a material by writing your own final color function in a custom shader. The final color function is applied after any lightning has been applied, so we wont have light­sources brightening up objects that are supposed to be hidden. The incredibly useful Surface Shader Examples page in the Unity documentation includes an example titled “Custom Fog with Final Color Modifier”, where a custom finalcolor function is used to apply fog based on the vertical position of the pixel in screenspace. This is nearly what I want, but I want the fog to be only dependent on the y-axis-position in world space. Another example in there, titled “Slices via World Space Position”, uses the world coordinates of the rendered pixel to slice the object vertically. From this example we can see how to use the world space position of the pixel we are rendering.

The shader below utilises principles from both the examples. The final color is faded into the fog color using the world coordinates of the rendered pixel, providing a fog­like effect based on the vertical position of the object rather than the distance between the object and the camera.

Shader "Custom/AltitudeFog"
{
    Properties 
    {
        _MainTex ("Base (RGB)", 2D) = "white" {}
		_FogColor ("Fog Color", Color) = (0.5, 0.5, 0.5, 1)
        _FogMaxHeight ("Fog Max Height", Float) = 0.0
        _FogMinHeight ("Fog Min Height", Float) = -1.0
    }
 
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200
        Cull Back
        ZWrite On
 
        CGPROGRAM
 
        #pragma surface surf Lambert finalcolor:finalcolor vertex:vert
 
        sampler2D _MainTex;
        float4 _FogColor;
        float _FogMaxHeight;
        float _FogMinHeight;
 
        struct Input 
        {
            float2 uv_MainTex;
            float4 pos;
        };
 
        void vert (inout appdata_full v, out Input o) 
        {
            float4 hpos = mul (UNITY_MATRIX_MVP, v.vertex);
            o.pos = mul(_Object2World, v.vertex);
            o.uv_MainTex = v.texcoord.xy;
        }
 
        void surf (Input IN, inout SurfaceOutput o) 
        {
            float4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Albedo = c.rgb;
        }
 
        void finalcolor (Input IN, SurfaceOutput o, inout fixed4 color)
        {
            #ifndef UNITY_PASS_FORWARDADD
            float lerpValue = clamp((IN.pos.y - _FogMinHeight) / (_FogMaxHeight - _FogMinHeight), 0, 1);
            color.rgb = lerp (_FogColor.rgb, color.rgb, lerpValue);
            #endif
        }
 
        ENDCG
    }
 
    FallBack "Diffuse"
}

This shader, used on the material of any partially submerged objects, applies a linear depth fog using the lerp function, but you could replace it with any function you want. A straightforward change is to use an exponential fog by changing the calculations in the finalcolor function, but for now, I’m quite happy with linear depth fog.

Sinking ships look much prettier with altitude fog.

Sinking ships look much prettier with altitude fog.

Advertisements

Tags: ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s