World reveal shader

By 13/09/2018 March 20th, 2019 Shaders

A “world reveal” shader (a.k.a. “dissolve the world shader” or “global dissolve“) lets you uniformly fade all the objects in your scene based on their distance from a position; today we ll create our one in Unity’s Shader Graph and write it in HLSL.

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

Since this is the part-2, I highly suggest you to read my previous tutorial about “dissolve shaders.


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.

PLAYER POSITION

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


SHADER GRAPH

Object Position and Distance

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

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 read my previous tutorial about Sprites diffuse shader (using shader graph).


HLSL (surface)

Object Position

In HLSL we can add the variable “worldPos” in our Input struct to get the vertex position of our objects.

You can see what other built-in parameters you can add to the Input struct in this Unity’s documentation page.

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).

RESULT(3D)

RESULT(2D)

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).


HLSL 3D LocalUV Dissolve Shader

HLSL – Sprites Diffuse – LocalUV Dissolve Shader

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.


UNIFORM 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!)

HLSL (Surface)

Shader Graph

RESULT (2D)

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.

THE PROBLEM WITH 3D OBJECTS

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.

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!

Here’s an example of a noise shader: https://github.com/keijiro/NoiseShader
You can also learn how to generate noise here: https://thebookofshaders.com/11/ and here https://catlikecoding.com/unity/tutorials/noise/

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

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.

RESULT (3D)

 


ADDING OUTLINES

To add outlines you can follow the process on my previous tutorial here.


INVERSE EFFECT

What if we want to inverse the effect? (Objects disappear if the player is near)

You only need to change one line: float dist = _Radius - distance(_PlayerPos, IN.worldPos);

(The same process goes for Shader Graph).