Unity URP shaders in HLSL

Unity's Universal Render Pipeline uses HLSL with its own include files and a slightly different structure from the Built-in pipeline. The shader code you write for the picture is identical; only the wrapper changes. ShaderBattle writes that wrapper for you when you export.

Things to know about HLSL

  • The fragment function is the same HLSL as in the Built-in pipeline: float4 frag(float2 uv).
  • URP shaders use HLSLPROGRAM and include Core.hlsl instead of UnityCG.cginc.
  • Vertex positions go through TransformObjectToHClip.
  • For Shader Graph, paste your functions into a Custom Function node (File mode) and call frag(uv).

Cheat sheet

IdeaWrite
Vectorsfloat2 float3 float4
Declare a valuefloat d = length(p);
A functionfloat circle(float2 p, float r) { ... }
Matricesfloat2x2, multiply with mul(M, v)
Blendlerp(a, b, t)
Fractional partfrac(x)
Clamp to 0..1saturate(x)
Remainderfmod(a, b) (keeps the sign of a)
Choosec ? a : b
Angle of a vectoratan2(y, x)
Time in secondstime, or Unity's _Time.y
Pixel positionuv (0..1, bottom-left)
Width / heightaspect, or _ScreenParams.x / _ScreenParams.y
Entry pointfloat4 frag(float2 uv) { return …; }

Handy built-ins: sin cos abs sign floor ceil frac step smoothstep clamp min max pow exp sqrt length distance dot cross normalize reflect

Gotchas

  • Every pixel runs on its own, with no memory of other pixels.
  • Declare a function above the place you use it.
  • Prefer 2.0 over 2 in maths. This site fixes most cases for you; real engines may not.
  • Loops need a small fixed count: for (int i = 0; i < 5; i++).

Example: a glowing ring

The same shader as it is written for Unity (URP):

float4 frag(float2 uv)
{
    float2 p = (uv - 0.5) * float2(aspect, 1.0);
    float d = length(p);
    float m = 1.0 - smoothstep(0.0, 0.02, abs(d - 0.3));
    float3 bg = float3(0.08, 0.08, 0.12);
    float3 fg = float3(0.4, 0.9, 1.0);
    return float4(lerp(bg, fg, m), 1.0);
}

Exporting to Unity URP

In a URP project: Create → Shader → Unlit Shader, replace everything with this, then put a material using it on a Quad. For Shader Graph, paste your functions into a Custom Function node (File mode) and call frag(uv).

Shader "ShaderBattle/Glowing ring"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" }
        Pass
        {
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment fragMain
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

            struct Attributes { float4 positionOS : POSITION; float2 uv : TEXCOORD0; };
            struct Varyings { float4 positionHCS : SV_POSITION; float2 uv : TEXCOORD0; };

            Varyings vert(Attributes IN)
            {
                Varyings OUT;
                OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);
                OUT.uv = IN.uv;      // (0,0) bottom-left, (1,1) top-right
                return OUT;
            }

            // Globals the website gives you for free:
            #define time _Time.y                    // seconds since start
            static const float aspect = 1.0;        // a Quad is square. (The website renders 4:3.)

            // ---- your code from ShaderBattle -------------------------------
            float4 frag(float2 uv)
            {
                float2 p = (uv - 0.5) * float2(aspect, 1.0);
                float d = length(p);
                float m = 1.0 - smoothstep(0.0, 0.02, abs(d - 0.3));
                float3 bg = float3(0.08, 0.08, 0.12);
                float3 fg = float3(0.4, 0.9, 1.0);
                return float4(lerp(bg, fg, m), 1.0);
            }
            // ----------------------------------------------------------------

            half4 fragMain(Varyings IN) : SV_Target
            {
                return frag(IN.uv);
            }
            ENDHLSL
        }
    }
}

Questions

What is the difference between Built-in and URP shaders?

The picture code is the same. The surrounding boilerplate (includes, vertex transform, tags) is different. Both exports are available in the language picker.

Does the exported shader work in HDRP?

It is written for URP. HDRP has its own structure; the fragment function itself still ports over.

Other languages

Unity (Built-in) · Unreal · Shadertoy / WebGL · OpenGL (LWJGL, raylib) · three.js · GameMaker · LÖVE (Lua) · Godot · Apple (iOS, macOS) · WebGPU / Bevy