Hello fellow Gamedevs!

Today I’d like to share a tutorial how to create heatwave/shockwave effect in a 2D game:

There is little information on how to work with displacement shaders properly in Unity so hopefully this short article will save you a lot of time.

Download assets or a ready-to-go Unity Package first and open them/it in Unity.

Learning by doing FTW!

Idea

First of all we’ve got to realize what this graphical effect that we call shockwave really is. If you pause the above gif and look closely enough, you’ll see that pixels are slightly shifted in the direction of the wave’s movement.

So in order to make a shockwave like this we need to:

a) create a moving ring (it’s called annulus in mathematics I kid you not)

b) create an effect that shifts pixels in a certain direction

c) combine the two

The Ring

Creating a moving ring is pretty straightforward. Make a new game object, give it a shiny SpriteRenderer with sonar.png and attach the ShockwaveScript.

Make a background out of the attached floor tiles so you can actually see the effect.

Change the material of the ring to WaveEffectMaterial. Don’t worry about this now, I’ll explain later what it does.

What does ShockwaveScript script do? Not much. It changes the scale of the ring to create the illusion of perpetual movement. If you don’t understand the script below then have some fun with parameters (change 0.01f to something different etc.) for a quick Eureka! moment.

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class ShockwaveScript : MonoBehaviour {

void Update ()

{

transform.localScale += new Vector3(0.01f, 0.01f, 0.01f);

if(transform.localScale.x > 2f)

{

transform.localScale = new Vector3(0.01f, 0.01f, 0.01f);

}

}

}

If everything works now is the time for something a bit harder.

The pixel displacement shader

DISCLAIMER: I won’t get into much detail on how to write shaders – I’ll assume you know the basics. If not read up. I’ll just keep to the relevant parts for our effect.

So as we’ve discussed – we need to shift some pixels to create a shockwave effect. This can be achieved using a shader that grabs the screen pixel data first and then manipulates it.

This kind of shader uses a mechanism called Grab Pass. Adding this little code:

GrabPass

{

"_BackgroundTexture"

}



somewhere in your shader will load all the pixels on screen to a variable of your choice (_BackgroundTexture in this case).

Then we go through all the pixels on screen. Instead of painting a color we found we paint a color of a different pixel, slightly outwards the center of the ring.

Here’s the crucial function:

half4 frag(v2f i) : SV_Target

{

half4 d = tex2D(_NoiseTex, i.grabPos);

We use a noise texture to randomize the effect (some pixels are shifted further) and load it into half4 d variable.

float4 p = i.grabPos + (d * _Intensity);



p variable holds the shifted position of the pixel.

half4 bgcolor = tex2Dproj(_BackgroundTexture, p);



So instead of getting the color of the pixel at i.grabPos, we grab it at p.

return bgcolor;

}



That’s it! Feel free to ask me any questions and if you like my work please support me on Patreon or buy my game when it’s out.

