4. week

Unity Engine Lab 2

VFX Graph – The EPIC Unity Engine Tutorial

What you will learn in this section:

  • Visual Effects in Unity Engine
  • What is a Particle System
  • What is VFX Graph
  • The difference between them

An important part of almost every game is its visual design. In today’s world of competition, very few developers decide to go with graphics reminiscent of the first Counter-Strike or Space Invaders. However, we often hear opinions that beautiful effects can only be created by an artist or a skilled designer. That’s simply not true. In today’s lab, we will explore Unity Engine’s tools for creating visual effects.

The tutorial is prepared in the form of images, and you can use your own game to follow along.

Visual Effects in Unity Engine

In Unity, we can choose between two different tools: VFX Graph and Particle System. These tools are not enemies — in most games, both are used since each has its own pros and cons. Let’s briefly summarize them:

Particle System – Easy to use, simpler overall workflow, works much better with collisions, uses the CPU for particle processing, and is mostly used in smaller games.

VFX Graph – A much more powerful tool for creating effects, capable of handling millions of particles thanks to GPU processing. It’s faster but more complex, and working with collisions is more challenging. For small games, it might not be worth the extra complexity.

Particle System VFX Graph
USING CPU GPU
SIMULATION Simple Complex
PARTICLE COUNT Thousands Millions
PHYSICS Underlying Physics System Primitives, Depth Buffer, Signed Distance Fields

The main difference is that the Particle System is controlled in the Inspector, which you’re already familiar with. Its interface makes it easy to see and adjust settings right away, providing a clear overview of what can be done.

Although VFX Graph may seem “better” in every way, it all depends on the goal you want to achieve with the effect. In this tutorial, we’ll focus on working with VFX Graph.

Instructions

Step 1: VFX Graph

The VFX effect we’ll be creating will simulate snowfall. For that, we’ll need an FBX file of a snowflake that we exported earlier in the Blender tutorial.
The first step is to create the actual VFX graph.

Task 1.1

Create a folder named VFXGraph where we’ll store our effects.
Right-click on it and select Create > Visual Effects > Visual Effect Graph.

Creating VFX Graph
Fig. 1: Creating VFX Graph

Comment

In the previous step, it might happen that the option Visual Effect does not appear in the menu.
In that case, go to Package Manager find Visual Effect Graph among the packages, and install it.

Creating VFX Graph
Fig. 2: Creating VFX Graph

After opening the created VFX graph, you should see something like this:

Creating VFX Graph
Fig. 3: Creating VFX Graph

Before we dive into creating, let’s quickly go over the logic and theory of what we’re looking at:

1. Section

This is the Blackboard.
The Blackboard serves as a centralized place for storing and managing parameters, properties, and other data that can be used by nodes within the graph. Its main features include:

  • Parameter Management – Defining and handling parameters such as colors, sizes, or booleans.
  • Data Binding – Nodes in the graph can be linked to the Blackboard, so changing a parameter dynamically affects other parts of the graph.
  • Graph Communication – Nodes can communicate with each other by writing and reading data from the Blackboard.
  • Exposed Parameters – Parameters that we want to control externally, e.g., from scripts.

2. Section

Here we see the structure of our effect. This is where we add components, set properties, and shape the overall behavior of the effect. The main parts are:

  • Spawn – Modules like “Spawn” or “Burst” used to control particle generation.
  • Initialize Particle – Module for defining initial particle properties.
  • Update Particle – Module that defines how particles evolve over time.
  • Output Particle Quad – Module that determines how particles are rendered in the scene.

Each module can be customized based on our needs, so we don’t have to use all of them.
Pressing SPACE allows you to add a new module and browse all available options.

3. Section

The Play Controls window is used to preview the effect. It includes Play, Stop, and Pause options, as well as Play Rate, which controls the playback speed.

That’s all we need to know for now — let’s get started.

Step 2: Diving In

To add an element to our system, press Space or right-click.
However, be careful whether you’re creating a block or a node.
If you want to create a block, your cursor must be inside a block area.

