Multi-Pass Shader Writing

Sometimes, to render a complex effect, we need to perform multiple rendering passes within a single rendering loop. We can organize these related passes under the same SubShader for unified management. A Shader containing multiple passes is commonly referred to as a multi-pass shader.

As shown below, declare multiple passes required for rendering within a SubShader. The engine will render these passes in the order they are declared:

SubShader "SubShaderName" {
  ...
  // Global variable area: variable declarations, struct declarations, render state declarations
  ...
 
  Pass "Pass0" { ... }
  Pass "Pass1" { ... }
  Pass "Pass2" { ... }
 
  ...
}

UsePass

Developers can reuse shader passes using the UsePass directive: UsePass "{pass path}". The pass path format is {ShaderName/SubShaderName/PassName}. For example, if the following shader pass is declared:

Shader "water" {
  ...
  SubShader "Default" {
    ...
    Pass "0" {
      ...
    }
    ...
  }
  ...
}

Developers can reuse it in other custom shaders via UsePass "water/Default/0".

Additionally, the UsePass directive supports reusing built-in engine passes. Currently supported built-in passes include:

Built-in ShaderPass Path
PBRpbr/Default/Forward
Unlitunlit/Default/Forward
Skyboxskybox/Default/Forward
Particle-shaderparticle-shader/Default/Forward
SpriteMaskSpriteMask/Default/Forward
SpriteSprite/Default/Forward

The SubShader is not only used for organizing multiple passes but also supports setting Tags, which correspond to the engine's setTag API. For example, setting a ReplaceTag:

SubShader "SubShaderName" {
  ...
  Tags {ReplaceTag = "opaque"}
 
  Pass "PassName" {
    ...
  }
}

Was this page helpful?

On this page