# 6. VFX Graph Performance and Quest
Part of [[VFX Graph]]. Previous: [[5. VFX GraphicsBuffers and Audio-Reactive Effects]]. Next: [[7. VFX Graph Pitfalls]].
> [!note] Verification status
> From the 17.5 Requirements page: compute + SSBO required, **no OpenGL ES**, URP support **not out of preview** (only some URP platforms). The older "What's new in 12" page says URP high-end mobile support covers "a subset of high-end mobile devices" and recommends the built-in Particle System "for most mobile applications". `VisualEffect.culled`, `playRate`, `allowInstancing` exist on 6000.5. **Not verified:** an official statement that Quest 2 is a supported VFX Graph target - a Unity staff forum post (2023) says they tested on Quest 2 without reproducing a specific bug, which is anecdotal, not a support statement.
**VR version note:** Quest work in this vault targets **Unity 6.3 LTS (6000.3.27f2+)** ([[0.Choosing a Unity Version]]), whose VFX Graph is the 17.3 line. Re-check the 17.3 requirements page before shipping.
## 6.1 Where VFX Graph spends time
| Cost | Where | Fix |
|---|---|---|
| Simulation | Compute, scales with **alive** particles and Update blocks | Fewer blocks, shorter lifetimes, cheaper turbulence |
| Memory | GPU buffers sized by **capacity** | Capacity = real peak, not "just in case" |
| Culling failures | Wrong **bounds** -> simulates/renders off-screen or pops | Recorded or Manual bounds |
| Overdraw | Fragment cost of transparent quads | Smaller particles, fewer layers, opaque/alpha-clip where possible |
| Sorting | Transparent sort per frame | Disable sorting for additive effects (order doesn't matter) |
| Per-instance overhead | Many VisualEffect components | One instance + events (part 3); **instancing** for identical graphs |
## 6.2 Script: distance LOD for effects
Scale spawn rate with distance and stop updating effects nobody can see.
```csharp
// Assets/Scripts/VFX/VfxDistanceLod.cs
using UnityEngine;
using UnityEngine.VFX;
[RequireComponent(typeof(VisualEffect))]
public class VfxDistanceLod : MonoBehaviour
{
public Transform viewer; // camera; defaults to Camera.main
public float fullDetailDistance = 15f;
public float cutoffDistance = 60f;
[Tooltip("Exposed float multiplying spawn rate in the graph")]
public string rateProperty = "RateScale";
public float checkInterval = 0.25f;
VisualEffect vfx;
int rateId;
float timer;
void Awake()
{
vfx = GetComponent<VisualEffect>();
rateId = Shader.PropertyToID(rateProperty);
if (viewer == null && Camera.main != null) viewer = Camera.main.transform;
}
void Update()
{
timer -= Time.deltaTime;
if (timer > 0f || viewer == null) return;
timer = checkInterval;
float d = Vector3.Distance(viewer.position, transform.position);
float scale = 1f - Mathf.InverseLerp(fullDetailDistance, cutoffDistance, d);
if (vfx.HasFloat(rateId)) vfx.SetFloat(rateId, scale);
// Beyond the cutoff, stop simulating entirely; resume when back in range.
vfx.pause = scale <= 0f;
}
}
```
In the graph, multiply **Constant Rate** by `RateScale`. Pausing far effects saves compute; the effect resumes where it left off.
## 6.3 Quest 2 guidance
- **Graphics API:** Vulkan only. VFX Graph doesn't support OpenGL ES; remove GLES from the Android Graphics APIs list or the capability gate (part 1) will fall back.
- **Budget:** start with **one or two** VFX Graph systems on screen, low thousands of particles total. Quest 2's mobile GPU shares its budget with stereo rendering at 72-90 Hz ([[5.Quest 2 Performance and Rendering]]).
- **Overdraw is still the killer** - everything in [[5.VFX Graph Comparison and Performance]] about Shuriken overdraw applies equally to VFX Graph quads.
- **Avoid** depth-buffer collision, scene-color distortion, soft particles and volumetric outputs in VR unless profiled - each needs extra screen-size passes or textures.
- **Lit outputs** are expensive; use unlit additive/alpha outputs with emissive color.
- **Prefer the Particle System** for hit sparks and small bursts on Quest. Reserve VFX Graph for the one effect that needs huge counts (a swarm, a storm), and keep a Shuriken fallback via `VfxCapabilityGate.forceFallback` on the Quest quality level.
- **Test on device early.** Editor GPU != Adreno 650.
## 6.4 Profiling
1. **Visual Effect** inspector: debug info (alive count, bounds) and the graph's **profiling/debug** panels where available.
2. **Frame Debugger:** count VFX draws; confirm instancing batches identical graphs.
3. **GPU profiler / RenderDoc / OVR Metrics Tool on Quest:** compute dispatch time and fragment time.
## Sources
- Requirements and compatibility (17.5): https://docs.unity3d.com/Packages/
[email protected]/manual/System-Requirements.html
- What's new in version 12 (mobile compute guidance): https://docs.unity3d.com/Packages/
[email protected]/manual/whats-new-12.html
- Instancing: https://docs.unity3d.com/Packages/
[email protected]/manual/Instancing.html
- `VisualEffect` (culled, pause, playRate, allowInstancing): https://docs.unity3d.com/6000.5/Documentation/ScriptReference/VFX.VisualEffect.html
- Forum thread on VFX Graph mobile compatibility (staff answers, anecdotal Quest 2 test): https://discussions.unity.com/t/vfx-stop-working-when-update-2021-3-16f1-to-2022-or-2023/904038