Easy volumetric explosion in Unity3D

When Unity3D realeased their Unity4 update, they realeased a tech demo along with it: The Butterfly Effect

Unity4 tech demo: The Butterfly Effect

After seeing that, it made me want to make a volumetric explosion like the one you can see at the end.
So that’s what I did.

No DirectX11

Now they made that with directx 11, and my graphics card doesn’t support that, so I can’t really do the same.
So instead I tried to develop a simple way to create something that looks similar, without using any fancy stuff.

Here’s what the end result looks like:

explosions  Capture72
(ignore the weird scene-setup please)

Now I’m not saying the explosion I made looks as good as the one in the butterfly effect,
but it is volumetric, fairly inexpensive, doesn’t use alpha blending (so no sorting issues), and it writes correctly to the depth buffer.

And I like it, it looks kinda cartoony, and maybe too round, but I think it can work.

So How does it work?

In essence, it’s a sphere with displacement maps that interpolate over time,
And the color (and emission) is in relation to the extrusion amount (displacement), by using a ramp texture.

How to make it:

I’ll explain it step by step, but keep in mind that I assume Unity3D and basic game development and programming knowledge. (as well as basic Unity shader knowledge)

Step 1, making a sphere

I started of in Blender, but I’m sure most 3D modelling tools can do the same.

First create a sphere, with enough subdivisions for the displacement to work.
I used an Icosphere, instead of the default UV sphere, because vertices are more evenly spread across the surface.

Unwrap it, and make sure all vertices are within bounds.
Default automatic unwrapping should be sufficient, all 3D modelling tools should be able to unwrap a sphere properly.

Step 2, creating the displacement maps

Apply a material on the sphere with a couple of procedural textures (grayscale).
explosion_displ1
Bake these into a texture.
Make 2 more variations of these procedural textures and bake these as well.

Using Gimp or Photoshop (or anything simmilar), combine these grayscale textures into 1 texture, by placing each into a different channel (RGB), creating something like this:
explosion_displ
You could make a 4th texture and place it into the Alpha channel if you want, but I didn’t bother.

Step 3, creating the ramp texture

My ramp texture looks like this:
explosionRamp

The ramp texture is used to determine the colors of the explosion, the alpha value is used for emission.
The left pixels are used for the areas of the explosion that are only slightly extruded, the right pixels are used for the areas that are most extruded.

Step 4, creating the shader (partially)

The shader I made is a surface shader, that way the inemissive parts are properly lit, but If you don’t want that, you can write it as a simple vertex/fragment shader.

Start off with 4 properties:
_RampTex (“Color Ramp”, 2D) = “white” {}
_DispTex (“Displacement Texture”, 2D) = “gray” {}
_Displacement (“Displacement”, Range(0, 1.0)) = 0.1
_ChannelFactor (“ChannelFactor (r,g,b)”, Vector) = (1,0,0)

In the Vertex shader we offset the vertices based on a texture lookup using the displacement texture.
The color we get from this contains the displacement value according to all 3 displacement textures (RGB).
By using the float3 property I called _ChannelFactor (that is set in a script each frame, see lower), we determine the actual displacement, by taking the sum of the 3 values multiplied by the corresponding RGB value.

In the Surface shader, we do the same texture lookup,
using that value as the UV.x (UV.y can be anything), we do another lookup using the ramp texture.
We assign that color as the Albedo color, and the color multiplied by the alpha as Emission.
We could also assign the color in the Vertex shader, but then the colors would be interpolated between the vertices, whereas if we calculate the color in the surface/fragment shader, we get a correcter result.
But assigning it there is faster, as it would discard the need to do the displacement texture lookup in the surface shader again, so decide yourself what’s more important.

Step 5, animating the displacement

Now create a script, attached to the explosion, with a single public variable, the loopduration,
in the update loop we will determine the ChannelFactor, and assign it to the shader.
I used 3 sin functions (1 for each channel), and made sure their sum is 1 (though this is not necessary).

float r = Mathf.Sin((Time.time / loopduration) * (2 * Mathf.PI)) * 0.5f + 0.25f;
float g = Mathf.Sin((Time.time / loopduration + 0.33333333f) * 2 * Mathf.PI) * 0.5f + 0.25f;
float b = Mathf.Sin((Time.time / loopduration + 0.66666667f) * 2 * Mathf.PI) * 0.5f + 0.25f;
float correction = 1 / (r + g + b);
r *= correction;
g *= correction;
b *= correction;
renderer.material.SetVector("_ChannelFactor", new Vector4(r,g,b,0));

It should look something like this now:

explosionLoop

Step 6, animating the explosion

Now the explosion loops endlessly, but we want it to grow and change color over time, and it needs to “fade out” somehow.

Add 2 more properties to the shader: the minimum value and maximum value for the ramp texture.
They determine the range of the ramp texture to use, by animating this (in an AnimationClip, or in code), you can change the look of the explosion over time.

