Shuriken Particles & Shader Graph

Hi,

in Unity 6.6 (6000.6.0a8) we improved URP Particle Shaders, fixing some issues and exposing a few Particle specific functions to Shader Graph.

Particle Shaders Improvements

Bug Fixes

Deferred/Deferred+

When using Deferred or Deferred+, Particles Lit shaders (Lit and Simple Lit) were missing Rendering Layers, which made them miss lighting when rendered against the background, or when SSAO was enabled.

Also, when using Deferred or Deferred+ and Particle Systems set to Mesh Render Mode with GPU Instancing enabled, Particles Lit wasn’t using the Particle Color.

These fixes were also backported to 6000.5.1f1, 6000.4.13f1, 6000.3.19f1 and 6000.0.78f1.

Shadows

Particle Shaders had no ShadowCaster pass. As a result, the Particle System Renderer module “Cast Shadows” setting had no effect.

VertexStreams Requirements

The list of Custom Vertex Streams required by a Material would suggest fixing Particle Systems using GPU Instancing when a mix of Systems set to using Mesh and Billboards were found in the scene, and would eventually misconfigure them.

Improvements

Mutualization

ParticlesInstancing.hlsl and Particles.hlsl from URP ShaderLibrary were split, so as to share core functionality with Shader Graph.

Both files now exist in RP Core package ShaderLibrary, and are included in the original files which only implement the URP specifics.

Particle functions relevant to Shader Graph were made compatible and available as nodes using the new Shader Function Reflection API. See Shader Graph Nodes.

CBuffer Write & DXC Compliance

ParticlesInstancing.hlsl was writing to unity_ObjectToWorld and unity_WorldToObject to apply Particle Transforms to vertices’ position, normal and tangent.

ParticleInstancingSetup() is now a no-op (empty) function, and vertex data transformations are applied with a new function in the Vertex stage.

That new function is exposed to Shader Graph as Particle Transforms.

As a result, the pragma never_use_dxc was also removed from the Particle shaders.

Note that some platform specific includes still use never_use_dxc.

Shader Graph Nodes

Using any of the following nodes will result in including ParticleInstancing.hlsl and so requires adding the following pragma to the Preprocessor Directives in the Graph Settings.

instancing_options procedural:ParticleInstancingSetup

Particle Graph Templates

Shader Graph Templates ‘Particle Unlit’ and ‘Particle Lit’ were updated to take advantage of GPU Instancing by default.

Particle Transforms

Path: VFX/Particles/Transforms

When using Mesh Render Mode with GPU Instancing enabled, the Particle Transforms node transforms vertex data from Object (Particle) Space to Object (System) Space.

Particle Color

Path: VFX/Particles/Color

When the Particle System uses Billboard Render Mode (or Mesh with GPU Instancing disabled), it simply outputs what is connected to its input (defaults to Vertex Color).
When the Particle System uses Mesh Render Mode with GPU Instancing enabled, it multiplies the input by the Particle Color stored in the Particle Data Structured Buffer.

Texture Sheet Animation & Particle UV

Path: VFX/Particles/Texcoords

When the Particle System is using a Texture Sheet Animation module, the Particle Texcoords Node provides per particle Texture Coordinates to sample a flipbook texture.

Flipbook Mode

Provides UVs for the current particle animation frame.

Flipbook Blending Mode

Provides UVs for the current and next particle animation frames and the blend factor between the two.

It is expected to be fed the UV0 as UV source, and the Vertex Stream source for the Blend Amount (usually UV1.x but depends on Vertex Streams layout).

Note: This node is for advanced use cases where users would want to explicitly use the two UV coords and blend factor. It is otherwise much easier to use the Particle Flipbook Blending subgraph.

The node also expects a _FLIPBOOKBLENDING_ON keyword to be set and enabled. It will otherwise just provide UVs for the current particle animation frame.

When using Mesh Render Mode with GPU Instancing enabled, AnimBlend and UV2 are not required in the Vertex Steams.

Instead, AnimFrame is used.

