# 1. VFX Graph Setup and Mental Model
Part of [[VFX Graph]]. Next: [[2. VFX Exposed Properties Events and Binders]].
> [!note] Verification status
> Requirements (compute + SSBO, no OpenGL ES, no gamma in URP, URP support in preview) quoted from the 17.5 Requirements page; `SystemInfo.supportsComputeShaders` and `SystemInfo.maxComputeBufferInputsVertex` exist in the 6000.5 Scripting Reference (2026-11-10). Node/block names are from the 17.x manual and may be labelled slightly differently in your editor build. **Code not compiled in Unity.**
## 1.1 Install
1. Project: **Universal 3D** template, **Linear** color space (VFX Graph in URP doesn't support gamma).
2. **Window > Package Manager > Unity Registry > Visual Effect Graph > Install.** It's a core package: the version is fixed by your editor (17.5.x docs for 6000.5) and you can't pick another from the window.
3. URP Asset: enable **Depth Texture** (needed for depth-buffer collision and soft particles) and, if you want distortion, **Opaque Texture**.
4. **Create > Visual Effects > Visual Effect Graph.** Pick a template (start with the simple loop). Drag the asset into the scene - Unity adds a GameObject with a **Visual Effect** component.
## 1.2 The pipeline (contexts)
```
[Event: OnPlay] -> [Spawn] -> [Initialize Particle] -> [Update Particle] -> [Output Particle ...]
CPU side CPU GPU (once per new p) GPU (every frame) GPU (render)
```
| Context | Runs | Typical blocks | Think of it as |
|---|---|---|---|
| **Event** | When C# sends an event or the effect starts (`OnPlay`, `OnStop`, custom names) | - | The trigger |
| **Spawn** | CPU, per frame | Constant Rate, Single Burst, Periodic Burst | How many, when |
| **Initialize Particle** | GPU, once per new particle | Set Position (shape), Set Velocity Random, Set Lifetime, Set Color | Birth |
| **Update Particle** | GPU, every frame | Gravity, Linear Drag, Turbulence, Collide with Depth Buffer, Trigger Event on Die | Life |
| **Output Particle** | GPU, render | Quad/Mesh/Shader Graph output, Set Size over Life, Set Color over Life, Orient | Looks |
**Attributes** are per-particle data (`position`, `velocity`, `color`, `alpha`, `size`, `lifetime`, `age`, custom ones). **Properties** are per-effect inputs on the **Blackboard** (exposed to the Inspector and C#). Keep that distinction: C# sets *properties* (part 2) and sends *event attributes* (payloads that seed particle attributes at birth).
## 1.3 Capacity and bounds: the two settings that bite
- **Capacity** (Initialize context): max particles alive for that system. VFX Graph allocates GPU memory for the full capacity up front. A capacity of 1,000,000 costs memory even when you spawn 10.
- **Bounds** (Initialize context): used for culling. Too small = effect disappears when its origin leaves the screen; too big = never culled. Use **Recorded** bounds mode in the editor (play the effect, record), or set Manual bounds to the max reach.
## 1.4 First effect: a landmark beacon
A slow column of glowing motes above the landmark from [[4. Level Design with Terrain - Landmarks and Sightlines]] - visible across the map, cheap, and a perfect "go here" signal.
1. New graph `VFX_Beacon`. Spawn: **Constant Rate** 200.
2. Initialize: Capacity 2000, Bounds Manual center (0, 60, 0) size (20, 130, 20). **Set Position (Shape: Circle)** radius 3, **Set Velocity Random** min (0, 4, 0) max (0, 8, 0), **Set Lifetime Random** 8-14 s, **Set Size Random** 0.2-0.6.
3. Update: **Turbulence** (low intensity, large scale) for drift; **Linear Drag** small.
4. Output: Quad, additive blend, soft dot texture; **Set Color over Life** fading in/out; **Set Size over Life** gentle grow.
5. Blackboard: add a **Color** property `BeaconColor` (exposed) and a **float** `Intensity`. Multiply color by intensity in Initialize. Part 2 drives them from C# (e.g., beacon pulses when the quest updates - [[Quest Systems]]).
## 1.5 Script: capability gate with fallback
VFX Graph needs compute shaders and SSBO support in the vertex stage, and doesn't support OpenGL ES. Ship a fallback for devices that fail the check (or for Quest if you decide part 6's costs are too high).
```csharp
// Assets/Scripts/VFX/VfxCapabilityGate.cs
using UnityEngine;
using UnityEngine.VFX;
/// Enables a VisualEffect if the device meets VFX Graph's documented minimums,
/// otherwise enables a Particle System fallback.
public class VfxCapabilityGate : MonoBehaviour
{
public VisualEffect vfx;
public ParticleSystem fallback;
[Tooltip("Force the fallback, e.g. on a low quality level or for testing")]
public bool forceFallback;
public static bool DeviceSupportsVfxGraph =>
SystemInfo.supportsComputeShaders && SystemInfo.maxComputeBufferInputsVertex > 0;
void Awake()
{
bool useVfx = !forceFallback && DeviceSupportsVfxGraph;
if (vfx != null) vfx.gameObject.SetActive(useVfx);
if (fallback != null) fallback.gameObject.SetActive(!useVfx);
if (!useVfx)
Debug.Log(
quot;[VFX] Using Particle System fallback on {SystemInfo.graphicsDeviceType} " +
quot;(compute={SystemInfo.supportsComputeShaders}, vtxBuffers={SystemInfo.maxComputeBufferInputsVertex})");
}
}
```
**Explanation:** the two `SystemInfo` checks are exactly the minimums the requirements page lists. Logging the graphics API makes bug reports useful (OpenGL ES devices will fail; Vulkan Android usually passes).
## 1.6 Exercise
Build the beacon twice: once in VFX Graph, once as a Shuriken system (see [[1.Particle System Fundamentals]]). Compare GPU time in the Profiler at 2,000 and at 200,000 particles. Where does each break?
## Sources
- Requirements and compatibility (17.5): https://docs.unity3d.com/Packages/[email protected]/manual/System-Requirements.html
- VFX Graph manual (17.5): https://docs.unity3d.com/Packages/[email protected]/manual/index.html
- Blackboard: https://docs.unity3d.com/Packages/[email protected]/manual/Blackboard.html
- `SystemInfo.supportsComputeShaders`: https://docs.unity3d.com/6000.5/Documentation/ScriptReference/SystemInfo-supportsComputeShaders.html
- `SystemInfo.maxComputeBufferInputsVertex`: https://docs.unity3d.com/6000.5/Documentation/ScriptReference/SystemInfo-maxComputeBufferInputsVertex.html