Unity’s Visual Effect Graph system can be a powerful tool
But if you plan to use it for spawning a large number of effects at the same time, performance quickly becomes an issue.
Say, for instance, you want to use Visual Effect Graph for bullet impacts. If two bullet impacts need to be created on the same frame, normally you would spawn two separate impacts, each contained within a game object.
Creating multiple instances of the effect over different game objects is inefficient, and there is a better way to handle spawning multiple systems at the same time.
We could update the system’s position and then trigger an event that creates a new particle system. This works but only for a single particle system per frame.
One way to get around this would be to make an array of systems inside the same Visual Effect graph, but that would require management of the different event triggers and positional data variables. It works well if done, but it is not a great system to deal with.
Visual Effect graph does not allow an array or list of positions, so we can’t upload the positional data except by doing it with a single position per variable. So we look to other allowed inputs to see if there is another way to insert the positional data into the graph.
Correct Solution – Point Cache
Visual Effect graph DOES allow input of 2d texture maps. And there is a way to convert a list of 3d positional data into a 2d texture map. This way the positional data can be loaded into the graph and used to spawn multiple particle effect systems at the same time.
To do this we need to create a way to convert this data into a 2d texture map. This can be done by using the property binder component.
From the Unity Visual Effect Graph manual: “Property Binders are C# Behaviors you can attach to a GameObject with a Visual Effect Component: these behaviors enable making connections between scene or gameplay values and Exposed Properties for this Visual Effect instance.”
Property binders have a bunch of built-in data types you can use, and it’s pretty easy to create your own which allows you to define the data that is available to the Visual Effect instance.
Built-in Property Binders
Visual Effect Graph package comes with the following built-in property binders:
- Audio Spectrum to AttributeMap : Bakes the Audio Spectrum to an Attribute map and binds it to a Texture2D and uint Count properties
- Enabled : Binds the Enabled flag of a Game Object to a bool property
- Point Cache
- Hierarchy to AttributeMap : Binds positions an target positions of a hierarchy of transforms to Texture2Ds AttributeMaps and uint Count
- Multiple Position Binder: Binds positions of a list of transforms to a Texture2D AttributeMap and uint Count
- Axis : Binds the float value of an Input Axis to a float property
- Button : Binds the bool value of a button press state to a bool property
- Key : Binds the bool value of a keyboard key press state to a bool property
- Mouse : Binds the general values of a mouse (Position, Velocity, Clicks) to exposed properties
- Touch : Binds a input values of a Touch Input (Position, Velocity) to exposed properties
- Light : Binds Light Properties (Color, Brightness, Radius) to exposed properties
- Plane : Binds Plane Properties (Position, Normal) to exposed properties
- Terrain : Binds Terrain Properties (Size, Height Map) to exposed properties
- Position: Binds game object position to vector exposed property
- Position (previous): Binds previous game object position to vector exposed property
- Transform: Binds game object transform to transform exposed property
- Velocity: Binds game object velocity to vector exposed property
- Raycast: Performs a Physics Raycast and binds its result values (hasHit, Position, Normal) to exposed properties.
- Sphere: Binds properties of a Sphere Collider to a Sphere exposed property.
- Dropdown: Binds the index of a Dropdown to a uint exposed property
- Slider: Binds the value of a float slider to a uint exposed property
- Toggle: Binds the bool value of a toggle to a bool exposed property.
Property Binder Setup
In this case, we are interested in the Point Cache built-in property binder. You will find this in the dropdown like so:
The 2 fields need to be set to fields inside of the attached Visual Effect Graph on the same game object. They will be automatically populated for you.
Link to Visual Effect
Next, you just need to convert that data inside of Visual Effect back into positional data that can be used to spawn independent Visual Effect systems.
This is done by a simple sub-graph shown below:
This will take the texture map data and convert it into positional and directional data. The data can be referenced in the VFX Graph by using the SampleU variable.
Now that the data is in the graph, we can use it to spawn each system individually. Just add the block that we made to convert the data back to positional and rotational values:
This is powerful because now the effects are all drawn on the same draw call. And because they are created in Visual Effect graph, it is all done on the GPU.
Doing this allowed the creation of tens of thousands of particle systems with very little effect on the framerate!