Using AI for Unity Shaders: URP HLSL and Shader Graph Help That Works

Illustration: a glowing node graph of connected shader nodes beside a shiny sphere

Ask an AI assistant for a Unity shader and there is a good chance you get something that looks right, compiles, and renders bright pink in your URP project. That is not because AI is bad at shaders. It’s because most shader code on the internet was written for the Built-in Render Pipeline. This guide shows how to get AI Unity shaders for URP that actually work: how to spot Built-in CG code, the URP HLSL template the AI should follow, what to ask for lighting and shadows, and how to use AI to plan Shader Graph node setups instead of writing code at all.

Why AI Writes Built-in Shaders by Mistake

Unity shaders have been written in a CG-flavoured style for over a decade: CGPROGRAM blocks, UnityCG.cginc, surface shaders with #pragma surface. Tutorials, forum answers and GitHub repos are full of it. URP uses a different shader library, written in HLSL, with different include files, function names and rules for material properties.

Language models learn from that public code, so their default “Unity shader” is often the old style. Some Built-in style vertex/fragment shaders still draw in URP, but they won’t be SRP Batcher compatible and won’t receive URP lighting. Surface shaders don’t work in URP at all and show up magenta. Mixing the two styles in one file causes compile errors.

The fix is simple: tell the AI which pipeline you use, give it the structure you expect, and know how to check the output.

How to Spot Built-in Code in Seconds

If you see any of these, the shader was written for the Built-in pipeline:

  • CGPROGRAM / ENDCG instead of HLSLPROGRAM / ENDHLSL
  • #include "UnityCG.cginc" or "Lighting.cginc"
  • #pragma surface surf Standard (a surface shader)
  • UnityObjectToClipPos, UnityObjectToWorldNormal, _WorldSpaceLightPos0, _LightColor0
  • sampler2D _MainTex; with tex2D(...)
  • "LightMode"="ForwardBase"

URP code looks like this instead:

  • HLSLPROGRAM / ENDHLSL
  • #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
  • TransformObjectToHClip, TransformObjectToWorldNormal, GetMainLight()
  • TEXTURE2D(_BaseMap); SAMPLER(sampler_BaseMap); with SAMPLE_TEXTURE2D(...)
  • Material properties inside CBUFFER_START(UnityPerMaterial) … CBUFFER_END
  • "RenderPipeline"="UniversalPipeline" in the SubShader tags

The same habit applies to C#. AI often reaches for outdated APIs in scripts too. Our guide to hallucinated and outdated APIs covers how to catch those.

The URP HLSL Template to Give the AI

The most reliable trick is to paste a minimal, known-good URP shader into the conversation and say “follow this structure”. Here is an unlit textured shader, based on the structure Unity’s own URP documentation uses:

Shader "Custom/URPUnlitTint"
{
    Properties
    {
        _BaseMap ("Base Map", 2D) = "white" {}
        _BaseColor ("Base Color", Color) = (1, 1, 1, 1)
    }

    SubShader
    {
        Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" "Queue" = "Geometry" }

        Pass
        {
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #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;
            };

            TEXTURE2D(_BaseMap);
            SAMPLER(sampler_BaseMap);

            CBUFFER_START(UnityPerMaterial)
                float4 _BaseMap_ST;
                half4 _BaseColor;
            CBUFFER_END

            Varyings vert(Attributes IN)
            {
                Varyings OUT;
                OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);
                OUT.uv = TRANSFORM_TEX(IN.uv, _BaseMap);
                return OUT;
            }

            half4 frag(Varyings IN) : SV_Target
            {
                half4 tex = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, IN.uv);
                return tex * _BaseColor;
            }
            ENDHLSL
        }
    }
}

Key rules the AI must keep:

  • Every property from the Properties block (except textures) goes in the UnityPerMaterial CBUFFER, including each texture’s _ST tiling vector. Miss one and the shader loses SRP Batcher compatibility.
  • Textures and samplers stay outside the CBUFFER.
  • Use URP names. _BaseMap and _BaseColor match URP’s own Lit shader, so swapping materials between shaders keeps their values.

A Prompt That Produces URP Code

Give the pipeline, version, structure and constraints up front:

I'm using Unity 6 with URP 17. Write a hand-written HLSL shader,
not Shader Graph, and not Built-in pipeline code.

Rules:
- HLSLPROGRAM, include URP's Core.hlsl (and Lighting.hlsl if needed).
- No UnityCG.cginc, no surface shaders, no CGPROGRAM.
- All material properties in CBUFFER_START(UnityPerMaterial).
- Use TEXTURE2D/SAMPLER/SAMPLE_TEXTURE2D macros.
- Follow the structure of the template below.

Effect: an unlit hologram. Base color with a scrolling horizontal
scanline pattern (properties for line density and scroll speed),
a fresnel rim that brightens edges, transparent alpha blending.

[paste template here]

Transparent shaders need extra parts the AI should add on its own: "Queue"="Transparent" and "RenderType"="Transparent" tags, Blend SrcAlpha OneMinusSrcAlpha and ZWrite Off. If they’re missing, ask why. Explaining its own output is a good way to make the AI catch its mistakes.

When the shader errors, paste the exact error text from the shader’s Inspector or the Console, plus the line it points to. “It doesn’t work” gets you a rewrite. The exact error gets you a fix.

Lighting, Shadows and Missing Passes

Unlit effects are where AI-written HLSL shines. Lit shaders are where it struggles, because URP lighting involves keywords, shadow coordinates and several extra passes. A simple main-light diffuse is manageable:

// Add to the includes:
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"

// Add to Attributes:  float3 normalOS : NORMAL;
// Add to Varyings:    float3 normalWS : TEXCOORD1;

