The first post to this blog and a free easy to understand shader.

For my annual local game jam PegJam2017, I decided to create a game inspired by Monument Valley. I was particularly inspired by the following level and I wanted to attempt to recreate some of the atmosphere in my jam game. The jam game “Isolation” can be found here.

The simplest way to achieve the effect of the geometry fading away into fog / background is with a shader which i will share in full at the end. What I wanted my shader to do was fade the vertices of the geometry to a new color based on its distance to the y position of 0.

Step one I needed expose two color variables:

fixed4 _Color;

fixed4 _FogColor;

_Color for the tint of the geometry, and _FogColor for the background color that i am going to clear the screen to.

Step two I decided it would be useful for each object to define the y position of when the effect would began and the y position of the effect would be applied 100% of the way in a gradient so i exposed two new variables. This would allow customization for how the effect looked for each object in the scene.

half _FogStart;

half _FogEnd;

Step three I needed to convert the output position of my vertices to the games world position so that I knew the position relative to the effect start and end y positions.

float4 pos = mul(unity_ObjectToWorld, v.vertex).xyzw;

Step four I needed to calculate how powerful the effect would be based on the vertex y position using a simple calculation and the saturate function which just clamps the results between 0 and 1.

data.fog = saturate((_FogStart - pos.y) / (_FogStart - _FogEnd));

Step five is calculating the final color by lerping between the _Color and the _FogColor using the data.fog intensity calculated in step four. The _Color variable is multiplied by color.rgb which is the color output calculated by the standard unity shader. If I didn’t do this i would loose all shadow and lighting information in the scene.

color.rgb = lerp(color.rgb * _Color , _FogColor, IN.fog);

Finally to hook this up in unity i needed to create a new material with the shader and apply it to all of my 3d assets. To make the background the same color as the fog effect I also need to set the Background color property on the camera.

The result of all of this is a very simple shader that very closely resembles the effect from monument valley without any effort creating custom textures for all of the models. The shader also works with any colors, lighting, shadows and as far as i know also works with textures on the models. Because the effect is created with a shader i also get a cool fade in effect when the object moves up from below the ground.

By playing around with the start and end positions you can change the power of the effect and even reverse it to disappear into the sky instead of the ground.

Thanks for reading!



Shader "Custom/Fog"

{

Properties

{

_Color("Color", Color) = (1,1,1,1)

_MainTex("Texture", 2D) = "white" {}

_FogColor("Fog Color", Color) = (0.3, 0.4, 0.7, 1.0)

_FogStart("Fog Start", float) = 0

_FogEnd("Fog End", float) = 0

}

SubShader

{

Tags{ "RenderType" = "Opaque" }

CGPROGRAM

#pragma surface surf Lambert finalcolor:mycolor vertex:myvert

struct Input

{

float2 uv_MainTex;

half fog;

};

fixed4 _Color;

fixed4 _FogColor;

half _FogStart;

half _FogEnd;

sampler2D _MainTex;

void myvert(inout appdata_full v, out Input data)

{

UNITY_INITIALIZE_OUTPUT(Input,data);

float4 pos = mul(unity_ObjectToWorld, v.vertex).xyzw;

data.fog = saturate((_FogStart - pos.y) / (_FogStart - _FogEnd));

}

void mycolor(Input IN, SurfaceOutput o, inout fixed4 color)

{

fixed3 fogColor = _FogColor.rgb;

fixed3 tintColor = _Color.rgb;

#ifdef UNITY_PASS_FORWARDADD

fogColor = 0;

#endif

color.rgb = lerp(color.rgb * tintColor, fogColor, IN.fog);

}

void surf(Input IN, inout SurfaceOutput o)

{

o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb;

}

ENDCG

}

Fallback "Diffuse"

}