The difference between them:

  • Node – A self-contained element that processes data and controls the flow of the effect in the graph.
  • Block – Components that exist only within specific contexts (e.g., Spawn system, Initialize particle, etc.).

First, we’ll modify how our snowfall effect appears.
In the Spawn section, the constant mode means particles spawn and disappear constantly — which is perfect for snow, so we’ll leave it as is.

Instead, we’ll remove the Set Lifetime Random block and add a new one named Set Position Random (Per-component).
This lets us define random positions for each spawned particle within a specified range.
Next, we’ll add a lifetime for these particles using Add Lifetime, which gives each particle the same lifespan.
Finally, we can randomize their size with Set Scale.XYZ Random (Per-component).

We can now delete the entire Output Particle Quad block because we want the final particle to be our Blender FBX snowflake file.
Click and drag from the previous block’s output downwards, release, and choose Output Particle Mesh.

VFX without texture
Fig. 4: VFX without texture

Comment

If you are having troubles with running the VFX effects (for example you cannot see the particles), that is probably because of how the render pipeline is set in the project settings. Check the tutorial below to see how to fix it and convert your project to Universal Render Pipeline:

Comment

After that, everything should work properly.

As you can see, the particles currently have no texture.

VFX without texture
Fig. 5: VFX without texture

Task 2.1

Create a folder named Blender_textures and place your exported low-poly snowflake FBX file inside it.

Adding Blender file
Fig. 6: Adding Blender file

When you expand the asset, you’ll see it consists of a material and an object.
The material isn’t relevant since we didn’t create one in Blender — we only need the object itself.
Drag the object into the Mesh field under Output Particle Mesh.
Then set the color mapping to Gradient Mapped and choose white.

Setting object
Fig. 7: Setting object
Setting object
Fig. 8: Setting object

As you may notice, the texture now appears — though it may be very small.
In that case, adjust the snowflake size and play around with it.
One major issue is that the snowflakes are rotated incorrectly.

Task 2.2

Rotate the snowflakes to make the snowfall look more realistic.

Rotating snowflake
Fig. 9: Rotating snowflake

After adjusting the rotation, our scene should look something like this:

Final effect
Fig. 10: Final effect

Task 2.3

If you set the size range between XYZ (1, 1, 1) and (10, 10, 10), you might get results like (1, 1, 10), creating strange stretched lines.
Try fixing this by adding or removing certain blocks/nodes.

Step 3: Enhancing the Scene

Right now, our scene looks pretty empty. Let’s improve it by adding some fog.

Task 3.1

Add fog to the scene.

Fog can be found under:
Window > Rendering > Lighting > Environmental

Adding fog
Fig. 11: Adding fog

This small tweak already makes the scene look much better.
We can enhance it even further by adding a different skybox.

Task 3.2

Find a skybox in the Asset Store and change your scene’s skybox.

Adding skybox
Fig. 12: Adding skybox

Step 4: Adding More Effects

A VFX graph doesn’t have to contain only one particle initialization module — it can generate an unlimited number of effects.
This means we can enhance our snowfall by adding higher-quality flakes in the center of the effect near the camera, creating a richer and more detailed look.

Creating new initialization
Fig. 13: Creating new initialization

Task 4.1

Import the FBX file of the higher-quality snowflake you created into the Blender_textures folder.

Implementing FBX file
Fig. 14: Implementing FBX file

Add the following blocks:
Set Velocity Random (Per-component), Set Lifetime Random (Uniform), Set Position Random (Per-component), Set Scale.XYZ (Per-component), and Set Angle.XYZ Random (Per-component) — and adjust them as shown in the image.

As before, set the output to Output Particle Mesh, insert the snowflake asset, and apply color mapping using Gradient Mapped.

VFX Graph
Fig. 15: VFX Graph

The final result should look like this:

Final effect
Fig. 16: Final effect

Step 5: Controlling the Effect via Script

To control the effect via script, we need to expose parameters in the VFX Graph. This allows us to modify them using code. To make a parameter exposed, click the “+” button in the Blackboard.

