Special Effects

In this article by Maciej Szczesnik, author of Unity 5.x Animation Cookbook, we will cover the following recipes:

  • Creating camera shakes with the Animation View and Animator Controller
  • Using the Animation View to animate public script variables
  • Using additive Mecanim layers of add extra motion to a character
  • Using Blend Shapes to morph an object into another one

(For more resources related to this topic, see here.)

Introduction

This one is all about encouraging you to experiment with Unity's animation system. In the next ten recipes, we will create interesting effects and use animations in new, creative ways.

Using Animation Events to trigger sound and visual effects

This recipe shows a simple, generic way of playing different sound and visual effects with Animation Events.

Getting ready

To start with, you need to have a character with one, looped animation—Jump. We also need a sound effect and a particle system. We will need a transparent DustParticle.png texture for the particle system. It should resemble a small dust cloud. In the Rigs directory, you will find all the animations you need, and in the Resources folder, you'll find other required assets. When you play the game, you will see a character using the Jump animation. It will also play a sound effect and a particle effect while landing.

How to do it...

To play sound and visual effects with Animation Events, follow these steps:

  1. Import the character with the Jump animation.
  2. In the Import Settings, Animation tab, select the Jump animation.
  3. Make it loop.
  4. Go to the Events section.
  5. Scrub through the timeline in the Preview section, and click on Add Event Button. The Edit Animation Event window will appear.

    Edit Animation Event window
  6. Type Sound in the Function field and Jump in the String field. This will call a Sound function in a script attached to the character and pass the Jump word as a string parameter to it.
  7. Create another Animation Event. Set the Function field to Effect and the String field to Dust.
  8. Apply Import Settings.
  9. Create Animator Controller for the character with just the Jump animation in it.
  10. Place the character in a scene.
  11. Attach the controller to the Animator component of the character.
  12. Attach an Audio Source component to the character.
  13. Uncheck the Play On Awake option.
  14. Create an empty Game Object and name it Dust.
  15. Add a Particle System component to it. This will be our dust effect.
  16. Set the Particle System parameters as follows:
    • Duration to 1 second.
    • Start Life Time to 0,5 seconds.
    •      Start Speed to 0,4.
    •      Start Size to random between two constants: 1 and 2.
    •      Start Color to a light brown.
    •      Emission | Rate to 0.
    •      Emission | Bursts to one burst with time set to 0, min and max set to 5.
    •      Shape | Shape to Sphere.
    •      Shape | Radius to 0.2.
    •     For Color Over Lifetime, create a gradient for the alpha channel. In the 0% mark and 100% mark, it should be set to 0. In the 10% and 90% mark, it should be set to 255.
  17. Create a new Material and set the shader by navigating to Particles | Alpha Blended.
  18. Drag and drop a transparent texture of DustParticle.png into the Texture field of Material.
  19. Drag and drop Material by navigating to the Renderer | Material slot of our Dust Particle System.
  20. Create a Resources folder in the project's structure. Unity can load assets from the Resources folder in runtime without the need of referencing them as prefabs.
  21. Drag and drop the Jump.ogg sound and Dust Game Object into the Resources folder.
  22. Write a new script and name it TriggerEffects.cs.

    This script has two public void functions. Both are called from the Jump animation as Animation Events. In the first function, we load an Audio Clip from the Resources folder. We set the Audio Clip name in the Animation Event itself as a string parameter (it was set to Jump). When we successfully load the Audio Clip, we play it using the Audio Source component, reference to which we store in the source variable. We also randomize the pitch of the Audio Source to have a little variation when playing the Jump.ogg sound.

    public void Sound (string soundResourceName) {
        AudioClip clip = (AudioClip)
        Resources.Load(soundResourceName);
        if (clip != null)
        {
            source.pitch = Random.Range(0.9f, 1.2f);
            source.PlayOneShot(clip);
        }
    }
  23. In the second function, we try to load a prefab with the name specified as the function's parameter. We also set this name in the Animation Event (it was set to Dust). If we manage to load the prefab, we instantiate it, creating the dust effect under our character's feet.
    public void Effect (string effectResourceName) {
        GameObject effectResource =
         (GameObject)Resources.Load(effectResourceName);
        if (effectResource != null)
        {
            GameObject.Instantiate(effectResource,
            transform.position, Quaternion.identity);
        }
    }
  24. Assign the script to our character and play the game to see the effect.

How it works...

We are using one important feature of Animation Events in this recipe: the possibility of a passing string, int, or float parameter to our script's functions. This way, we can create one function to play all the sound effects associated with our character and pass clip names as string parameters from the Animation Events. The same concept is used to spawn the Dust effect.

The Resources folder is needed to get any resource (prefab, texture, audio clip, and so on.) with the Resources.Load(string path) function. This method is convenient in order to load assets using their names.

There's more...

Our Dust effect has the AutoDestroy.cs script attached to make it disappear after a certain period of time. You can find that script in the Shared Scripts folder in the provided Unity project example.

Creating camera shakes with the Animation View and the Animator Controller

