Unity Term Book
Graphics & Rendering

VFX & Particle System

Unity has two particle systems — Particle System (CPU-based, flexible) and VFX Graph (GPU-based, millions of particles) — for fire, smoke, rain, and magic FX.

Imagine...

A Particle System is a hand-fired firework — you set rate, angle, and color, and the CPU updates each particle. Precise, but slow at high counts. VFX Graph is an industrial firework machine — everything runs in parallel on the GPU, so millions of particles are possible, but you need a strong GPU and URP/HDRP. Pick based on particle count, target platform, and how complex the behavior is.

The concept in detail

The Particle System (also called Shuriken) is a component on a GameObject that creates and updates particles on the CPU. Each particle has position, velocity, color, size, and lifetime. Modules (Emission, Shape, Velocity, Color over Lifetime, Force, Collision…) give fine control. Good for: small fires, rain, snow, hit FX, smoke — tens to a few thousand particles.

VFX Graph (Visual Effect Graph) runs entirely on GPU compute shaders. You build update logic with a node graph similar to Shader Graph (Initialize, Update, Output). Millions of particles at good performance. Requires: URP or HDRP, a GPU with Compute Shader support (most GPUs from 2015+), not older Android/iOS.

VFX Graph splits particles into: Spawn (rate/burst), Initialize (initial attributes), Update (per-frame physics, color, size), and Output (how they draw: quad, mesh, ribbon). Contexts connect through a data flow, like a render pipeline.

Performance: a Particle System is fine on mobile and console if you stay under ~1000 live particles. Cap with maxParticles and Stop Action = Disable after play. VFX Graph scales better, but profile it on the target platform.

Particle System vs VFX Graph

CriteriaParticle SystemVFX Graph
ProcessingCPUGPU (Compute Shader)
Optimal particle count100 – 10,00010,000 – 10,000,000+
PipelineBuilt-in, URP, HDRPURP, HDRP only
Mobile✅ Good⚠️ Limited
InterfaceInspector moduleNode graph editor
Script APIFull C# APILimited (SetFloat, SetTexture)
Use whenFire, rain, hit FX, smokeGalaxy, fluid, crowd, destruction

Hands-on steps (Particle System)

1

Create a Particle System

GameObject → Effects → Particle System, or Add Component → Particle System on an existing GameObject.

2

Configure the Main module

Duration, Looping, Start Lifetime, Start Speed, Start Size, Start Color — the basics.

3

Pick an emission shape

Shape module: Cone (fire), Sphere (explosion), Box (rain from above), Circle (ring). Tune Radius and Arc.

4

Enable Color over Lifetime

Add a gradient: red → orange → yellow → transparent to fade a fire out.

5

Play from code when needed

ps.Play() / ps.Stop() / ps.Emit(count) — or EmitParams for an instant burst.

Interactive simulator

Tune Particle System parameters and press Burst / a preset to see the effect.

Alive particles:0Mode: Fire

Code example

Basic

Play/Stop a Particle System and emit a burst on demand (e.g. a hit effect).

using UnityEngine;

public class HitEffect : MonoBehaviour
{
  public ParticleSystem sparks;
  public ParticleSystem smoke;

  // Call on bullet impact — PlayOneShot a prefab at a position
  public static void PlayAt(Vector3 pos, Vector3 normal,
                             GameObject fxPrefab)
  {
      GameObject fx = Instantiate(fxPrefab, pos,
          Quaternion.LookRotation(normal));
      Destroy(fx, 2f); // Clean up after 2 seconds
  }

  // Burst emit: 30 particles immediately, no looping
  public void BurstEmit()
  {
      ParticleSystem.EmitParams ep = new ParticleSystem.EmitParams();
      ep.position = transform.position;
      sparks.Emit(ep, 30);
      smoke.Play();
  }

  // Change particle color at runtime via Main module
  public void SetColor(Color color)
  {
      var main = sparks.main;
      main.startColor = new ParticleSystem.MinMaxGradient(color);
  }
}

Code example

Advanced

Drive VFX Graph from C# — set properties and fire events with ExposedProperty.

using UnityEngine;
using UnityEngine.VFX;

public class VFXController : MonoBehaviour
{
  public VisualEffect vfx;

  // Property IDs — must match Exposed Property names in VFX Graph
  static readonly int SpawnRateID = Shader.PropertyToID("SpawnRate");
  static readonly int ColorID     = Shader.PropertyToID("BaseColor");
  static readonly int ExplodeID   = Shader.PropertyToID("OnExplode");

  void Start()
  {
      vfx.SetFloat(SpawnRateID, 50f);
      vfx.SetVector4(ColorID, new Vector4(1f, 0.5f, 0f, 1f));
  }

  public void Explode()
  {
      // SendEvent fires an event in VFX Graph (Burst spawn)
      vfx.SendEvent(ExplodeID);
  }

  public void SetIntensity(float t)
  {
      // Spawn rate 0 → 500 from intensity
      vfx.SetFloat(SpawnRateID, Mathf.Lerp(0f, 500f, t));
  }
}

📌 Quick recap

  • Particle System: CPU, every platform, <10k particles
  • VFX Graph: GPU, URP/HDRP only, millions of particles
  • Stop Action = Disable to reuse (object pooling)
  • ps.main.startColor must be reassigned as a struct
  • VFX Graph: SendEvent() fires a Burst context

⚠️ Common mistakes

  • ❌ Spawning many PS prefabs without Destroy

    Thousands of Particle Systems pile up → heavy lag

    ✅ Pool the PS, or Destroy(fx, lifetime) after it finishes

  • ❌ Editing ps.main.startColor.color directly

    Struct copy — the change never applies

    ✅ var main = ps.main; main.startColor = new MinMaxGradient(c);