Preprocessor Directives in Graph Settings

Hi,

In Unity 6.6 (6000.6.0a5), we’re adding Preprocessor Directives to Shader Graph, allowing you to add Pragmas, Defines and Includes to the shader without relying on Custom Function Nodes.

Preprocessor Directives

The Preprocessor Directives can be found at the bottom of the Graph Settings.


Pragmas

Pragmas can now be added to shader graphs. This allows you to add pragma directives such as:

  • enable_debug_symbols, which generates shader debug symbols.
  • use_dxc, which makes the shader compile with the DXC compiler.
  • intancing_options procedural:functionName, which enables procedural instancing with the supplied function.

To learn more about pragmas, see HLSL pragma directives reference.

Defines

Custom Defines can be set so as to allow for constant branching or provide local constant values.

Examples:

  • _DEBUG // temporarily switch between branches
  • _MAX_ITERATIONS 16 // set the maximum number of iterations for a loop in a Custom Function Node

The expected format is:

NAME VALUE (optional) // Comments (optional)

Where:

  • NAME is the name of the #define.
  • VALUE is usually a number (but can be anything to replace occurrences of NAME with).
  • // Comments must be put behind double slashes.

Toggle

If the define is just a name like _DEBUG, you can:

  • Use it in a Custom Function with #ifdef, #ifndef, #if defined(_DEBUG) for static branching.
  • Use a Custom Function Node to fetch the state in the shader graph.
  • Or use a Predefined Keyword.
    Predefined Keywords use predefined constants.
#ifdef _DEBUG
Out = true;
#else
Out = false;
#endif

Constant Value

If the define is a constant value, like MAX_ITERATIONS 16, you should declare a default value in the Custom Function like this:

#ifndef MAX_ITERATIONS
#define MAX_ITERATIONS 16
#endif
float CustomNoise(float2 uv)
{
    [unroll]
    for (int i = 0; i < MAX_ITERATION; i++)
    {
    // recursive noise
    }
}

Overriding Hierarchy

Since graph defines are set before includes and custom function code, their definition prevails.

Although they can be overridden with Shader Constant Defines in Project Settings / Graphics and/or Build Profiles Graphics Settings, which are also new in Unity 6.6.

Note: Shader Constant Defines in Graphics settings only allow for name/value pairs. If you want to override a name such as _DEBUG, you may just set a dummy value like _DEBUG 1.

But then you should use a Custom Function Node to branch, as Predefined Keywords expect no value.

#ifdef _DEBUG
Out = _DEBUG == 1;
#else
Out = false;
#endif

Includes

Shader Includes (HLSL files) can now be included without using a Custom Function Node.

This is useful to reference an include that contains some definitions that need to be included before others referenced by Custom Function Nodes.

14 Likes

Particle Shader Example

For example, pragmas and includes can be used to enable GPU instancing in shaders for Particle Systems.

TL;DR; While shader graph shaders do support GPU instancing, they don’t implement Procedural instancing. As a result, when used on a Particle System set to Mesh Render Mode, GPU Instancing is disabled, and Dynamic Batching is used instead, which hits performance pretty badly as vertices are transformed on the CPU.

More on this topic here.

3 Likes

Keyword Example

Pragmas can also be used to add Keywords, as a work-around for when the variant limit becomes a problem. More about it here.

1 Like

Could we get an option to specificy location/order of Includes.

For example I would like to override Lighting.hlsl but using this solution puts include after SubTarget includes.

It would be great if we could specify location with enums for example:

Currently in 6000.6.0a5

Location needed

1 Like

Thanks for your feedback!
That’s why it’s called “Graph” Includes :slight_smile:

I’ll check with the team if we can improve this before the bigger improvements we plan on how targets work.

1 Like

Add the official tag and pin it!

2 Likes

so now can we use DXC instead of FXC