// In vert:
OUT.normalWS = TransformObjectToWorldNormal(IN.normalOS);

// In frag:
Light mainLight = GetMainLight();
half ndotl = saturate(dot(normalize(IN.normalWS), mainLight.direction));
half3 lit = tex.rgb * _BaseColor.rgb * mainLight.color * ndotl;
return half4(lit, 1);

What that doesn’t do, and what AI often forgets to mention:

  • Receiving shadows needs the main light shadow keywords and a shadow coordinate passed to GetMainLight. The keyword names have shifted across URP versions, which is exactly where AI guesses wrong.
  • Casting shadows needs a separate pass with "LightMode"="ShadowCaster". Without it, the object casts no shadow at all.
  • Depth passes. Features like SSAO and depth-based effects need DepthOnly and DepthNormals passes. Without them, the object can be missing from the depth texture.
  • Additional lights, ambient light and fog each need their own code.

If you need full lighting, shadows and everything else, Shader Graph handles all of that for you. Use hand-written HLSL for unlit effects, stylized lighting, or when you really need control. Our URP toon shader guide shows a stylized lit shader built the Shader Graph way.

📚 Want to understand the code AI gives you?

AI can write shaders, but you still need to read them. A good book on graphics programming and the maths behind lighting makes AI output far easier to judge and fix. We picked a few that are worth the shelf space.

See our programming and game design book picks →

Planning Shader Graph Nodes With AI

AI can’t build a Shader Graph for you inside a chat window, but it’s very good at planning one. Ask for the node chain as a text recipe:

I'm using Shader Graph in Unity 6 URP. Give me a node-by-node recipe
for a dissolve effect on a Lit material: noise-based dissolve with a
glowing edge. List the Blackboard properties with types, then each
node and what connects to what, then the Graph Settings I need to change.
Only use nodes that exist in Shader Graph.

A good answer looks like this:

  1. Blackboard: Cutoff (Float, slider 0 to 1), Edge Width (Float), Edge Color (Color, HDR), Noise Scale (Float).
  2. Simple Noise with Scale from Noise Scale.
  3. Add: Cutoff + Edge Width. Then Step with that as Edge and noise as In, then One Minus to get a thin band just above the cutoff. Pixels below the cutoff get clipped anyway, so only the edge stays lit.
  4. Multiply the band by Edge Color, into the Emission block.
  5. Noise into Alpha, Cutoff into Alpha Clip Threshold.
  6. Graph Settings: enable Alpha Clipping so the Alpha Clip Threshold block appears.

Build it yourself and check each node preview as you go. If the AI names a node you can’t find in the Create Node search, ask for an alternative. Recipes sometimes mix in node names from other engines. If you’re new to the editor itself, start with our Shader Graph tutorial for beginners.

For a piece of maths that’s awkward in nodes, the Custom Function node lets you paste HLSL. In File mode, the function name needs a precision suffix, such as MyNoise_float, and you type MyNoise as the name in the node. Tell the AI this, or it will write a plain function name and the node will fail to find it.

Checking the Result

Before you trust an AI shader:

  • Select the .shader asset. The Inspector shows compile errors and whether it’s SRP Batcher compatible.
  • Use the Frame Debugger (Window > Analysis > Frame Debugger) to see if the object draws in the passes you expect, including shadows.
  • Test in a build for your target platform, especially mobile and WebGL. A shader that’s fine in the editor can fail on a weaker GPU or graphics API.
  • Change every property in the material Inspector and make sure each one does something. AI sometimes declares properties it never uses.

Troubleshooting

Material is pink or magenta

The shader failed to compile or isn’t supported by URP. Surface shaders always do this. Check the shader Inspector for errors, then ask for a URP HLSL version. Our pink materials guide covers other causes, such as unconverted imported materials.

“undeclared identifier ‘UnityObjectToClipPos’”

The AI used a Built-in function inside a URP HLSL shader. Replace it with TransformObjectToHClip(positionOS.xyz), and ask the AI to remove all other Built-in functions too.

“redefinition of ‘_Time’” or other redefinition errors

The shader includes both UnityCG.cginc and URP’s Core.hlsl. They define the same things. Remove the CG include and port its functions.

“SRP Batcher: not compatible” in the shader Inspector

A material property is outside the UnityPerMaterial CBUFFER, or the CBUFFER differs between passes. Every pass must declare the same CBUFFER with the same properties in the same order.

The object casts no shadow, or vanishes in effects like SSAO

The shader has no ShadowCaster or depth passes. Ask the AI to add them, or rebuild the effect in Shader Graph.

Custom Function node error: function not found

The HLSL function is missing the _float or _half suffix, or the name in the node doesn’t match. Check that the inputs and outputs match the function signature too.

FAQ

Can AI write URP shaders that actually work?

Yes, especially unlit and stylized effects, as long as you state URP, give it a template and paste exact errors back. Full PBR lighting with shadows is better done in Shader Graph.

Should I use HLSL or Shader Graph with AI help?

Shader Graph for most lit materials, because URP handles lighting, shadows and passes for you. HLSL for unlit effects, post-style tricks or when you need exact control.

Can I convert a Built-in CG shader to URP with AI?

Often, yes. Paste the old shader plus the URP template and ask for a port. Expect to fix lighting code by hand, since Built-in lighting functions have no one-to-one URP equivalent.

Why does my AI shader work in the editor but not on mobile?

Mobile GPUs and graphics APIs are stricter about precision and features. Test on the device, and ask the AI to avoid features your target doesn’t support.

Can AI read my Shader Graph file?

The .shadergraph file is JSON, so an AI can read it, but it’s long and hard to edit by hand. Describing the graph or sharing screenshots of the node setup usually works better.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *