Super Mario Galaxy “Reveal Hidden Platforms” CG Shader

I’m enjoying playing through my old Nintendo Wii titles with my six-year old son – he’s into Super Mario Galaxy, but I have to help him with the tricky levels (naturally, I’m happy to oblige!).  One such level is in the “Haunty Halls” galaxy, in which the level is mostly invisible, and the floor in the immediate vicinity of the player only becomes visible after Yoshi eats a bulb berry. The player must then quickly navigate through the level to find the next berry before the visible area shrinks and the player falls into darkness.

http://www.mariowiki.com/images/7/7d/HaHaG3.png

I thought I’d have a go at a similar effect in Unity, and came up with the following CG shader:

Shader "Custom/Proximity" {
	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {} // Regular object texture 
		_PlayerPosition ("Player Position", vector) = (0,0,0,0) // The location of the player - will be set by script
		_VisibleDistance ("Visibility Distance", float) = 10.0 // How close does the player have to be to make object visible
		_OutlineWidth ("Outline Width", float) = 3.0 // Used to add an outline around visible area a la Mario Galaxy
		_OutlineColour ("Outline Colour", color) = (1.0,1.0,0.0,1.0) // Colour of the outline
	}
	SubShader {
		Tags { "RenderType"="Transparent" "Queue"="Transparent" }
		Pass {
		Blend SrcAlpha OneMinusSrcAlpha
		
		CGPROGRAM
		#pragma vertex vert
		#pragma fragment frag		

		// Access the shaderlab properties
		uniform sampler2D _MainTex;
		uniform float4 _PlayerPosition;
		uniform float _VisibleDistance;
		uniform float _OutlineWidth;
		uniform fixed4 _OutlineColour;
		
		// Input to vertex shader
		struct vertexInput {
			float4 vertex : POSITION;
			float4 texcoord : TEXCOORD0;
		};
		// Input to fragment shader
		struct vertexOutput {
			float4 pos : SV_POSITION;
			float4 position_in_world_space : TEXCOORD0;
			float4 tex : TEXCOORD1;
		};
         
		// VERTEX SHADER
		vertexOutput vert(vertexInput input) 
		{
			vertexOutput output; 
			output.pos =  mul(UNITY_MATRIX_MVP, input.vertex);
			output.position_in_world_space = mul(_Object2World, input.vertex);
			output.tex = input.texcoord;
			return output;
		}
 
 		// FRAGMENT SHADER
		float4 frag(vertexOutput input) : COLOR 
		{
			// Calculate distance to player position
			float dist = distance(input.position_in_world_space, _PlayerPosition);
 
 			// Return appropriate colour
			if (dist < _VisibleDistance) {
				return tex2D(_MainTex, float2(input.tex)); // Visible
			}
			else if (dist < _VisibleDistance + _OutlineWidth) {
				return _OutlineColour; // Edge of visible range
			}
			else {
				float4 tex = tex2D(_MainTex, float2(input.tex)); // Outside visible range
				tex.a = 0;
				return tex;
			}
		}

		ENDCG
		} // End Pass
	} // End Subshader
	FallBack "Diffuse"
} // End Shader

 

It’s fairly self-explanatory – the key feature is that, in the vertex shader, the input vertex coordinates input.vertex (which are supplied in model coordinates) are multiplied by the Unity _Object2World matrix to turn them into world coordinates, output.position_in_world_space. Then, in the fragment shader, the CG distance function is used to calculate the distance from the current fragment to the player’s position, _PlayerPosition, and return one of three colours accordingly.

If the fragments outside visible range are set to semitransparent grey and the border colour set to yellow, it looks as follows:

image

 

In order to make the shader dynamic, the _PlayerPosition property must be updated programmatically through script, by attaching the following (Unity)script onto the object to which the shader is placed, and dragging the player object from the inspector onto the “player” property slot:

 

#pragma strict

// Take effect even in edit mode
@script ExecuteInEditMode()

// Get a reference to the player
public var player : Transform;
 
function Update ()
{
	if (player != null) {
		// Pass the player location to the shader
		renderer.sharedMaterial.SetVector("_PlayerPosition", player.position);
	}
}

 

And here’s a video of it in action:

About these ads
This entry was posted in Game Dev and tagged , , , . Bookmark the permalink.

2 Responses to Super Mario Galaxy “Reveal Hidden Platforms” CG Shader

  1. Pingback: Animal Crossing Curved World Shader | Alastair Aitchison

  2. Luan says:

    Amazing shader! Didn’t know about the
    Will be modifying it to obtain a slightly different effect.

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