In this recipe, we will use a simple but very effective method to create camera shakes. These effects are often used to emphasize impacts or explosions in our games.

Getting ready...

You don't need anything special for this recipe. We will create everything from scratch in Unity. You can also download the provided example. When you open the Example.scene scene and play the game, you can press Space to see a simple camera shake effect.

How to do it...

To create a camera shake effect, follow these steps:

  1. Create an empty Game Object in Scene View and name it CameraRig.
  2. Parent Main Camera to CameraRig.
  3. Select Main Camera and add an Animator component to it.
  4. Open Animation View.
  5. Create a new Animation Clip and call it CamNormal. The camera should have no motion in this clip. Add keys for both the camera's position and its rotation.
  6. Create another Animation Clip and call it CameraShake. Animate the camera's rotation and position it to create a shake effect. The animation should be for about 0.5 seconds.
  7. Open the automatically created Main Camera controller.
  8. Add a Shake Trigger parameter.
  9. Create two transitions:
    •      Navigate to CamNormal | CameraShake with this condition: Shake the Trigger parameter, Has Exit Time is set to false, and Transition Duration is set to 0.2 seconds.
    •      Navigate to CameraShake | CamNormal with no conditions, Has Exit Time is set to true, and Transition Duration is set to 0.2 seconds.
  10. Write a new script and call it CamShake.cs.
  11. In this script's Update() function, we check whether the player pressed the Space key. If so, we trigger the Shake Trigger in our controller.
    if (Input.GetKeyDown(KeyCode.Space))
    {
        anim.SetTrigger("Shake");
    }

    As always, the anim variable holds the reference to the Animator component and is set in the Start() function with the GetComponent<Animator>() method.

  12. Assign the script to Main Camera.
  13. Play the game and press Space to see the effect.

How it works...

In this recipe, we've animated the camera's position and rotation relative to the CameraRig object. This way, we can still move CameraRig (or attach it to a character). Our CameraShake animation affects only the local position and rotation of the camera. In the script, we simply call the Shake Trigger to play the CameraShake animation once.

There's more...

You can create more sophisticated camera shake effects with Blend Trees. To do so, prepare several shake animations of different strengths and blend them in a Blend Tree using a Strengthfloat parameter. This way, you will be able to set the shake's strength, depending on different situations in the game (the distance from an explosion, for instance).

Using the Animation View to animate public script variables

In Unity, we can animate public script variables. The most standard types are supported. We can use this to achieve interesting effects that are not possible to achieve directly. For instance, we can animate the fog's color and density, which is not directly accessible through the Animation View.

Getting ready...

In this recipe, everything will be created from scratch, so you don't need to prepare any special assets. You can find the Example.scene scene there. If you open it and press Space, you can observe the fog changing color and density. This is achieved by animating the public variables of a script.

Animated fog

How to do it...

To animate public script variables, follow these steps:

  1. Create a new script and call it FogAnimator.cs.
  2. Create two public variables in this script: public float fogDensity and public Color fogColor.
  3. In the script's Update() function, we call the o Trigger in the controller when the player presses Space. We also set the RenderSettings.fogColor and RenderSettings.fogDensity parameters using our public variables. We also adjust the main camera's background color to match the fog color.
    if (Input.GetKeyDown(KeyCode.Space))
    {
        anim.SetTrigger("ChangeFog");
    }
    RenderSettings.fogColor = fogColor;
    RenderSettings.fogDensity = fogDensity;
    
    Camera.main.backgroundColor = fogColor;
  4. Create a new Game Object and name it FogAnimator.
  5. Attach the FogAnimator.cs script to it.
  6. Select the FogAnimator game object and add an Animator component to it.
  7. Open the Animation View.
  8. Create a new Animation Clip.
  9. Make sure Record Button is pressed.
  10. Create an animation for the public float fogDensity and public Color fogColor parameters by changing their values.
  11. You can create any number of animations and connect them in the automatically created Animator Controller with transitions based on the ChangeFog Trigger (you need to add this parameter to the controller first).
  12. Here's an example controller:

    An example controller for different fog animations
  13. Remember that you don't need to create animations of the fog changing its color or density. You can rely on blending between animations in the controller. All you need to have is one key for the density and one for the color in each animation. In this example, all Transition Durations are set to 1 second, and every transition's Has Exit Time parameter is set to false.
  14. Make sure that the fog is enabled in the Lighting settings.
  15. Play the game and press the Space button to see the effect.

How it works...

Normally, we can't animate the fog's color or density using the Animation View. But we can do this easily with a script that sets the RenderSettings.fogColor and RenderSettings.fogDensity parameters in every frame. We use animations to change the script's public variables values in time. This way, we've created a workaround in order to animate fog in Unity.

We've just scratched the surface of what's possible in terms of animating public script variables. Try experimenting with them to achieve awesome effects.

Using additive Mecanim layers to add extra motion to a character

In previous recipes, we used Mecanim layers in the override mode. We can set a layer to be additive. This can add additional movement to our base layer animations.

Getting ready...