Add another property to the shader: the clipping value.
The clipping value determines at what displacement amount to clip (cut holes in the mesh), by animating this (in an AnimationClip, or in code), you can fade out the explosion over time.
Unfortunately, this is a sharp cut, but because the displacement is still animated, the holes constantly change shape, making it not that big of an issue (IMO).

To make the explosion grow, simply animate it’s scale in an AnimationClip or in code.

explosionLoop2

Step 7, finishing touches

Add a point light inside the explosion (and animate this aswell).

You can also place a smoke particle system inside it, so that when the explosion starts clipping away, it looks like it fades into smoke.

I also made the shader 2-sided (clipping off), so that when the camera is inside the shell, you still see the explosion.

Using a Bloom or Glow post effect also helps sell the effect.

And that’s it, all done!

Full shader code:

Shader "Custom/Explosion" 
{
	Properties 
	{
		_RampTex ("Color Ramp", 2D) = "white" {}
		_DispTex ("Displacement Texture", 2D) = "gray" {}
		_Displacement ("Displacement", Range(0, 1.0)) = 0.1
		_ChannelFactor ("ChannelFactor (r,g,b)", Vector) = (1,0,0)
		_Range ("Range (min,max)", Vector) = (0,0.5,0)
		_ClipRange ("ClipRange [0,1]", float) = 0.8
	}

	SubShader 
	{
		Tags { "RenderType"="Opaque" }
		Cull Off
		LOD 300

		CGPROGRAM
		#pragma surface surf Lambert vertex:disp nolightmap
		#pragma target 3.0
		#pragma glsl

		sampler2D _DispTex;
		float _Displacement;
		float3 _ChannelFactor;
		float2 _Range;
		float _ClipRange;

		struct Input 
		{
			float2 uv_DispTex;
		};

		void disp (inout appdata_full v)
		{
			float3 dcolor = tex2Dlod (_DispTex, float4(v.texcoord.xy,0,0));
			float d = (dcolor.r*_ChannelFactor.r + dcolor.g*_ChannelFactor.g + dcolor.b*_ChannelFactor.b);
			v.vertex.xyz += v.normal * d * _Displacement;
		}

		sampler2D _RampTex;

		void surf (Input IN, inout SurfaceOutput o) 
		{
			float3 dcolor = tex2D (_DispTex, IN.uv_DispTex);
			float d = (dcolor.r*_ChannelFactor.r + dcolor.g*_ChannelFactor.g + dcolor.b*_ChannelFactor.b) * (_Range.y-_Range.x) + _Range.x;
			clip (_ClipRange-d);
			half4 c = tex2D (_RampTex, float2(d,0.5));
			o.Albedo = c.rgb;
			o.Emission = c.rgb*c.a;
		}
		ENDCG
	}
	FallBack "Diffuse"
}
About these ads

