Shader kinds and stages
A shader is a class marked with [Shader] that derives from one of three base classes. The base class decides what the shader does and which methods it has.
| Kind | Base class | What it does | Methods |
|---|---|---|---|
| Lit | ShaderScript.Lit |
Describes a surface that the render pipeline lights, like URP's and HDRP's Lit shaders. | Vert, Frag, optionally Displace (HDRP) |
| Unlit | ShaderScript.Unlit |
Outputs a final color, without lighting, like the Unlit shaders. | Vert, Frag |
| Fullscreen | ShaderScript.Fullscreen |
Processes the whole image, for post-processing effects. | Frag |
Derive directly from one of these classes: a shader can't derive from another shader class.
Stages
The GPU runs a shader in stages, and each stage is a method of the class.
Vert
public override void Vert(VertexInput IN, ref VertexOutput OUT)
Runs once for each vertex of the mesh. IN is the vertex as stored in the mesh; OUT is what goes on to the next stages. OUT starts as a copy of the vertex, so an empty Vert leaves the mesh as it is. Change OUT.positionOS to deform the mesh, for example to animate a flag or grass, and update OUT.normalOS along with it so that lighting follows the new shape. You can also compute values once per vertex and pass them to Frag. See Input and output data.
Frag
// Lit
public override void Frag(FragmentInput IN, ref LitFragmentOutput OUT)
// Unlit
public override void Frag(FragmentInput IN, ref UnlitFragmentOutput OUT)
// Fullscreen
public override void Frag(FullscreenInput IN, ref FullscreenOutput OUT)
Runs once for each pixel the object covers, or for a Fullscreen shader, once for each pixel of the screen. IN holds the data for the pixel. What Frag fills in depends on the kind:
- A Lit shader describes the surface at the pixel: its base color, normal, smoothness, metalness, emission and so on. The render pipeline does the lighting.
- An Unlit shader outputs the pixel's color and opacity.
- A Fullscreen shader outputs the pixel's color, usually computed from the image rendered so far.
Displace
public override void Displace(TessellationInput IN, ref TessellationOutput OUT)
Lit shaders only, HDRP only. When the shader has tessellation turned on with [Tessellation], the GPU subdivides the mesh into smaller triangles after Vert, and Displace runs for each new vertex, typically to move it along its normal by a height map. See HDRP features.
Passes
To render one object, a render pipeline draws it several times, each time for a different purpose: the color itself, depth, shadows, motion vectors, the lightmapper, the selection outline in the Scene view, and more. Each of these draws is a pass. Shader Script generates all the passes each render pipeline needs, and runs your Vert and Frag in each of them. A Lit shader has more passes than an Unlit one, and HDRP has more passes than URP.
You usually don't need to think about passes. When you do, for example to skip expensive work in a pass that doesn't need it, check CurrentPass:
public override void Frag(FragmentInput IN, ref LitFragmentOutput OUT)
{
float2 uv = IN.uv0;
float4 color = BaseMap.Sample(uv);
OUT.alpha = color.a;
// The shadow pass only needs the shape and opacity of the surface.
if (CurrentPass != ShaderPass.ShadowCaster)
{
OUT.albedo = (half3)color.rgb;
OUT.emission = ExpensiveGlow(uv);
}
}
CurrentPass is a compile-time constant: each pass is compiled separately, and the branches that don't apply to it are removed, so the check costs nothing. The main passes are:
| Pass | Purpose |
|---|---|
Forward |
Renders the object's color. |
GBuffer |
Writes the surface to the G-buffer in deferred rendering. Lit shaders only. |
DepthOnly |
Writes depth only, for the depth pre-pass. |
DepthNormals |
URP only: writes depth and normals, for effects such as screen space ambient occlusion. |
ShadowCaster |
Renders the object into shadow maps. |
MotionVectors |
Writes per-object motion, for temporal anti-aliasing and motion blur. |
Meta |
Gives the lightmapper the surface's color and emission for baked lighting. |
SceneSelection, Picking |
Selection outline and object picking in the Scene view. |
Fullscreen |
The single pass of a Fullscreen shader. |
HDRP adds more: transparent depth pre- and post-passes, back faces of transparent objects, distortion, the Rendering Debugger and the ray tracing passes. The ShaderPass enum lists all of them.