Quick answer: Add a Spawn Event named “OnHit” (or whatever) on the graph; route it into a Spawn Context. From script call vfx.SendEvent("OnHit", attribute). The graph editor target panel shows the event count incrementing if the binding is correct.

Hit registers, you call SendEvent on the VisualEffect, nothing spawns. The graph plays its idle effect normally; your custom event is invisible. The chain from script to GPU has three parts and any of them can be wrong.

The Symptom

SendEvent returns no value, no error, no particles. The graph keeps emitting whatever it was emitting before. Toggling the VisualEffect off/on or calling Play() works, but custom events do not.

The Three Required Pieces

1. Spawn Event in the graph. Right-click in the graph → Create Node → Event → Event. Name it (e.g. “OnHit”). The name is case-sensitive and must match SendEvent exactly.

2. Spawn Context wired from the event. Drag from the Event node’s output to a Spawn Context input. Spawn Contexts are the only nodes that consume events; without one wired, the event has nowhere to go.

3. SendEvent from script with the matching name.

using UnityEngine;
using UnityEngine.VFX;

public class HitVFX : MonoBehaviour
{
    public VisualEffect vfx;
    private static readonly int _hitId = Shader.PropertyToID("OnHit");

    public void Hit(Vector3 position, Vector3 normal)
    {
        var attr = vfx.CreateVFXEventAttribute();
        attr.SetVector3("position", position);
        attr.SetVector3("velocity", normal * 5f);
        vfx.SendEvent(_hitId, attr);
    }
}

Caching the event id with PropertyToID is a small win; the string overload also works.

Reading the Attribute on the Graph Side

To use the position/velocity you sent, add Set Position from Event and Set Velocity from Event blocks in the Initialize Particle context. The blocks expose dropdowns to pick which Spawn Event the attribute came from.

Verifying It Worked

Select the GameObject. Open the VFX Graph asset. The Target Visual Effect dock at the bottom of the graph shows live stats per Spawn Context: Spawn Count, Spawn Per Second, and event arrivals. SendEvent should bump the “Spawn Count” or “Direct Spawn” figure.

If the figure stays at zero, the script side is fine but the graph side is not receiving. Re-check: Event node name, edge into a Spawn Context, asset is saved.

Common Pitfall: Output Particle Quad Stops Listening

If the graph compiles with errors, the runtime swap-in fails silently and SendEvent does nothing. Open the graph and look for red nodes. A common cause is changing an exposed property type without re-saving its consumers; everything appears connected but the compile fails.

Pooling Caveat

VisualEffect components do not pool well across scenes — SendEvent on a freshly enabled VisualEffect may fire before the GPU sees the activation. Wait one frame after enable before SendEvent, or call vfx.Play() before sending custom events to force initialization.

“Spawn Event named, wired into a Context, SendEvent with the exact name. Graph dock confirms the count.”

Related Issues

For VFX Graph not rendering at all, see VFX not rendering. For exposed property changes ignored, see exposed property not applied.

Event → Spawn Context. Send by name. Watch the dock.