We will need a character with three animations—Idle, TiredReference, and Tired. The first animation is a normal, stationary idle. The second animation has no motion and is used as a reference pose to calculate the additive motion from the third animation. TiredReference can be the first frame of the Tired animation. In the Tired animation, we can see our character breathing heavily.

You will find the same Humanoid character there. If you play the game and press Space, our character will start breathing heavily while still using the Idle animation. You can find all the required animations in the Rigs directory.

How to do it...

To use additive layers, follow these steps:

  1. Import the character into Unity and place it in a scene.
  2. Go to the Animation tab in Import Settings.
  3. Find the TiredReference animation and check the Additive Reference Pose option (you can also use the normal Tired animation and specify the frame in the Pose Frame field).
  4. Loop the Idle and Tired animations.
  5. Create a new Animator Controller.
  6. Drag and drop the Idle animation into the controller and make it the default state.
  7. Find the Layers tab in upper-left corner of the Animator window.
  8. Select it and click on the Plus button below to add a new layer.
  9. Name the newly created layer Tired.
  10. Click on the Gear icon and set the Blending to Additive. Take a look at this diagram for reference:
                                                                                                          Additive layer settings
  11. Drag and drop the Tired animation to the newly created layer.
  12. Assign the controller to our character.
  13. Create a new script and call it Tired.cs. In this script's Update() function, we set the weight of the Tired layer when the player presses Space. The Tired layer has an index of 1. We use a weightTarget helper variable to set the new weight to 0 or 1, depending on its current value. This allows us to switch the additive layer on and off every time the player presses Space. Finally, we interpolate the weight value in time to make the transition more smooth, and we set weight of our additive layer with the SetLayerWeight() function.
    if (Input.GetKeyDown(KeyCode.Space))
    {
        if (weightTarget < 0.5f)
        {
            weightTarget = 1f;
        }
        else if (weightTarget > 0.5f)
        {
            weightTarget = 0f;
        }
    }
    weight = Mathf.Lerp(weight, weightTarget, Time.deltaTime * tiredLerpSpeed);
    
    anim.SetLayerWeight(1, weight);
  14. Attach the script to the Humanoid character.
  15. Play the game and press Space to see the additive animation effect.

How it works...

Additive animations are calculated using the reference pose. Movements relative to this pose are then added to other animations. This way, we can not only override the base layer with other layers but also modify base movements by adding a secondary motion.

Try experimenting with different additive animations. You can, for instance, make your character bend, aim, or change its overall body pose.

Using Blend Shapes to morph an object into another one

Previously, we used Blend Shapes to create face expressions. This is also an excellent tool for special effects. In this recipe, we will morph one object into another.

Getting ready...

To follow this recipe, we need to prepare an object with Blend Shapes. We've created a really simple example in Blender—a subdivided cube with one shape key that looks like a sphere. Take a look at this screenshot for reference:

A cube with a Blend Shape that turns it into a sphere

You will see a number of cubes there. If you hit the Space key in play mode, the cubes will morph into spheres. You can find the Cuboid.fbx asset with the required Blend Shapes in the Model directory.

How to do it...

To use Blend Shapes to morph objects, follow these steps:

  1. Import the model with at least one Blend Shape to Unity. You may need to go to the Import Settings | Model tab and choose Import BlendShapes.
  2. Place the model in Scene.
  3. Create a new script and call it ChangeShape.cs. This script is similar to the one from the previous recipe. In the Update() function, we change the weight of the of the first Blend Shape when player presses Space. Again, we use a helper variable weightTarget to set the new weight to 0 or 100, depending on its current value. Blend Shapes have weights from 0 to 100 instead of 1. Finally, we interpolate the weight value in time to make the transition smoother. We use the SetBlendShapeWeight() function on the skinnedRenderer object. This variable is set in the Start() function with the GetComponent<SkinnedMeshRenderer>() function.
    if (Input.GetKeyDown(KeyCode.Space))
    {
        if (weightTarget < 50f)
        {
            weightTarget = 100f;
        }
        else if (weightTarget > 50f)
        {
            weightTarget = 0f;
        }
    }
    weight = Mathf.Lerp(weight, weightTarget, Time.deltaTime * blendShapeLerpSpeed); 
    skinnedRenderer.SetBlendShapeWeight(0, weight);
  4. Attach the script to the model on the scene.
  5. Play the game and press Space to see the model morph.

How it works...

Blend Shapes store vertices position of a mesh. We have to create them in a 3D package. Unity imports Blend Shapes and we can modify their weights in runtime using the SetBlendShapeWeight() function on the Skinned Mesh Renderer component.

Blend Shapes have trouble with storing normals. If we import normals from our model it may look weird after morphing. Sometimes setting the Normals option to Calculate in the Import Settings can helps with the problem. If we choose this option Unity will calculate normals based on the angle between faces of our model. This allowed us to morph a hard surface cube into a smooth sphere in this example.

Summary

This article covers some basic recipes which can be performed using Unity. It also covers basic concept of of using Animation Layer, Mecanim layer and creating Camera shakes

Resources for Article:


Further resources on this subject:


You've been reading an excerpt of:

Unity 5.x Animation Cookbook

Explore Title