Writing Shader Code for the Universal RP


Before we define the vertex or fragment shader functions we need to define some structs which are used to pass data in and out of them. In built-in they are usually named “appdata” and “v2f” (short for vertex to fragment) while URP shaders tend to use “Attributes” and “Varyings” instead. These are just names and likely aren’t too important though.

The URP ShaderLibrary also uses some structs to help organise data needed for certain functions – such as InputData and SurfaceData which are used in lighting/shading calculations, I’ll be going through them in the Lighting section.

Since this is a fairly simple Unlit shader our Attributes and Varyings won’t be all that complicated :

struct Attributes {
	float4 positionOS	: POSITION;
	float2 uv			: TEXCOORD0;
	float4 color		: COLOR;
// Don't forget these semi-colons at the end of each struct,
// or you'll get "Unexpected Token" errors

The Attributes struct will be the input to the vertex shader. It allows us to obtain the per-vertex data from the mesh, using the parts in capital letters which are known as semantics. This includes : vertex position (POSITION), vertex colour (COLOR) and the UVs (aka texture coordinates). A mesh has 8 different UV channels, which can be accessed through TEXCOORD0 to TEXCOORD7.

Note that, Mesh.uv is TEXCOORD0. There is no Mesh.uv1. The next channel is Mesh.uv2, which corresponds to TEXCOORD1, and so on up to Mesh.uv8 and TEXCOORD7.

We can also access vertex normals via NORMAL, and tangents via TANGENT. These aren’t usually used in Unlit shaders though.

struct Varyings {
	float4 positionCS	: SV_POSITION;
	float2 uv			: TEXCOORD0;
	float4 color		: COLOR;

The Varyings struct will be the output of the vertex shader and input to the fragment (assuming there’s no geometry shader in-between, which might need another struct, but we aren’t going through that in this post).

After the structs you’ll also commonly see the texture and sampler being defined – (as while the texture is in the shader properties it hasn’t been defined in hlsl yet. Other properties are included in the CBUFFER). In URP, we use the following :