Skip to content

Custom ShaderLab and URP HLSL

↑

ShaderLab declares the Shader, Properties, SubShader and Pass structure. HLSL functions perform the actual vertex and fragment calculations. URP shaders generally need URP shader tags and URP library includes; a Built-In Surface Shader example is not a valid URP replacement.

The example below is an unlit URP pass. It uses the object-to-clip-space transform and returns one configured color. It does not calculate lights, shadows or textures, which keeps the initial learning example focused.

HCSTechUnlit.shader
Shader "HCSTech/UnlitColor"
{
Properties { _BaseColor ("Base Color", Color) = (0.2, 0.8, 0.5, 1) }
SubShader
{
Tags { "RenderPipeline" = "UniversalPipeline" "RenderType" = "Opaque" }
Pass
{
HLSLPROGRAM
#pragma vertex Vert
#pragma fragment Frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct Attributes { float4 positionOS : POSITION; };
struct Varyings { float4 positionCS : SV_POSITION; };
CBUFFER_START(UnityPerMaterial)
float4 _BaseColor;
CBUFFER_END
Varyings Vert(Attributes input)
{
Varyings output;
output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
return output;
}
half4 Frag(Varyings input) : SV_Target { return (half4)_BaseColor; }
ENDHLSL
}
}
}

Why the constant buffer? Keeping material properties in UnityPerMaterial follows the layout URP expects for SRP Batcher compatibility. More advanced shaders need proper pass tags and lighting includes. Pitfall: Test on your selected target platforms, not only in Scene view.

Try it: Create a Shader asset with this code, create a material and change _BaseColor. Compare it to a Lit URP shader.