Skip to content

Instantly share code, notes, and snippets.

@adammyhre
Last active June 21, 2026 17:34
Show Gist options
  • Select an option

  • Save adammyhre/a8d21f95b4780035625195b8679fbff0 to your computer and use it in GitHub Desktop.

Select an option

Save adammyhre/a8d21f95b4780035625195b8679fbff0 to your computer and use it in GitHub Desktop.
Shader Function Reflection API Examples
// Example 2 — Customizing the node with XML hints (Unity 6.5+)
//
// The same three ingredients as Example 1, plus reflection hints that change
// how the node looks and behaves in Shader Graph:
//
// funchints -> customize the node as a whole (name, search category...)
// paramhints -> customize an individual port (display name, color picker,
// slider range, default value...)
//
// Hint validation is strict and type-aware:
// <sg:Color/> only valid on float3/float4 (and half variants)
// <sg:Range> only valid on a float/half scalar (synonym: Slider)
// <sg:Default> a comma separated list of floats
//
// This node desaturates the input color, then tints it - a quick duotone /
// sepia look driven entirely by the Tint color picker and Strength slider.
#include "ShaderApiReflectionSupport.hlsl"
///<funchints>
/// <sg:ProviderKey>Malevolent.Colorize</sg:ProviderKey>
/// <sg:DisplayName>Colorize</sg:DisplayName>
/// <sg:SearchCategory>Malevolent/Color</sg:SearchCategory>
///</funchints>
///<paramhints name = "tint">
/// <sg:DisplayName>Tint</sg:DisplayName>
/// <sg:Color/>
/// <sg:Default>1, 0.4, 0.1</sg:Default>
///</paramhints>
///<paramhints name = "strength">
/// <sg:DisplayName>Strength</sg:DisplayName>
/// <sg:Range>0, 1</sg:Range>
/// <sg:Default>0.75</sg:Default>
///</paramhints>
UNITY_EXPORT_REFLECTION
float3 Colorize(float3 color, float3 tint, float strength) {
float luma = dot(color, float3(0.2126, 0.7152, 0.0722));
return lerp(color, luma * tint, strength);
}
// Example 3 — Procedural energy / lava field (Unity 6.5+)
//
// Two things this example shows off that the first two didn't:
//
// 1. Helper functions. Only the function marked with UNITY_EXPORT_REFLECTION
// becomes a node. Everything else in the file (Hash, ValueNoise, Fbm) is
// just normal HLSL that the exported function is free to call. This is how
// you wrap noise, SDFs, or SRP Shader Library functions behind one clean node.
//
// 2. Multiple outputs via 'out' parameters. The reflection API supports
// in / out / inout parameters and a void return type, so a single node can
// drive both Base Color and Emission on the master stack.
#include "ShaderApiReflectionSupport.hlsl"
// --- Helper functions (not reflected, just plain HLSL) ----------------------
float Hash(float2 p) {
p = frac(p * float2(123.34, 456.21));
p += dot(p, p + 45.32);
return frac(p.x * p.y);
}
float ValueNoise(float2 uv) {
float2 i = floor(uv);
float2 f = frac(uv);
float a = Hash(i);
float b = Hash(i + float2(1, 0));
float c = Hash(i + float2(0, 1));
float d = Hash(i + float2(1, 1));
float2 u = f * f * (3.0 - 2.0 * f);
return lerp(lerp(a, b, u.x), lerp(c, d, u.x), u.y);
}
float Fbm(float2 uv) {
float sum = 0.0;
float amp = 0.5;
[unroll]
for (int i = 0; i < 5; i++) {
sum += amp * ValueNoise(uv);
uv *= 2.0;
amp *= 0.5;
}
return sum;
}
// --- The reflected node -----------------------------------------------------
///<funchints>
/// <sg:ProviderKey>Malevolent.EnergyField</sg:ProviderKey>
/// <sg:DisplayName>Energy Field</sg:DisplayName>
/// <sg:SearchCategory>Malevolent/Procedural</sg:SearchCategory>
///</funchints>
///<paramhints name = "coolColor">
/// <sg:DisplayName>Cool Color</sg:DisplayName>
/// <sg:Color/>
/// <sg:Default>0.05, 0.0, 0.2</sg:Default>
///</paramhints>
///<paramhints name = "hotColor">
/// <sg:DisplayName>Hot Color</sg:DisplayName>
/// <sg:Color/>
/// <sg:Default>1.0, 0.45, 0.1</sg:Default>
///</paramhints>
///<paramhints name = "scale">
/// <sg:DisplayName>Scale</sg:DisplayName>
/// <sg:Range>1, 16</sg:Range>
/// <sg:Default>4</sg:Default>
///</paramhints>
///<paramhints name = "speed">
/// <sg:DisplayName>Speed</sg:DisplayName>
/// <sg:Range>0, 2</sg:Range>
/// <sg:Default>0.5</sg:Default>
///</paramhints>
UNITY_EXPORT_REFLECTION
void EnergyField(
float2 uv,
float time,
float3 coolColor,
float3 hotColor,
float scale,
float speed,
out float3 albedo,
out float3 emission) {
float n = Fbm(uv * scale + time * speed);
float ramp = saturate(n * n * 2.0);
albedo = lerp(coolColor, hotColor, ramp);
emission = hotColor * pow(ramp, 3.0) * 4.0;
}
// Extra — Wrapping an SRP Shader Library function (Unity 6.5+)
//
// One of the headline use cases for the reflection API: surfacing functions
// that already live in the SRP Shader Library without writing a Custom Function
// node by hand. Here we expose Unity's perceptual-quality desaturation helper
// (Luminance + a simple saturation control) as a one-click node.
//
// Because the file includes Color.hlsl, the wrapped function has access to
// everything in the URP/Core shader library.
#include "ShaderApiReflectionSupport.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
///<funchints>
/// <sg:ProviderKey>Malevolent.Saturation</sg:ProviderKey>
/// <sg:DisplayName>Saturation</sg:DisplayName>
/// <sg:SearchCategory>Malevolent/Color</sg:SearchCategory>
///</funchints>
///<paramhints name = "amount">
/// <sg:DisplayName>Amount</sg:DisplayName>
/// <sg:Range>0, 2</sg:Range>
/// <sg:Default>1</sg:Default>
///</paramhints>
UNITY_EXPORT_REFLECTION
float3 Saturation(float3 color, float amount) {
// Luminance() comes from the SRP Core Color library include above.
float luma = Luminance(color);
return lerp(luma.xxx, color, amount);
}
// Example 1 — Basics of the Shader Function Reflection API (Unity 6.5+)
//
// Three ingredients are all you need to turn a plain HLSL function into a
// Shader Graph node:
// 1. #include "ShaderApiReflectionSupport.hlsl" (gives us the macro)
// 2. UNITY_EXPORT_REFLECTION (marks the function for reflection)
// 3. an <sg:ProviderKey> hint (makes it show up in the Create Node menu)
//
// Input/output ports are reflected straight from the function signature, so
// the three parameters below become three input ports, and the float2 return
// value becomes the output port.
#include "ShaderApiReflectionSupport.hlsl"
///<funchints>
///</funchints>
///<funchints>
/// <sg:ProviderKey>Malevolent.ScrollingUV</sg:ProviderKey>
/// <sg:SearchCategory>Malevolent/UV</sg:SearchCategory>
///</funchints>
UNITY_EXPORT_REFLECTION
float2 ScrollingUV(float2 uv, float2 speed, float time) {
return uv + frac(speed * time);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment