> ## Content Index
> Fetch the complete content index at: https://blog.febucci.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# World Reveal Shader in Unity: Circle Dissolve Tutorial
- URL: https://blog.febucci.com/2018/09/world-reveal-shader/
- Published: 2018-09-01T13:00:00.000Z
- Updated: 2026-04-06T07:25:48.000Z
- Description: Build a world-space reveal shader that makes objects appear based on distance from a point. Covers fog-of-war, circle dissolve, and noise-based edges.
- Author: Federico Bellucci
- Tags: Tutorials, Unity

Want to make objects appear or disappear based on the player's position? That's what a world reveal shader does. It computes the distance between each pixel and a world position, then uses that to dissolve or reveal the geometry. It's perfect for fog-of-war effects, exploration reveals, or dramatic scene transitions. This tutorial gives you full HLSL code and Shader Graph setups for both 2D and 3D.

## How do I make a world reveal or circle dissolve shader in Unity?

A **world reveal shader** (also called "dissolve the world shader" or "global dissolve") fades every object in your scene based on its distance from a point, typically the player. Today we'll create one in Unity's **Shader Graph** and write it in **HLSL**, covering both 2D sprites and 3D objects.

Here's an example of what we'll create:

0:00 

/0:03 

1× 

Since this is **part 2**, I *highly suggest* reading my previous tutorial about [dissolve shaders](https://blog.febucci.com/2018/09/dissolve-shader/) first. If you're new to Unity shaders in general, my [intro to writing shaders in HLSL](https://blog.febucci.com/2019/11/how-to-write-shaders-in-unity/) covers the basics you'll need. The effect uses a single global shader variable (`_PlayerPos`), 1 distance calculation per pixel, and a configurable reveal radius to control how far objects stay visible.

## How it works

The approach has 3 steps:

1. Pass the player's world position to all shaders each frame using `Shader.SetGlobalVector`
2. In each shader, compute the distance between the pixel's world position and the player position
3. Use that distance as the dissolve amount (replacing the manual `_Amount` parameter)

### Using distance as parameter

Let's say we want to **dissolve an object** in our scene if it's too **far from the player**. We already declared the `"_Amount"` parameter which controls the fade/dissolve progress of our object; we just need to replace it with the distance between the object and the player.

To do this we have to get the **Player** and the **Object** position.

### Retrieving the Player position

The **process** is the same for both **Unity's Shader Graph** and **HLSL**: we need to pass the player position via code.

```hlsl
private void Update()
{
    //Updates the _PlayerPos variable in all the shaders
    //Be aware that the parameter name has to match the one in your shaders or it wont' work
    Shader.SetGlobalVector("_PlayerPos", transform.position); //"transform" is the transform of the Player
}

```

### Via Shader Graph

Using Shader Graph you'll be able to use the Position and Distance nodes.

- [Position Node documentation](https://docs.unity3d.com/Packages/com.unity.shadergraph@7.2/manual/Position-Node.html?ref=blog.febucci.com).
- [Distance Node documentation](https://docs.unity3d.com/Packages/com.unity.shadergraph@7.2/manual/Distance-Node.html?ref=blog.febucci.com).

![](https://storage.ghost.io/c/38/36/383676a1-e894-4116-9a98-bb5a9336da39/content/images/2024/09/febucci-tutorial-world-reveal-shader-graph-3d-local.jpg)

💡

P.s. to make this work with Sprite Renderers you must add the `"_MainTex"` property, sample it and connect it to the albedo.  
You can also read my previous tutorial about [Sprites diffuse shader](https://www.febucci.com/2018/07/sprite-diffuse-shader/?ref=blog.febucci.com) (using shader graph).

---

### Via HLSL (Surface)

**Object Position**

In HLSL we can add the variable "**worldPos**" in our **Input** struct to get the vertex position of our objects. (If you want to learn more about what the vertex stage can do, check out my [vertex shader tutorial](https://blog.febucci.com/2018/10/vertex-shader/).)

```hlsl
struct Input 
{
	float2 uv_MainTex;
	float3 worldPos; //add this and Unity will set it automatically
}

```

You can see what other built-in parameters you can add to the Input struct in this [Unity's documentation page](https://docs.unity3d.com/Manual/SL-SurfaceShaders.html?ref=blog.febucci.com).

---

**Apply the distance**

We need to use the distance between our objects and our player as the amount of the dissolve. You can use the already built-in `distance` function ([Microsoft documentation here](https://docs.microsoft.com/it-it/windows/win32/direct3dhlsl/dx-graphics-hlsl-distance?ref=blog.febucci.com)).

```hlsl
 void surf (Input IN, inout SurfaceOutputStandard o) {
	half dissolve_value = tex2D(_DissolveTexture, IN.uv_MainTex).x;
 
	float dist = distance(_PlayerPos, IN.worldPos);
 
	clip(dissolve_value - dist/ 6f); //"6" is the maximum distance where your object will start showing
 
	//Set albedo, alpha, smoothness etc[...]
}

```

---

## Setting up the shader

### For 2D Sprites

```hlsl
Shader "Custom/GlobalDissolveSprites"
{
	Properties
	{
		[PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
		_Color("Tint", Color) = (1,1,1,1)
		[MaterialToggle] PixelSnap("Pixel snap", Float) = 0
		[HideInInspector] _RendererColor("RendererColor", Color) = (1,1,1,1)
		[HideInInspector] _Flip("Flip", Vector) = (1,1,1,1)
		[PerRendererData] _AlphaTex("External Alpha", 2D) = "white" {}
		[PerRendererData] _EnableExternalAlpha("Enable External Alpha", Float) = 0
 
 
		_DissolveTexture("Dissolve texture", 2D) = "white" {}
		_Radius("Distance", Float) = 1 //distance where we start to reveal the objects
	}
 
	SubShader
	{
		Tags
		{
			"Queue" = "Transparent"
			"IgnoreProjector" = "True"
			"RenderType" = "Transparent"
			"PreviewType" = "Plane"
			"CanUseSpriteAtlas" = "True"
		}
 
		Cull Off
		Lighting Off
		ZWrite Off
		Blend One OneMinusSrcAlpha
 
		CGPROGRAM
		#pragma surface surf Lambert vertex:vert nofog nolightmap nodynlightmap keepalpha noinstancing
		#pragma multi_compile _ PIXELSNAP_ON
		#pragma multi_compile _ ETC1_EXTERNAL_ALPHA
		#include "UnitySprites.cginc"
 
		struct Input
		{
			float2 uv_MainTex;
			fixed4 color;
			float3 worldPos; //Built-in world position
		};
 
		sampler2D _DissolveTexture; //texture where we get the dissolve value
		float3 _PlayerPos; //"Global Shader Variable", contains the Player Position
		float _Radius;
 
		void vert(inout appdata_full v, out Input o)
		{
			v.vertex = UnityFlipSprite(v.vertex, _Flip);
 
			#if defined(PIXELSNAP_ON)
			v.vertex = UnityPixelSnap(v.vertex);
			#endif
 
			UNITY_INITIALIZE_OUTPUT(Input, o);
			o.color = v.color * _Color * _RendererColor;
		}
 
		void surf(Input IN, inout SurfaceOutput o)
		{
			half dissolve_value = tex2D(_DissolveTexture, IN.uv_MainTex).x;
			float dist = distance(_PlayerPos, IN.worldPos);
			clip(dissolve_value - dist / _Radius);
 
			fixed4 c = SampleSpriteTexture(IN.uv_MainTex) * IN.color;
			o.Albedo = c.rgb * c.a;
			o.Alpha = c.a;
		}
 
		ENDCG
	}
 
	Fallback "Transparent/VertexLit"
}

```

💡

P.S. To create the last shader I copied the default "Sprites-Diffuse" Unity's shader and added the "dissolve" part previously explained in this tutorial.  
You can find all default shaders [clicking here](https://unity3d.com/get-unity/download/archive?ref=blog.febucci.com).

0:00 

/0:04 

1× 

---

### For 3D Objects

```hlsl
Shader "Custom/GlobalDissolveSurface" {
	Properties {
		_Color ("Color", Color) = (1,1,1,1)
		_MainTex ("Albedo (RGB)", 2D) = "white" {}
		_Glossiness("Smoothness", Range(0,1)) = 0.5
		_Metallic("Metallic", Range(0,1)) = 0.0
 
		_DissolveTexture("Dissolve texture", 2D) = "white" {}
		_Radius("Distance", Float) = 1 //distance where we start to reveal the objects
	}
		SubShader{
			Tags { "RenderType" = "Opaque" }
			LOD 200
			Cull off //material is two sided
 
		CGPROGRAM
 
		#pragma surface surf Standard fullforwardshadows
 
		#pragma target 3.0
 
		sampler2D _MainTex;
		sampler2D _DissolveTexture; //texture where we get the dissolve value
 
		struct Input
		{
			float2 uv_MainTex;
			float3 worldPos; //Built-in world position
		};
 
		half _Glossiness;
		half _Metallic;
		fixed4 _Color;
 
		float3 _PlayerPos; //"Global Shader Variable", contains the Player Position
		float _Radius; 
 
		void surf (Input IN, inout SurfaceOutputStandard o) {
 
			half dissolve_value = tex2D(_DissolveTexture, IN.uv_MainTex).x;
 
			float dist = distance(_PlayerPos, IN.worldPos);
 
			clip(dissolve_value - dist/ _Radius);
 
			fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
			o.Albedo = c.rgb;
			o.Metallic = _Metallic;
			o.Smoothness = _Glossiness;
			o.Alpha = c.a;
		}
 
		ENDCG
	}
	FallBack "Diffuse"
}

```

0:00 

/0:04 

1× 

---

As you can see the objects dissolve "locally", we don't have a uniform effect because we're getting the "dissolve value" from the texture sampled with the UV of each object. (This is less noticeable in 2D).

Stay Updated 

Email sent! Check your inbox to complete your signup. 

PS. Oh hey just a heads up that if you're liking this post and would like to support us (for free!), read new ones as soon as they're ready and also unlock extra materials... please consider becoming a free member! It'll make us super happy that you're here for us, and also less anxious about algorithm changes, AI and whatever is coming next. We're a small team so it really means a lot; thank you so much! 🥹

## Uniforming the effect

To uniform the effect we can use global coordinates (world position) as the UV of the dissolve texture.  
It's also important to set "`Wrap = Repeat`" in our dissolve texture settings so we can repeat the texture without noticing it (also, make sure that the texture is seamless/repeats well!)

![](https://storage.ghost.io/c/38/36/383676a1-e894-4116-9a98-bb5a9336da39/content/images/2024/09/febucci-tutorial-world-reveal-texture-wrap-settings.jpg)

## For 2D Sprites

**HLSL**

```hlsl
half dissolve_value = tex2D(_DissolveTexture, IN.worldPos / 4).x; //I modified the worldPos to reduce the texture size

```

**Shader Graph**

![](https://storage.ghost.io/c/38/36/383676a1-e894-4116-9a98-bb5a9336da39/content/images/2024/09/febucci-world-reveal-using-world-pos-as-uv-shadergraph.jpg)
  
  
That's the result, you can already see that the dissolve texture is now uniform all around the world.  
  
This shader is already perfect for 2D games but we need to improve it for 3D objects.

### For 3D Objects

**The Wrapping Iusse**

![](https://storage.ghost.io/c/38/36/383676a1-e894-4116-9a98-bb5a9336da39/content/images/2024/09/febucci_dissolve-without-3dnoise-problem-example.jpg)
  
  
As you can see it doesn't work for "non vertical" faces, wrapping the texture badly.  
That's because the UV needs a float2 and if we pass our worldPos it only gets the X and Y.

If we fix this issue applying some math to display the texture on all faces we'll encounter a new problem: the objects intersect with each other while fading, not being uniform.

### Noise Solution

The solution is not beginner-friendly, you should remove the texture and generate a 3D Noise in the world and get the "dissolve value" from there.  
I won't cover how to generate a 3D Noise in this post but you can find a lot of ready-to-use noise functions around!

0:00 

/0:03 

1× 

Stay Updated 

Email sent! Check your inbox to complete your signup. 

PPS. Super short reminder to consider joining and helping us for free in case you're liking this post! We get to write you directly with more updates and become super happy that you find these articles useful 🫶

Here's an example of a noise shader: [https://github.com/keijiro/NoiseShader](https://github.com/keijiro/NoiseShader?ref=blog.febucci.com) You can also learn how to generate noise here: [https://thebookofshaders.com/11/](https://thebookofshaders.com/11/?ref=blog.febucci.com) and here [https://catlikecoding.com/unity/tutorials/noise/](https://catlikecoding.com/unity/tutorials/noise/?ref=blog.febucci.com)

I set my surface function this way (assuming that you already have written the noise part):

```hlsl
void surf (Input IN, inout SurfaceOutputStandard o) {
 
	float dist = distance(_PlayerPos, IN.worldPos);
 
	//"abs" because you have to make sure that the noise is between the range [0,1]
	//you can remove "abs" if your noise function returns a value between [0,1]
        //also, replace "NOISE_FUNCTION_HERE" with your 3D noise function.
	half dissolve_value = abs(NOISE_FUNCTION_HERE(IN.worldPos));
 
	float clip_value = (dissolve_value - (dist - _Radius) / _Radius) * step( _Radius , dist ) ;
	clip(clip_value);
 
	o.Emission = float3(1, 1, 1) * step( clip_value , 0.05f ) * step(_Radius, dist);
			
 
	fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
	o.Albedo = c.rgb;
	o.Metallic = _Metallic;
	o.Smoothness = _Glossiness;
	o.Alpha = c.a;
}

```

Quick reminder for HLSL: you need to write/declare every function before you use/call it.

💡

P.S. If you want to create this using Unity's Shader Graph, you should use Custom Nodes (and generate the noise writing the HLSL code in them). I'll talk about Custom Nodes in a future tutorial.

## Frequently asked questions

### What is a world reveal shader?

It's a shader that fades scene objects based on their distance from a given position (usually the player), creating the illusion that the world "reveals" itself around you as you move.

### How do I pass the player position to all shaders at once?

Call `Shader.SetGlobalVector("_PlayerPos", transform.position)` in your player's Update method. Every shader that declares `_PlayerPos` as a global variable will receive it automatically.

### Does this work with 2D sprites in Unity?

Yes. For 2D sprites you need to add `_MainTex` support and use world position as the dissolve UV, which gives a uniform look across all sprites at once.

### Why does the effect look bad on 3D objects?

Using a 2D texture with world XY coordinates breaks on non-vertical faces. The clean fix is to replace the texture with a 3D noise function sampled at the world position.

---

## Adding Outlines

To add outlines you can follow the process on my previous [Dissolve Shader tutorial](https://www.febucci.com/2018/09/dissolve-shader/?ref=blog.febucci.com).

0:00 

/0:03 

1× 
  
  
Inverting the effect

What if we want to inverse the effect? (Objects disappear if the player is near). You only need to change one line:

```hlsl
float dist = _Radius - distance(_PlayerPos, IN.worldPos);

```

The same process goes for Shader Graph.

0:00 

/0:06 

1×