agentsclimarketplace

Urp hlsl templates

Skill adevra/unity-shader-agent-skills/skills/urp-hlsl-templates

Curated agent skills for Unity shader development targeting mobile GPUs and WebGL browsers.

Install
npx -y skills add adevra/unity-shader-agent-skills --skill urp-hlsl-templates

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 8 stars8 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Production-ready URP HLSL/ShaderLab code templates with SRP Batcher compatibility for Unity

SKILL.md

12.9 KB, as published. Nobody here has run it

URP HLSL Shader Code Templates

TRIGGER

Use this skill when the user wants to write a Unity shader in HLSL/ShaderLab code (not Shader Graph) for Universal Render Pipeline. Triggers include: "URP shader", "HLSL", "ShaderLab", "write a shader", "custom shader", "vertex fragment shader", "SRP Batcher", "CBUFFER", "custom lit shader", "unlit shader", or any code-based shader authoring in URP. Also trigger when converting Built-in pipeline shaders to URP, or when the user references Cyanilux templates, phi-lira gists, or NedMakesGames tutorials.


CORE RULES — URP HLSL

  1. Always use HLSLPROGRAM / ENDHLSL, never CGPROGRAM / ENDCG. URP uses HLSL, not CG. CG blocks will compile but miss URP-specific includes and macros.

  2. All material properties must be in a CBUFFER_START(UnityPerMaterial) / CBUFFER_END block for SRP Batcher compatibility. Without this, each material breaks batching and gets its own draw call.

  3. Include URP Core, not legacy Unity includes.

    // CORRECT (URP)
    #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
    #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
    
    // WRONG (Built-in / legacy)
    #include "UnityCG.cginc"
    #include "Lighting.cginc"
    
  4. Use URP transform macros, not legacy ones:

    // URP                              // Legacy equivalent
    TransformObjectToHClip(posOS)       // UnityObjectToClipPos(v.vertex)
    TransformObjectToWorld(posOS)       // mul(unity_ObjectToWorld, v.vertex)
    TransformObjectToWorldNormal(nOS)   // UnityObjectToWorldNormal(v.normal)
    TransformWorldToHClip(posWS)        // mul(UNITY_MATRIX_VP, float4(posWS, 1))
    GetVertexPositionInputs(posOS)      // (convenience struct)
    GetVertexNormalInputs(nOS, tanOS)   // (convenience struct)
    
  5. Tags must include "RenderPipeline" = "UniversalPipeline" or the shader won't be recognized by URP.

  6. Use TEXTURE2D and SAMPLER macros instead of sampler2D:

    TEXTURE2D(_MainTex);
    SAMPLER(sampler_MainTex);
    // Sample with:
    half4 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv);
    

TEMPLATE: URP UNLIT (MOBILE-READY)

Minimal unlit shader with SRP Batcher compatibility. Use as starting point for mobile shaders:

Shader "Custom/URP_Unlit_Mobile"
{
    Properties
    {
        _BaseMap ("Base Map", 2D) = "white" {}
        _BaseColor ("Base Color", Color) = (1, 1, 1, 1)
    }
    
    SubShader
    {
        Tags
        {
            "RenderType" = "Opaque"
            "RenderPipeline" = "UniversalPipeline"
            "Queue" = "Geometry"
        }
        
        Pass
        {
            Name "ForwardLit"
            Tags { "LightMode" = "UniversalForward" }
            
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fog
            
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            
            // SRP Batcher compatible: all properties in CBUFFER
            CBUFFER_START(UnityPerMaterial)
                float4 _BaseMap_ST;
                half4 _BaseColor;
            CBUFFER_END
            
            TEXTURE2D(_BaseMap);
            SAMPLER(sampler_BaseMap);
            
            struct Attributes
            {
                float4 positionOS : POSITION;
                float2 uv : TEXCOORD0;
            };
            
            struct Varyings
            {
                float4 positionCS : SV_POSITION;
                float2 uv : TEXCOORD0;
                half fogFactor : TEXCOORD1;
            };
            
            Varyings vert(Attributes input)
            {
                Varyings output;
                VertexPositionInputs posInputs = GetVertexPositionInputs(input.positionOS.xyz);
                output.positionCS = posInputs.positionCS;
                output.uv = TRANSFORM_TEX(input.uv, _BaseMap);
                output.fogFactor = ComputeFogFactor(posInputs.positionCS.z);
                return output;
            }
            
            half4 frag(Varyings input) : SV_Target
            {
                half4 color = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv) * _BaseColor;
                color.rgb = MixFog(color.rgb, input.fogFactor);
                return color;
            }
            ENDHLSL
        }
        
        // Shadow caster pass (required for objects to cast shadows)
        Pass
        {
            Name "ShadowCaster"
            Tags { "LightMode" = "ShadowCaster" }
            
            ZWrite On ZTest LEqual ColorMask 0
            
            HLSLPROGRAM
            #pragma vertex ShadowPassVertex
            #pragma fragment ShadowPassFragment
            #include "Packages/com.unity.render-pipelines.universal/Shaders/ShadowCasterPass.hlsl"
            ENDHLSL
        }
        
        // Depth pass (required for depth-based effects)
        Pass
        {
            Name "DepthOnly"
            Tags { "LightMode" = "DepthOnly" }
            
            ZWrite On ColorMask R
            
            HLSLPROGRAM
            #pragma vertex DepthOnlyVertex
            #pragma fragment DepthOnlyFragment
            #include "Packages/com.unity.render-pipelines.universal/Shaders/DepthOnlyPass.hlsl"
            ENDHLSL
        }
    }
    
    Fallback "Universal Render Pipeline/Unlit"
}

TEMPLATE: URP LIT WITH MAIN LIGHT

Adds Lambert diffuse lighting from the main directional light:

Shader "Custom/URP_SimpleLit_Mobile"
{
    Properties
    {
        _BaseMap ("Base Map", 2D) = "white" {}
        _BaseColor ("Base Color", Color) = (1, 1, 1, 1)
    }
    
    SubShader
    {
        Tags
        {
            "RenderType" = "Opaque"
            "RenderPipeline" = "UniversalPipeline"
            "Queue" = "Geometry"
        }
        
        Pass
        {
            Name "ForwardLit"
            Tags { "LightMode" = "UniversalForward" }
            
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE
            #pragma multi_compile _ _SHADOWS_SOFT
            #pragma multi_compile_fog
            
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
            
            CBUFFER_START(UnityPerMaterial)
                float4 _BaseMap_ST;
                half4 _BaseColor;
            CBUFFER_END
            
            TEXTURE2D(_BaseMap);
            SAMPLER(sampler_BaseMap);
            
            struct Attributes
            {
                float4 positionOS : POSITION;
                float3 normalOS : NORMAL;
                float2 uv : TEXCOORD0;
            };
            
            struct Varyings
            {
                float4 positionCS : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 normalWS : TEXCOORD1;
                float3 positionWS : TEXCOORD2;
                half fogFactor : TEXCOORD3;
            };
            
            Varyings vert(Attributes input)
            {
                Varyings output;
                VertexPositionInputs posInputs = GetVertexPositionInputs(input.positionOS.xyz);
                VertexNormalInputs normInputs = GetVertexNormalInputs(input.normalOS);
                
                output.positionCS = posInputs.positionCS;
                output.positionWS = posInputs.positionWS;
                output.normalWS = normInputs.normalWS;
                output.uv = TRANSFORM_TEX(input.uv, _BaseMap);
                output.fogFactor = ComputeFogFactor(posInputs.positionCS.z);
                return output;
            }
            
            half4 frag(Varyings input) : SV_Target
            {
                half4 baseColor = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv) * _BaseColor;
                
                // Main light (directional)
                float4 shadowCoord = TransformWorldToShadowCoord(input.positionWS);
                Light mainLight = GetMainLight(shadowCoord);
                
                half3 normal = normalize(input.normalWS);
                half NdotL = saturate(dot(normal, mainLight.direction));
                half3 diffuse = baseColor.rgb * mainLight.color * NdotL * mainLight.shadowAttenuation;
                
                // Ambient
                half3 ambient = SampleSH(normal) * baseColor.rgb;
                
                half3 finalColor = diffuse + ambient;
                finalColor = MixFog(finalColor, input.fogFactor);
                
                return half4(finalColor, baseColor.a);
            }
            ENDHLSL
        }
        
        // Include ShadowCaster and DepthOnly passes (same as unlit template above)
        UsePass "Custom/URP_Unlit_Mobile/ShadowCaster"
        UsePass "Custom/URP_Unlit_Mobile/DepthOnly"
    }
    
    Fallback "Universal Render Pipeline/Simple Lit"
}

BUILT-IN → URP CONVERSION CHEAT SHEET

Built-inURP Equivalent
#include "UnityCG.cginc"#include ".../Core.hlsl"
#include "Lighting.cginc"#include ".../Lighting.hlsl"
UnityObjectToClipPos(v)TransformObjectToHClip(v.xyz)
UnityObjectToWorldNormal(n)TransformObjectToWorldNormal(n)
_WorldSpaceLightPos0GetMainLight().direction
_LightColor0GetMainLight().color
UNITY_LIGHTMODEL_AMBIENTSampleSH(normal)
SHADOW_COORDS / TRANSFER_SHADOWTransformWorldToShadowCoord(posWS)
SHADOW_ATTENUATION(i)GetMainLight(shadowCoord).shadowAttenuation
tex2D(_Tex, uv)SAMPLE_TEXTURE2D(_Tex, sampler_Tex, uv)
sampler2D _TexTEXTURE2D(_Tex); SAMPLER(sampler_Tex);
UNITY_FOG_COORDS / APPLY_FOGComputeFogFactor() / MixFog()
v2f struct conventionVaryings struct convention
appdata struct conventionAttributes struct convention
Tags { "LightMode" = "ForwardBase" }Tags { "LightMode" = "UniversalForward" }
Surface shader #pragma surfaceNo equivalent — write vertex/fragment manually

MULTI-PASS AND ADDITIONAL PASSES

URP requires explicit pass names for the renderer to recognize them:

LightMode TagPurpose
UniversalForwardMain rendering pass
ShadowCasterShadow map generation
DepthOnlyDepth prepass
DepthNormalsDepth + normals prepass (for SSAO, depth-normals effects)
MetaLightmap baking
Universal2D2D renderer pass
SRPDefaultUnlitFallback when no LightMode matches

COMMON PITFALLS

  1. Forgetting CBUFFER → Breaks SRP Batcher. Every draw call becomes unique. Check with Frame Debugger > SRP Batcher column.

  2. Using sampler2D instead of TEXTURE2D macro → Works but loses cross-platform sampler control and may break on some platforms.

  3. Missing ShadowCaster pass → Object won't cast shadows. Always include it or use UsePass/Fallback.

  4. Missing DepthOnly pass → Depth-based effects (fog, post-processing, water depth) won't see this object.

  5. Using multi_compile instead of shader_featuremulti_compile compiles ALL keyword variants. shader_feature only compiles variants used by materials in the build. For material-specific toggles, always use shader_feature.


REFERENCE REPOS AND GISTS

SOURCES

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.