Add a “Float” named SpawnRate and link it to Constant Spawn Rate. You can now access and modify this value via script.

Adding variables
Fig. 17: Adding variables

Similarly to SpawnRate, add the following parameters (WindVelocity_low, WindVelocity_high, SnowflakeSize_low, and SnowflakeSize_high). Unlike SpawnRate, these will affect XYZ positions and velocities, so instead of “Float,” select “Vector3”. Connect them to their respective blocks in the graph.

Adding variables
Fig. 18: Adding variables

Now we can implement the script.

Right-click in the Project window and choose C# Script. Rename it to SnowstormToggle and open it with a double-click.

Script
Fig. 19: Script

This script demonstrates how to modify exposed parameters through code. It includes a simple void method that will be triggered via a button we’ll create later.

using UnityEngine;
using UnityEngine.VFX;

public class SnowstormToggle : MonoBehaviour
{
    public VisualEffect snowfallEffect;
    private bool isSnowstorm = false;

    private float normalSpawnRate = 50000;
    private Vector3 normalSnowflakeSize_low = new Vector3(4f, 4f, 4f);
    private Vector3 normalSnowflakeSize_high = new Vector3(7f, 7f, 7f);
    private Vector3 normalWind_low = new Vector3(1, -1, 1);
    private Vector3 normalWind_high = new Vector3(5, -5, 5);

    private float stormSpawnRate = 100000;
    private Vector3 stormSnowflakeSize_low = new Vector3(8f, 8f, 8f);
    private Vector3 stormSnowflakeSize_high = new Vector3(11f, 11f, 11f);
    private Vector3 stormWind_low = new Vector3(5, -5, 5);
    private Vector3 stormWind_high = new Vector3(10, -10, 10);

    public void ToggleSnowstorm()
    {
        if (isSnowstorm)
        {
            snowfallEffect.SetFloat("SpawnRate", stormSpawnRate);
            snowfallEffect.SetVector3("SnowflakeSize_low", stormSnowflakeSize_low);
            snowfallEffect.SetVector3("SnowflakeSize_high", stormSnowflakeSize_high);
            snowfallEffect.SetVector3("WindVelocity_low", stormWind_low);
            snowfallEffect.SetVector3("WindVelocity_high", stormWind_high);
        }
        else
        {
            snowfallEffect.SetFloat("SpawnRate", normalSpawnRate);
            snowfallEffect.SetVector3("SnowflakeSize_low", normalSnowflakeSize_low);
            snowfallEffect.SetVector3("SnowflakeSize_high", normalSnowflakeSize_high);
            snowfallEffect.SetVector3("WindVelocity_low", normalWind_low);
            snowfallEffect.SetVector3("WindVelocity_high", normalWind_high);
        }

        isSnowstorm = !isSnowstorm;
    }
}

To apply this script to a button, it is necessary to create an "Empty Object" in the hierarchy using "Create Empty". After creating this object, move the script into it.

Comment

Name it something meaningful so that it’s clear which script is contained in that object.

Creating Empty Object
Fig. 20: Creating Empty Object

In "Snowfall effect", insert the VFX graph for the snowfall.

Adding the script to the object
Fig. 21: Adding the script to the object

In the next step, create a button in the hierarchy under UI > Button. You will see a large canvas appear, which contains the button. This canvas represents the user interface in the game. The fact that it looks strange in the scene view doesn’t matter.

Creating the button
Fig. 22: Creating the button
Moving the button
Fig. 23: Moving the button

Next, open the button in the Inspector and under "On Click", use the "+" to add an on-click effect — in other words, what happens when the user clicks the button. Then, drag the object containing the script into the On Click event field. After you have the object with the script there, click on No function > (class name) > (void method name).

Configuring the button
Fig. 24: Configuring the button

If you now press Play in Unity, you will see a button in the game that adjusts the effect according to the script.

script
Fig. 25: script
script
Fig. 26: script
script
Fig. 27: script

Now you can try changing these values and test what works best for your effect.

Additional Resources

Intro to VFX - https://unity.com/how-to/introduction-vfx-graph-unity