Unity3D: Advance Skybox Blending for Day Night Cycle

Complete the day-night cycle with a custom blended skybox shader: two skybox sets and a blend factor driven by the day phase controller.

Last time I created a day night cycle with smooth light and fog transition. Now I will perfect that cycle by adding a skybox transition between day and night. For this functionality we need a custom skybox shader that contains 2 skybox texture sets and a blend factor with range [0-1] to combine them.

This custom shader was created by Aras Pranckevicius in his article on the Unify Community (Unity wiki). I use it together with the DayNightController script from the previous article.

The Blended Skybox Shader

Create a new shader named SkyboxBlend and copy this code:

Shader "RenderFX/Skybox Blended" {
Properties {
	_Tint ("Tint Color", Color) = (.5, .5, .5, .5)
	_Blend ("Blend", Range(0.0,1.0)) = 0.5
	_FrontTex ("Front (+Z)", 2D) = "white" {}
	_BackTex ("Back (-Z)", 2D) = "white" {}
	_LeftTex ("Left (+X)", 2D) = "white" {}
	_RightTex ("Right (-X)", 2D) = "white" {}
	_UpTex ("Up (+Y)", 2D) = "white" {}
	_DownTex ("Down (-Y)", 2D) = "white" {}
	_FrontTex2("2 Front (+Z)", 2D) = "white" {}
	_BackTex2("2 Back (-Z)", 2D) = "white" {}
	_LeftTex2("2 Left (+X)", 2D) = "white" {}
	_RightTex2("2 Right (-X)", 2D) = "white" {}
	_UpTex2("2 Up (+Y)", 2D) = "white" {}
	_DownTex2("2 Down (-Y)", 2D) = "white" {}
}

SubShader {
	Tags { "Queue" = "Background" }
	Cull Off
	Fog { Mode Off }
	Lighting Off
	Color [_Tint]
	Pass {
		SetTexture [_FrontTex] { combine texture }
		SetTexture [_FrontTex2] { constantColor (0,0,0,[_Blend]) combine texture lerp(constant) previous }
		SetTexture [_FrontTex2] { combine previous +- primary, previous * primary }
	}
	Pass {
		SetTexture [_BackTex] { combine texture }
		SetTexture [_BackTex2] { constantColor (0,0,0,[_Blend]) combine texture lerp(constant) previous }
		SetTexture [_BackTex2] { combine previous +- primary, previous * primary }
	}
	Pass {
		SetTexture [_LeftTex] { combine texture }
		SetTexture [_LeftTex2] { constantColor (0,0,0,[_Blend]) combine texture lerp(constant) previous }
		SetTexture [_LeftTex2] { combine previous +- primary, previous * primary }
	}
	Pass {
		SetTexture [_RightTex] { combine texture }
		SetTexture [_RightTex2] { constantColor (0,0,0,[_Blend]) combine texture lerp(constant) previous }
		SetTexture [_RightTex2] { combine previous +- primary, previous * primary }
	}
	Pass {
		SetTexture [_UpTex] { combine texture }
		SetTexture [_UpTex2] { constantColor (0,0,0,[_Blend]) combine texture lerp(constant) previous }
		SetTexture [_UpTex2] { combine previous +- primary, previous * primary }
	}
	Pass {
		SetTexture [_DownTex] { combine texture }
		SetTexture [_DownTex2] { constantColor (0,0,0,[_Blend]) combine texture lerp(constant) previous }
		SetTexture [_DownTex2] { combine previous +- primary, previous * primary }
	}
}

Fallback "RenderFX/Skybox", 1
}

Material Setup

Create a new Skybox material using shader RenderFX > Skybox Blended, set the blend slider to 0, and apply skybox textures according to this rule:

  • Put Day Skybox (front) texture to "Front"
  • Put Night Skybox (front) texture to "2 Front"
  • Put Day Skybox (up) texture to "Up"
  • Put Night Skybox (up) texture to "2 Up"
  • And also put left, right, back, down textures according to their variables

Assign Render Settings > Skybox material to this custom material.

Driving the Blend from the Day Phase

Add a new variable to the DayNightController:

// blend value of skybox using SkyBoxBlend Shader in render settings range 0-1
private float SkyboxBlendFactor= 0.0f;

Create UpdateSkyboxBlendFactor():

private void UpdateSkyboxBlendFactor(){
	if (currentPhase == DayPhase.Dawn)
	{
		float relativeTime = currentCycleTime - dawnTime;
		SkyboxBlendFactor = 1 - (relativeTime / halfquarterDay);
	}
	else if (currentPhase == DayPhase.Day)
	{
		SkyboxBlendFactor = 0.0f;
	}
	else if (currentPhase == DayPhase.Dusk)
	{
		float relativeTime = currentCycleTime - duskTime;
		SkyboxBlendFactor = relativeTime / halfquarterDay;
	}
	else if (currentPhase == DayPhase.Night)
	{
		SkyboxBlendFactor = 1.0f;
	}

	RenderSettings.skybox.SetFloat("_Blend", SkyboxBlendFactor);
}

Finally, call UpdateSkyboxBlendFactor() in Update() after updating the ambient light of the game world.