Skip to main content

๐ŸŒŒ Lesson 9.2: The VFX Graph โ€” GPU Particles

Shuriken from the last lesson simulates every particle on the CPU, which is fine for hundreds. But a blizzard, a galaxy, or a magical vortex wants millions. The Visual Effect Graph moves the whole simulation onto the GPU and hands you a node-based editor to author it. In this lesson you'll install it, understand why the GPU changes the scale of what's possible, and learn to read its Spawn โ†’ Initialize โ†’ Update โ†’ Output context flow.

๐ŸŽฏ Learning Objectives

By the end of this lesson, you will be able to:

  • Install the Visual Effect Graph package and create a graph asset in a URP project
  • Explain how GPU particles differ from CPU (Shuriken) particles and why they scale to millions
  • Read the four contexts โ€” Spawn, Initialize, Update, Output โ€” and how data flows down the graph
  • Identify Blocks inside a context and what they do
  • Expose parameters on the Blackboard to drive an effect from the Inspector or code
  • Decide when to choose VFX Graph over Shuriken (and when not to)

Estimated Time: 45 minutes  ยท  Prerequisite: Lesson 9.1 (Particle Systems / Shuriken)

In This Lesson

Installing the VFX Graph

The Visual Effect Graph is a separate package. Open Window โ–ธ Package Manager, switch the source dropdown to Unity Registry, find Visual Effect Graph, and click Install. On a URP project it's usually already pulled in as a dependency, but installing it explicitly guarantees the version matches your pipeline.

Then create your first graph: Assets โ–ธ Create โ–ธ Visual Effects โ–ธ Visual Effect Graph. This makes a .vfx asset. To use it in a scene, add a Visual Effect component to a GameObject (GameObject โ–ธ Visual Effects โ–ธ Visual Effect) and drag your .vfx asset into its Asset Template field. Double-click the asset to open the graph editor.

โš ๏ธ VFX Graph needs the right pipeline

The Visual Effect Graph runs on URP and HDRP โ€” not the old Built-in Render Pipeline. Since this course is URP throughout, you're fine. It also relies on compute shaders, so it won't run on very old hardware or some low-end mobile GPUs; for those targets, stick with Shuriken.

GPU vs. CPU Particles

Shuriken updates each particle on the CPU, one after another, every frame. Your CPU is a handful of very fast cores โ€” brilliant for game logic, but it can only chew through so many particles before the frame rate drops. A few thousand is its comfortable ceiling.

The VFX Graph runs the simulation as a compute shader on the GPU, which has thousands of small cores all updating particles in parallel. Because position, velocity, and age live in GPU buffers and never round-trip to the CPU, the graph can simulate and draw hundreds of thousands to millions of particles at interactive frame rates.

๐Ÿ“– Definition

GPU particles: particles whose entire lifecycle โ€” spawning, physics, aging, death โ€” is computed on the graphics card in parallel. The trade-off: because the data stays on the GPU, game-logic C# can't cheaply read individual particle positions the way it can with a Shuriken system. GPU particles are for spectacle, not for gameplay collisions you need to query per particle.

Here's the divide at a glance:

flowchart TB subgraph CPU["Shuriken (CPU)"] A["Handful of fast cores"] --> B["~hundreds to a few thousand
particles comfortably"] B --> C["Easy for C# to read
individual particles"] end subgraph GPU["VFX Graph (GPU)"] D["Thousands of parallel cores"] --> E["hundreds of thousands
to millions of particles"] E --> F["Data stays on GPU;
built for spectacle"] end

Figure 1: The two particle systems solve different problems โ€” Shuriken for gameplay-connected effects, VFX Graph for massive, GPU-driven spectacle.

Anatomy of a VFX Graph

Open a .vfx asset and you land in a dark node canvas. Unlike Shuriken's flat Inspector stack, the VFX Graph is a flow of contexts connected top to bottom by fat wires: particles are born at the top and flow downward through stages until they're drawn. Down one side sits the Blackboard, a panel of exposed properties you can wire into any node.

The Unity Visual Effect Graph editor A recreation of Unity's Visual Effect Graph editor. On a dark dotted canvas, four contexts are stacked vertically and connected by wires flowing downward: a green Spawn context at the top containing a Constant Spawn Rate block, wired into a blue Initialize Particle context containing Set Lifetime, Set Velocity and Set Color blocks, wired into a blue Update Particle context containing Gravity and Turbulence blocks, wired into a red Output Particle Quad context containing Set Size over Life and a Main Texture block. On the left is a Blackboard panel listing exposed properties: SpawnRate float, Lifetime float, BaseColor color and Turbulence float. Save Compile Blackboard ยท Target Blackboard + Exposed Properties SpawnRate float Lifetime float BaseColor Color Turbulence float Wire these into any block port to drive it. Spawn Constant Spawn Rate Rate Initialize Particle capacity 4096 Set Lifetime (Random) Set Velocity (from Direction) Set Color Update Particle per frame Gravity Turbulence Collision (optional) Output Particle Quad Set Size over Life Main Texture / Blend: Additive draws to screen โ‘  how many are born โ‘ก their birth values โ‘ข change each frame โ‘ฃ how they're drawn
Figure 2: The Visual Effect Graph editor (faithfully recreated). Particles flow top to bottom through four contexts โ€” Spawn, Initialize, Update, Output โ€” each holding blocks. The left Blackboard exposes properties you wire into any block or drive from the Inspector/code.

The Four Contexts

A context is a stage in a particle's life. Data flows down the wires from one to the next, and each context answers a different question:

  • Spawn (green) โ€” how many particles are born, and when? Holds blocks like Constant Spawn Rate or Single Burst. This is the VFX Graph equivalent of Shuriken's Emission module.
  • Initialize Particle (blue) โ€” what values does each particle get at birth? Set Lifetime, Set Velocity, Set Position, Set Color. Runs once per particle, the moment it spawns. It also declares the system's Capacity โ€” the max particles allocated on the GPU.
  • Update Particle (blue) โ€” what changes every frame while it's alive? Gravity, Turbulence, Force, Collision, drag. Runs every frame for every living particle โ€” this is where the GPU's parallelism pays off.
  • Output Particle (red) โ€” how is each particle drawn? Output Particle Quad (camera-facing billboards), Mesh, or Line. Holds the texture, blend mode, and Size-over-Life. This is the final stage; it renders to the screen.

โœ… The Shuriken translation

If you know Shuriken, the mapping is clean: Spawn โ‰ˆ Emission, Initialize โ‰ˆ the Main module's Start-values, Update โ‰ˆ the over-lifetime modules, and Output โ‰ˆ the Renderer. The VFX Graph just makes each stage an explicit, wire-connected node instead of a foldout.

Blocks: The Verbs

Inside each context sits a stack of blocks โ€” the individual operations. A block is a small unit of behaviour: Set Velocity from Direction & Speed, Add Position (Sphere), Gravity, Turbulence. You add a block by right-clicking inside a context โ–ธ Create Block, or with the spacebar menu, and blocks run top to bottom within their context.

Blocks have input ports on the left. You can type a constant value directly, or drag a wire from an operator node (Add, Multiply, Random, Noise, Age over Lifetime) or from a Blackboard property. That wiring is what makes the graph expressive: a Set Color block can be fed a gradient sampled by the particle's age, so color animates without a dedicated module.

๐Ÿ“– Definition

Context vs. Block: a context is a life stage (Spawn/Initialize/Update/Output) drawn as a big titled box; a block is one operation living inside a context. Contexts are the nouns of a particle's life; blocks are the verbs that act on it.

๐Ÿ’ก Order matters inside a context. Blocks execute top to bottom, so a Set Position that runs before Add Position (Sphere) gives a different result than the reverse. If an effect looks wrong, check block order before you touch the values.

The Blackboard

The Blackboard is the panel of named properties (see the left side of Figure 2). You create a property there โ€” SpawnRate, Lifetime, BaseColor โ€” then drag it onto the canvas and wire it into any block port. Two big wins:

  • Reuse โ€” one BaseColor can feed the Initialize color, a trail tint, and the output all at once. Change it in one place, everything updates.
  • Exposure โ€” tick a property as Exposed and it appears on the Visual Effect component in the Inspector, per-instance. Now the same graph can be a red torch on one GameObject and a blue torch on another, with no duplicate assets.

Exposed properties are also settable from C# through the VisualEffect component, so gameplay can drive an effect at runtime:

using UnityEngine;
using UnityEngine.VFX;

public class VortexController : MonoBehaviour
{
    [SerializeField] VisualEffect vfx;

    // Cache property IDs once โ€” cheaper and typo-proof at the call site.
    static readonly int SpawnRateID = Shader.PropertyToID("SpawnRate");
    static readonly int BaseColorID = Shader.PropertyToID("BaseColor");

    void Start()
    {
        vfx.SetFloat(SpawnRateID, 5000f);
        vfx.SetVector4(BaseColorID, new Color(0.2f, 0.6f, 1f, 1f));
    }

    // Fire a one-shot burst event defined in the Spawn context.
    public void Erupt()
    {
        vfx.SendEvent("OnErupt");
    }
}

Notice the pattern from earlier lessons: cache the property as an ID with Shader.PropertyToID once, then reuse it โ€” the exact same idea as Animator.StringToHash for animator parameters.

โš ๏ธ Reading particles back is expensive

You can push values into a VFX Graph cheaply, but pulling individual particle positions back to the CPU means a GPU-to-CPU readback that stalls the frame. If your gameplay needs to know where each particle is (for per-particle collision damage, say), that's a sign the effect belongs in Shuriken, not the VFX Graph.

VFX Graph or Shuriken?

Both ship in the same project and you'll use both. Choose by the job:

  • Reach for the VFX Graph when you need huge counts (blizzards, sandstorms, galaxies, magic vortexes), GPU features like flipbooks and mesh output at scale, or complex node-driven behaviour โ€” and your target hardware supports compute shaders.
  • Reach for Shuriken when the effect is small, needs to interact tightly with gameplay (particle collisions that call your code, sub-emitters spawning pickups), must run on low-end/older mobile GPUs, or when a quick Inspector tweak beats opening a graph.

โœ… Pro Tip: prototype in Shuriken, scale in VFX Graph

Because Shuriken is faster to set up, many teams block out an effect's timing and feel there first, then rebuild the "hero" version in the VFX Graph once they know it needs the particle count or GPU features. Don't reach for the graph until the scale actually demands it.

Hands-on Challenge

๐Ÿ‹๏ธ Exercise 1: A million-spark vortex

Objective: Build a GPU effect that would bring Shuriken to its knees.

  1. Create a Visual Effect Graph asset and open it. You'll get the default Spawn โ†’ Initialize โ†’ Update โ†’ Output flow.
  2. In Spawn, set the Constant Spawn Rate high (e.g. 20,000). In Initialize, raise the Capacity so the system can hold them, and set Lifetime and an initial position on a sphere.
  3. In Update, add a Turbulence block so the sparks swirl, and a Gravity block for drift.
  4. In Output Particle Quad, set an additive blend and a small size, then add Set Size over Life so sparks shrink as they age.
  5. On the Blackboard, create an exposed SpawnRate float and wire it into the Spawn block. Confirm it now appears on the Visual Effect component in the Inspector.
๐Ÿ’ก Hint: I raised the rate but the count is capped

The Spawn rate says how fast particles are created, but the Capacity in the Initialize context is the hard ceiling on how many can be alive at once. Raise Capacity to match the rate ร— lifetime you expect.

โœ… Success check

Tens of thousands of sparks swirl smoothly with no frame-rate collapse, and dragging the exposed SpawnRate on the Visual Effect component in the Inspector visibly thickens or thins the vortex in real time.

๐Ÿ‹๏ธ Exercise 2: Drive it from code

Attach the VortexController script from the Blackboard section to the GameObject holding your Visual Effect. Wire the vfx reference in the Inspector, then call SetFloat to ramp SpawnRate up over a few seconds (a coroutine or Mathf.Lerp in Update) so the vortex "spins up." Confirm the graph reacts live โ€” proof that exposed Blackboard properties are your bridge between gameplay and GPU spectacle.

๐ŸŽฏ Quick Quiz

Question 1: Which context sets the values a particle is born with, such as its lifetime and initial velocity?

Question 2: Why can the VFX Graph handle millions of particles when Shuriken can't?

Question 3: Your gameplay needs to read each particle's position every frame to deal collision damage. Which tool fits better?

Summary

๐ŸŽ‰ Key Takeaways

  • The Visual Effect Graph is a separate URP/HDRP package that simulates particles on the GPU, scaling to hundreds of thousands or millions.
  • A graph is a top-to-bottom flow of four contexts: Spawn (how many), Initialize (birth values + Capacity), Update (per-frame change), Output (how it's drawn).
  • Blocks are the operations inside a context; they run top to bottom and take wired inputs from operators or the Blackboard.
  • The Blackboard holds named, reusable properties; mark them Exposed to tune per-instance in the Inspector or set them from C# via VisualEffect.SetFloat/SendEvent.
  • Choose VFX Graph for massive GPU spectacle; choose Shuriken for small, gameplay-connected effects and low-end hardware.

๐Ÿš€ What's Next?

Particles add motion; the mood of a scene comes from its grade โ€” the bloom on a bright spark, the warm tint of a sunset, the vignette that pulls your eye to the center. In Lesson 9.3: Post-Processing with URP Volumes we layer cinematic image effects over the whole camera using the Volume framework.

๐ŸŒŒ You can read a VFX Graph now

Spawn how many, Initialize their birth, Update them each frame, Output how they draw โ€” with the Blackboard as the control panel. That flow is every VFX Graph you'll ever open.