Note: when using Mesh Render Mode with GPU Instancing enabled, the mesh is expected to feature UV2 that matches UV.

Particle Flipbook Blending

Path: VFX/Particles/Flipbook Blending

When the Particle System is using a Texture Sheet Animation module, the Particle Flipbook Blending subgraph samples the same texture twice, using the Particle UV of the current and next frames, and blends them using the blend factor.

It is expected to be fed the Vertex Stream source for the Blend Amount (usually UV1.x).

The subgraph also adds a _FLIPBOOKBLENDING_ON Shader Feature Keyword.

When left disabled (default) it will just sample the texture with the UVs of the current animation frame.

Note: the up-to-date version of this subgraph comes in 6000.7.0a1 and 6000.6.0b2.

AnimFrame

Path: Input/Particles/AnimFrame

Provides the current Texture Sheet Animation frame.

Custom Particle Data

Should you want to use custom particle data in a shader graph, while using Mesh Render Mode with GPU Instancing enabled, you need to customize the ParticleData struct.

Here’s an example of a custom ParticleData include that features Particle Age:

#ifndef CUSTOM_PARTICLESINSTANCING_INCLUDED
#define CUSTOM_PARTICLESINSTANCING_INCLUDED

#ifndef UNITY_PARTICLE_INSTANCE_DATA
#define UNITY_PARTICLE_INSTANCE_DATA CustomParticleInstanceData
#define UNITY_PARTICLE_INSTANCE_DATA_NO_ANIM_FRAME
#endif

struct CustomParticleInstanceData
{
    float3x4 transform;
    uint color;
    float agePercent;
};

#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ParticlesInstancing.hlsl"

///<funchints>
///     <sg:ProviderKey>Custom.Particles.AgePercent</sg:ProviderKey>
///     <sg:DisplayName>Particle Age</sg:DisplayName>
///     <sg:SearchCategory>Input/Particles</sg:SearchCategory>
///     <sg:SearchName>Age</sg:SearchName>
///     <sg:SearchTerms>Particle, Age</sg:SearchTerms>
///</funchints>
UNITY_EXPORT_REFLECTION
void GetParticleAge(inout float agePercent)
{
#if defined(UNITY_PARTICLE_INSTANCING_ENABLED)
    UNITY_PARTICLE_INSTANCE_DATA data = unity_ParticleInstanceData[unity_InstanceID];
    agePercent = data.agePercent;
#endif
}

#endif // CUSTOM_PARTICLESINSTANCING_INCLUDED

  1. Wrap everything in a define check so as to prevent redefinitions

  2. Check that UNITY_PARTICLE_INSTANCE_DATA isn’t already defined

  3. Define it using your custom struct name

  4. If it doesn’t contain AnimFrame, define UNITY_PARTICLE_INSTANCE_DATA_NO_ANIM_FRAME

  5. Add a function with an `inout` parameter, meant to be fed the VertexStream source in case GPU Instancing is disabled, and overwrite it when it is enabled.

  6. Add the reflection API include, macro and hints to make it available in Shader Graph.

Then in a Shader Graph:

  1. In Preprocessor Directives

    1. add the instancing_options pragma

    2. Include your custom HLSL file to make sure it is included first

  1. Add a Particle Transforms node and connect its outputs to the Vertex Stage inputs.

  2. Use your custom data node in the graph.

On the Particle System, set up the Custom Vertex Stream to match your Particle Data struct.

Normal is only required for Lit shaders.
Tangent is only required for Lit shaders using Normal Maps.
AnimFrame is only required for Texture Sheet Animation UVs when using GPU Instancing.
AnimBlend is otherwise required for Texture Sheet Animation UVs when not using GPU Instancing.

Samples

We’ve updated samples to reflect those improvements.

Particle Shader Graph sample moved from the HDRP package to Shader Graph, and includes examples of shader graphs supporting GPU Instancing, Flipbook Blending, Soft Particles, Camera Fading, Distortion and Custom Particle Data. They work with both URP and HDRP.

The sample update landed in 6000.7.0a2 and is being backported to 6000.6.0b2.

1 Like