43 thoughts on “Easy volumetric explosion in Unity3D

  1. Hi Steven, can you share the full code for the surface shader. Its my first time coding shaders and i cant get it to pick from the ChannelFactor. Please
    FYI, this is definately not an Easy Volumetric Explosion, I have the eyebags to proove it.

  2. haha, it’s easy compared to the volumetric explosion they used in the butterfly effect clip, as it’s it’s just a combination of fairly simple shader stuff.
    If you’re new to shaders however, then it’s not so easy I suppose (especially in Unity).
    In my post I assumed the readers to have some Unity surface shader knowledge.
    Alright, I’ll add the full shader code to the post.

  3. Hello Steven, this method is just awesome, thank you
    Anyway, i’m facing a problem.
    I’m using Unity 4 and after i created a shader with your code,
    i saw there is no slot for ramp texture on inspector
    so where do i have to put the ramp texture?
    the shader itself working perfectly, but without no ramp texture
    the explosion become grayscaled
    can you help me with this problem?
    it will be glad to me if you may send a Unity package to my email below:

    Kind regards,

  4. Ah, woops, the shader code I posted at the bottom of the post used a different name for the ramp texture than in the rest of the post (It was called “Base (RGB)” instead of “Color Ramp”).
    I fixed it now.
    In case you’re not familliar with writing shaders in Unity; the “Properties”-part of the shader defines what can be set in the editor.
    The line _RampTex (“Color Ramp”, 2D) = “white” {} defines a texture slot (2D) that is called “_RampTex” internally and displayed in the editor as “Color Ramp“, with the default texture beeing a full white texture (= “white” {}).

  5. Hi Steve,

    Just a quick thanks for this post – very useful. I have managed to recreate your volumetric explosion effect and added a few lighting effects to further enhance for a small game/POC I was working on.

    Cheers

  6. Pingback: Getting started with Unity 3D, and a small game prototype | Hobbyist coder

  7. If I remember correctly, it’s a fairly basic particle system using one of the default smoke textures with an alpha blended material.
    The particles fade in fast and out slowly, and they scale a little up over their lifetime. They also have a random rotation and a slow random rotational speed.
    The only other important thing, I think, is that you have to time them properly so they are only visible (more or less) when the explosion starts clipping away. (you don’t want to see the smoke when the explosion is still completely fiery)

  8. No homo but i love you XD i have been looking for a shader like this for like ages. I will credit you in my game you are great XD :)

  9. Hey, first of all im very begineer at the shader stuffs. I did all of your steps, but when i apply the material into my blender model at unity, the sphere is totally black colored… May i ask you to can you make a unitypackage which include the model, material, and the final explosion?

  10. strange, are you sure the shader is correct? (you can compare with the one at the bottom of the post). And the material’s parameters are set properly?

    I’ll see if I can find some time to make a unitypackage and upload it somewhere.

    The reason I hadn’t yet was because I thought this way (without having the final version available) caused people to make it themselves, allowing them to understand it better and allowing them to make changes where they see fit, causing them to learn from it and create something unique, rather than just using the one I made without understanding how it works.

  11. Great article! I am just sad to not have a render as good as yours, I guess you kept some stuff secret and I understand. But could you tell me about the sphere, how many triangles does it have ? I am wondering if my poor rendering comes from the fact I don’t have enough polygons.

  12. Hey Steve, thanks for this cool little tip, however I’m not getting any displacement :/ Do you know why this could be? I’m not getting any compiler errors. Also please could you post the script, preferably in C# just because I’m not sure if I’ve done it right. Many thanks in advance.

  13. Hi there – I’d like to echo the request for the unity file. This is a great article, missing critical information. I’ve given it a few hours but as I don’t even know how to make the shader aware of the ramp image I’m just giving up. With infinite time maybe I’d get the explosion working one day, but I can’t see how at the moment. It’s a pity, as what you’ve made looks nice.

  14. Unfortunately, it seems that my displacement is uniform, and the whole sphere simply “bubbles” up and down. Doesn’t look good at all.

  15. This works great in the editor, but is there a way to make it work with iOS? All I get is a black sphere. I’m not familiar enough with shaders to know what is keeping it from working, if it will at all on iOS. Thanks for sharing this, I learned a lot from it.

  16. @ Kurt: Strange, the piece of code I posted is pretty much the entire script, there’s really nothing more to it, that code is just placed in an Update() function (maybe you forgot that?). If you’re having problems with the shader, I posted the full shader code as well, you can just use that.

  17. @ Sonny: I really didn’t intentionally kept anything secret.
    The sphere is quite big (in polycount), it has about 15000 vertices and 30000 tris, but halve of that should be more than sufficient normally.

  18. @ Aleksey Abramenko: did you make that with my volumetric explosion tutorial, or is are you just showing an example of what it could be used for?
    cause that looks really great!

  19. @ Robin Jubber: That’s unfortunate, it’s strange how it just doesn’t seem to work for some people, I’ve really added all necessary info in my post. I even added the full shader code and c# code, I really don’t see how it doesn’t work then.
    I really didn’t intend it to be so troublesome, I just figured it’s better to give a tutorial than to give the finished work, so people would actually understand how it works and learn from it so they can even perhaps improve on it.

  20. @ MIke M: Thanks. Unfortunately my knowledge of iOs development is pretty limited, I have no idea what the restrictions are. :s
    Strange though, you say it works in editor just not on iOs? I would expect it to throw an error then if it does stuff that can’t be done on iOs.

  21. Hi there Steven – it’s certainly a cool effect you’ve created and I’ve learnt a bit about both shaders and the process the model needs to undergo in its creation – and I appreciate your desire for people to learn from your example. However as use of Unity is likely to involve people with all sorts of different skill levels, some of us are going to be caught out or stopped in our tracks when we fail to perform some operation a more experienced Unity user might employ without thinking about it. A unity project with the explosion in it would make sure we can spot where we’ve made mistakes and better see the relationshop between various elements. To put it another way – if I can’t get it to work, my learning experience ends there, in failure.

  22. Your shader is really awesome an impressive! If i want to use it on mobile, do you know is there any way to replace the clip instruction in the shader? I tried to modify other dissolve shader codes to use if-else but the performance is as bad as using the clip instruction one.

  23. @ Robin Jubber :
    Don’t know if you had seen my comment just before yours, I linked to a package someone else uploaded containing the explosion, you could download that one.
    To be honest, it’s kinda weird that I’m linking to someone else’s version of my explosion, so maybe I should just upload the original one on the asset store and link to that.

  24. @ cmw :
    uh, you can’t replace clip() with if-else, if you want to discard a pixel, you have to use clip(). Unless you change the alpha and have it be a transparent shader, but I can’t see how performance could benefit from that.
    Also if-else is generally a no go in shaders.
    Anyway, I’m not so familiar with mobile stuff, so can’t really help you, sorry.
    But I’m wondering, is the performance bad, or does it just not work? Cause I can’t really see how it would not work on mobile, technically speaking, it’s not that advanced a shader.

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