Simple Smoke Effect Explained

A few people have asked how I created the smoke effect for Stranger on the 103rd Floor and it’s actually quite simple so I thought I’d create a little how-to post.

Software used: Unity & Blender, Assets: Toony Colours Pro

Blender

Firstly I created a a simple cloud model in Blender. I did this by creating some low poly spheres and rearranging and sizing them until I found a shape I liked. If you’re new to Blender, you may find this task a bit awkward as it’s not the most beginner friendly program but here are some steps to help

First open Blender, where you should be presented with the basic cube, lamp and camera. We’ll need to delete these, so select each of them and press X, then delete

Untitled-2
Deleting the base objects

Next add an ico sphere. The number of subdivisions can be changed in the left hand side menu depending on the detail you want in the smoke clouds. The sphere can be moved around the screen using the x/y/z axis arrows or freehand (I like to use the arrows as it gives me more control). Pressing Ctrl-Alt-Q will split the screen into orthographic views which I find super helpful for positioning as it’s easier to see multiple objects relative to each other

Untitled-1
Adding an Ico Sphere

For this particular smoke effect, I created multiple ico spheres and grouped them into a cluster similar to the one below. Multiple objects can be joined together into one by highlighting the objects and pressing Ctrl-J (this is optional in this example). Also depending on what style you’re going for you can apply smooth shading to the ico spheres so their surface appears rounded rather than flat. To do this highlight all the vertices while in edit mode, press W and select “Shade Smooth”. Then save the smoke as a .blend file and you’re done!

Untitled-3
Resulting Ico Sphere Cluster

Unity

The resulting .blend file can then be dropped into your Unity project. Create a new material and add it to the Blender model before applying Toony Colours Pro shaders. There’s tonnes of different ways you can shade the object but I chose a very simple no shadow set-up with an outline to achieve my affect. I’d advise you to experiment and come up with something unique as it’s easy to do and can make a big difference to the look.

Untitled-4
Simple differences in shading

Below are my settings for the shader, keeping it super simple (As I’m not using the full potential of Toony Colours Pro here, you could probably write your own shader to do the same, but I’m no shader expert and using the asset worked perfectly for me)

Toony Colours Settings

Now that the model is done, we move onto the scripting needed to create that billowing effect. First create a script which instantiates a new smoke particle at a fixed interval of time called “Emitter” and attached it to a game object. It’s a super simple timer based emitter, but I created this first so it’s easier to test and see the effects of the smoke particle behaviour later. A low time interval is needed to create a thick smoke effect

using UnityEngine;
using System.Collections;

public class Emitter : MonoBehaviour
{
   public GameObject Emitted;

   [Range(0.0f, 10.0f)]
   public float TimeDelay;
   float Count;

   void Update ()
   {
      Count -= Time.deltaTime;

      if (Count <= 0) {
         GameObject _emit = Instantiate (Emitted, transform.position, transform.rotation) as GameObject;
         Count = TimeDelay;
      }
   }
}

Next I created the “SmokeParticleBehaviour” script, which is where all the work is done. This script is attached to a game object containing a Rigidbody2D and the Smoke Particle model, created earlier (In my case the model is a child object of the Smoke_Particle).

Object

One of the most important aspects of the script is the animation curve. Animation curves allow you to manually define a curve in the inspector, and evaluate the y-axis according to the x-axis input. For example, for this application, the x-axis will be the time the smoke particle has been active, and the y-axis will be the scale of the object, so once it’s instantiated,  as the x axis value gets higher, the scale (which is based on the y-axis), will grow larger and smaller according to the curve we create. Keyframes can be added to give you more control over the shape of the curve by right clicking and selecting “Add Key”

Curve
Sample Animation Curve

If you’re not familiar with animation curves there is a more in depth tutorial on them here.

First a number of variables need to be declared. These include:

  • ScaleSize: public animation curve which can be manually set
  • LifeTime: public float to say how long the the smoke particle will stay active for before being destroyed
  • Counter: float to count how long the smoke particle has been active
  • RB: The Rigidbody2D component of the object

In the Start method, the rigidbody which is attached is found and some of the variables are set with a random element so the particles aren’t too uniform. The scale is also set 0.

In the Update method, the Counter records how long the smoke particle has been active for. As our animation curves x-axis is set to between 0 and 1, by dividing the Counter value by the LifeTime variable we can get the relative position on the x-axis of the ScaleSize graph. Then by using ScaleSize.Evaluate, we can get the related position on the y-axis and use it as the new scale for the smoke particle.

Finally, once the Counter reaches the LifeTime length that was previously set, the gameobject destroys itself

Below is this simplified version of the script

using UnityEngine;
using System.Collections;

public class SmokeParticleBehaviour : MonoBehaviour
{
   public AnimationCurve ScaleSize;
   public float LifeTime = 2.6f;
   float Counter = 0;
   Rigidbody2D RB;

   void Start()
   {
      RB = GetComponent<Rigidbody2D>();
      RB.gravityScale = Random.Range(-.5f, -.6f);
      RB.AddForce(Vector2.right * Random.Range(-10, 10));
      transform.localScale = new Vector2(0,0);
   }

   void Update()
   {
      Counter += Time.deltaTime;
      float Scale = ScaleSize.Evaluate(Counter / LifeTime);
      transform.localScale = new Vector3(Scale, Scale, Scale);

      if (Counter >= LifeTime)
         Destroy(gameObject);

   }
}

I’ve left out a few details from the script for simplicity but they should be easy to fill in. This includes rotation of the gameobject as it rises (this can be done as a constant rotation or with another animation curve) and also a slight offset to the left and the right as it rises to make it seem more natural (this is done above with a small addForce to either the left or the right on starting but can be changed to another method  or applied as it rises). How you want to do this and how much randomness you put in each function is up to you

Other things to note:

The smoke in Stranger on the 103rd Floor is actually functional, e.g. it can block lasers and the enemies vision so you can sneak past them, and will be one of the more commonly used items. To make it do these additional functions, I added a Collider2D to the smoke particle. This also means it collides with tiles rather than going through them

So that’s it! There’s a few ways it could be built upon and optimised but this is a simplified version to give you a general idea on how to create you’re own version, so I hope it helps. If there’s any details I’ve left out or additional stuff you’d like to know, send me a message or ask me on twitter @sopcen.

For updates on the game you can follow me on twitter, or check out the TIGSource devlog or IndieDB

Advertisement
Privacy Settings

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 )

Connecting to %s