Thermal/ Stealth Vision Effect

This one has been requested a few times.

In this post I'll set up a Thermal Vision effect with replacement shaders.

Thermal Shader

On researching how to best start a thermal look shader, I came across a matcap shader posted by bgolus on the Unity Forums, a nice starting point.

I've modified it a lot to make it more consistent on different angles, by basing the cap on the vertex and normals, so it's not really a matcap anymore, but I wanted to give credit to the starting shader.

Going through the steps, first in the vertex function:

1. The object normals

float3 v.normal;

2. Normalized vertex position, will start from the pivot of the model

float3 vertexN = normalize(v.vertex);

3. Cross product of these values

float3 viewCross = cross(vertexN, v.normal);

4. Half the crossproduct.xy and offset to create a more even result

o.cap = viewCross.xy * 0.5 + 0.5;

Over to the fragment function

5. Create a mask and multiply inverted

fixed4 m = tex2D(_Mask, i.uv);
i.cap *= (1 - m.g);

6. Project color texture over result. (I'm using the orange-purple style, but you can use the bigger gradient/ something else too of course)

fixed4 color = tex2D(_Matcap, i.cap);

That's it for the thermal shader, one important part is to give it a custom tag so the replacement script can set it properly, so make sure the tags contain this:

 Tags{  "ThermalVision" = "ThermalColors"} 

Here's the full shader:  Pastebin Link  

Replacing Shader

In order to get the thermal shader to replace another, you just need to that same tag to the shader you want to replace:

Tags{  "ThermalVision" = "ThermalColors"}

  And make sure that all the properties you need are also exposed to the replaced shader:

_Mask("G = no thermal", 2D) = "black" {}
_Matcap("Matcap", 2D) = "white" {}
_Strength("Mask Strength", Range(0,2)) = 0.4 

To swap out a shader, we need to add a second camera, and call  

camera.SetReplacementShader(Shader, "NamedShader");

on it.

So, create a new camera, and parent it to your main camera, and zero out the position/rotation so it's in the same place.

Set it to Solid Color, and black background. 

In the "Camera Preview" you should see the same as the normal camera, only no Skybox, just black.

Time to set the replacements,

Add a public Shader variable, and drop the thermal effect shader in there.

Then add the camera as a new variable, and in Start call SetReplacementShader , using the public shader, and the name we've given it in the tags

  public Shader ThermalShader;
  Camera cam;
   void Start()
 cam = GetComponent<Camera>();
 cam.SetReplacementShader(ThermalShader, "ThermalVision");

When you run this, you should only see the thermal effect on the meshes with the replaced shader.

Image Effect

At this point the thermal shader is clearly visible, but we can't see anything else. To add a bit of an environment back to the camera, I'm using the DepthNormals texture in an Image Effect in combination with the Opaque texture.

Image Effect Shader: Pastebin Link 

Add this simple Blit script to the thermal camera, and drag in the Image Effect Shader

I put in the same image as the thermal shader, but you can add different ones of course!

Thermal Switching Script

All that's needed now is to trigger it during playtime.

I'm using the T key to switch a bool that turns on the camera, sets the replacement, and sets a post processing volume to full strength. And in reverse when you press T again.

Add some post-processing to the thermal camera to finish up. I added Chromatic Abberation and Depth of Field 

Here's the Thermal Switching Script: Pastebin Link 

(Using PPS 2, might need to be updated for newer version of the Post Processing stack)


If you don't want the effect to show through walls, Set the replacement camera to "Don't Clear" instead of "Solid Color". If you want the Skybox to turn black as well, in the switching code. Cache the Skybox Material, set it to null

Private Material SkyboxMaterial;
skyboxMaterial = RenderSettings.skybox;
RenderSettings.skybox = null;

 then return it again when the thermal effect is off.

RenderSettings.skybox = skyboxMaterial;

Now it's less of a gameplay mechanic and more just a visual effect.

Quick Start if you don't care about explanation:

1.Grab Thermal Effect Shader

2. Grab Replaced Toon Shader OR add "ThermalVision" = "ThermalColors" , and _Matcap, _Mask , _Strength variables to your own shader

3. Create Second camera under your main camera, set to Solid Color, Black Background

4. Grab Thermal Image Effect Shader, create Material, and add ThermalBlit Script to this second camera, dragging in that material.

5. Add ThermalController script, drag in Thermal Effect Shader, add in a post process volume (optional)

6. Press T to switch vision. (Make sure whatever you want to show up has the replaced shader).


Shader Code Thermal Effect: Pastebin Link 

Shader Code Replaced Toon Shader: Pastebin Link 

Shader Code Image Effect: Pastebin Link 

C# Script Blit : Pastebin Link 

C# Script Thermal Switcher:  Pastebin Link  

Matcap Images:

More info on Replacement Shaders:

This old video is where I first learned about them

Video on Replacement Shaders by Making stuff look good in Unity 

By becoming a patron, you'll instantly unlock access to 104 exclusive posts
By becoming a patron, you'll instantly unlock access to 104 exclusive posts
Tier Benefits
Recent Posts