01 SubShader Setup in ShaderLab

Every shader must include at least one SubShader. In the SubShader, you define one or more passes (each of which contains your actual shader code) and specify metadata that informs Unity how and when to use that SubShader. This setup is crucial because Unity selects the most compatible SubShader based on your target hardware and active render pipeline.

Basic Structure Example:

GLSL · For Built-in RP, you might see CGPROGRAM/ENDCG,
SubShader {
    Tags { "RenderType" = "Opaque" }
    LOD 100

    Pass {
        // For Built-in RP, you might see CGPROGRAM/ENDCG,
        // while URP/HDRP typically use HLSLPROGRAM/ENDHLSL.
        CGPROGRAM
            // Compiler directives and shader code go here...
        ENDCG
    }
}

Subshader Tags

Tags are key–value pairs that provide essential metadata for a SubShader. They affect shader behavior, drawing order, and how the shader interacts with replacement systems or post-processing. Below is an overview of the main tags and their pipeline-specific nuances.

ShaderLab Queue Tags

Queue tags determine the order in which objects are drawn by the GPU. The render queue affects layering, transparency, and masking. The GPU sorts draw calls by these numerical values:

GLSL · ShaderLab Queue Tags
Tags { "Queue" = "Geometry" }
  • Background:
    This render queue is rendered before any others. You’d typically use this for things that really need to be in the background.
    Range: 0–1499 (default 1000)
  • Geometry:
    For opaque objects; the default for most shaders.
    Range: 1500–2399 (default 2000)
  • AlphaTest:
    Suitable for objects with cutout transparency (e.g., foliage, vegetation) that need to be rendered after opaque objects.
    Range: 2400–2699 (default 2450)
  • Transparent:
    For transparent objects; drawn back-to-front.
    Range: 2700–3599 (default 3000)
  • Overlay:
    For UI or overlay elements rendered last.
    Range: 3600–5000 (default 4000)
[ PIPELINE EXECUTION: QUEUE ]

Pipeline-Specific Notes:
Built-in & URP: Queue tags are set directly in the shader and appear in the material Inspector.
HDRP (2024/2025): Queue tags can be overridden by Material Settings (Rendering Priority). To enforce draw order in HDRP, set the queue in the SubShader tags and adjust Material Order in the Inspector.

ShaderLab RenderType Tags

The RenderType tag categorizes shaders into logical groups for global replacements or post-processing. This tag helps Unity identify which shaders can be replaced at runtime (e.g., via Camera.RenderWithShader).

GLSL · ShaderLab RenderType Tags
Tags { "RenderType"="Opaque" }

Common RenderType Values:

  • Opaque:
    Default for most non-transparent materials. (Normal, Self Illuminated, Reflective, terrain shaders)
  • Transparent:
    Used for shaders with blending, such as glass or particles. (Transparent, Particle, Font, terrain additive pass shaders).
  • TransparentCutout:
    For materials that use alpha testing (masked transparency , Transparent Cutout, two pass vegetation shaders).
  • Background:
    For skyboxes and distant scenery.
  • Overlay:
    For UI and similar overlay elements. (GUITexture, Halo, Flare shaders.)
[ PIPELINE EXECUTION: RENDERTYPE ]

Built-in & URP: Directly specified and visible.
HDRP: Although still used, HDRP may manage some transparency or advanced effects via additional material settings.

Specialized Tags

Beyond Queue and RenderType, several other tags refine shader behavior:

  • TreeOpaque: Used for opaque tree bark.
  • TreeTransparentCutout: Used for tree leaves that use alpha cutout.
  • TreeBillboard: Used for trees rendered as billboards.
  • Grass: For full 3D grass models.
  • GrassBillboard: For grass rendered as billboards to improve performance.

Additional Tags

Beyond Queue and RenderType, several other tags refine shader behavior:

  • RequireOptions:
    Ensures a pass is rendered only if specific quality settings (e.g., SoftVegetation) are enabled.
  • DisableBatching:
    Controls whether dynamic batching is allowed (values: True, False, LODFading).
  • ForceNoShadowCasting:
    Prevents the shader from casting shadows. (Note: In HDRP, this does not prevent contact shadows.)
    GLSL · Implementation example
    Tags { "ForceNoShadowCasting" = "True" }
  • IgnoreProjector:
    Excludes the shader from being affected by projectors. (Built-in only) Tells Unity to ignore projectors when rendering this geometry.
  • CanUseSpriteAtlas:
    Indicates that the shader supports batching through a Sprite Atlas.
  • PreviewType:
    Specifies how the shader should be previewed in the editor (e.g., Sphere, Plane, Skybox).
  • GrabPass:
    Captures current screen contents into a texture will grab current screen contents into a texture. The texture can be accessed in further passes by _GrabTexture name. Note: this form of grab pass will do the expensive screen grabbing operation for each object that uses it! GrabPass { "TextureName" } will grab screen contents into a texture, but will only do that once per frame for the first object that uses the given texture name. The texture can be accessed in further passes by the given texture name. This is a more performant way when you have multiple objects using grab pass in the scene. Additionally, GrabPass can use Name and Tags commands.
    GLSL · Implementation example
    GrabPass { "TextureName" }
  • UsePass:
    Reuses passes from another shade. Inserts all passes with a given name from a given shader. Shader/Name contains the name of the shader and the name of the pass, separated by a slash character. Note that only first supported subshader is taken into account.
    GLSL · Implementation example
    UsePass "Shader/PassName"

Usage: RenderType tags help with shader replacement systems (e.g., using Camera.RenderWithShader) and enable filtering when applying post-processing effects.

[ PIPELINE SELECTION: ADVANCED TAGS ]

Pipeline-Specific Notes:
Built-in & URP: RenderType tags work as defined and help organize shader behavior.
HDRP: Although available, HDRP’s advanced material system often uses additional parameters to control transparency and rendering effects.

(Works only with URP/Built-in RP) Tags are labels that show how and when our shaders are processed. Like a GameObject Tag, these can be used to recognize how a shader will be rendered or how a group of shaders will behave graphically.

02 ShaderLab Blending Modes

Blending is the cornerstone of creating visually rich materials like glass, fire, smoke, and holograms. Let’s break down this critical stage in the rendering pipeline.

Blending combines the fragment shader’s output color (SrcValue) with the color already in the render target (DstValue). Think of it as layering in Photoshop—but in real-time 3D. This “merging” stage occurs after the fragment shader and is responsible for incorporating transparency, depth, and stencil data into the final pixel color.

Blending options can be written in different fields: within the SubShader field or the Pass field, the position will depend on the number of passes and the final result that we need.

  • Default Behavior: When blending is disabled (default: Blend Off), Source color overwrites the destination (no transparency).
  • Activating Blending: Enable blending + set "Queue"="Transparent" to render after opaque objects.

Blending combines fragment shader output (SrcValue) with the existing render target color (DstValue) using the equation:

FinalColor = SrcFactor * SrcValue [OP] DstFactor * DstValue

Default operation ([OP]) is Add, making the typical equation:

FinalColor = SrcFactor * SrcValue + DstFactor * DstValue

Blend Factors Cheat Sheet

Factor RGB Value Use Case
One (1,1,1) Full color contribution (e.g., additive glow).
SrcAlpha (A,A,A) Standard transparency (UI, glass).
OneMinusSrcAlpha (1-A,1-A,1-A) Inverse alpha masking (soft particles).
DstColor (R,G,B) Multiplicative effects (stained glass).

Numerical Example

Let’s say we have an RGB pixel with the following destination values:
DstValue = [0.5R, 0.45G, 0.35B]

  • Step 1: Multiply DstValue by SrcFactor One (which is [1, 1, 1]):
    Result: [0.5R, 0.45G, 0.35B]
  • Step 2: Assume the DstFactor also equals the current DstValue ([0.5, 0.45, 0.35]). Multiply each component:
    Calculation:
    R: $$0.5 \times 0.5 = 0.25$$
    G: $$0.45 \times 0.45 \approx 0.20$$
    B: $$0.35 \times 0.35 \approx 0.12$$
    Result: [0.25R, 0.20G, 0.12B]
  • Step 3: Add the two results (using Add as [OP]):
    Calculation:
    R: $$0.5 + 0.25 = 0.75$$
    G: $$0.45 + 0.20 = 0.65$$
    B: $$0.35 + 0.12 \approx 0.47$$
    Final Result: [0.75R, 0.65G, 0.47B]

Common Blend Factors

Some frequently used blend factors include:

  • Off: Disables blending.
  • One: (1, 1, 1) – Leaves the value unchanged.
  • Zero: (0, 0, 0) – Eliminates the value.
  • SrcColor / SrcAlpha: Uses the corresponding components from the source.
  • OneMinusSrcColor / OneMinusSrcAlpha: Uses (1 - source component) values.
  • DstColor / DstAlpha: Uses the destination color or alpha.
  • OneMinusDstColor / OneMinusDstAlpha: Uses (1 - destination component) values.

To use blending in your shader, you'll need to modify the “Queue” tag—by default, it’s set to “Geometry” (making the object opaque). Change it to “Transparent” to indicate that the object should be rendered after opaque objects and blended accordingly.

Blend presets provide standard configurations for frequently used blending effects. The table below outlines these presets, the associated Blend command, and a brief description of their typical usage.

Blend Presets

Blend Preset Blend Command Description
Traditional Alpha Blending Blend SrcAlpha OneMinusSrcAlpha The classic method for transparent materials, where the source’s alpha determines transparency.
Additive Blending Blend One One Often used for particles or glow effects, as it adds color values, making bright effects stand out.
Mild Additive Blending Blend OneMinusDstColor One A softer additive effect where the influence of the destination color is partially accounted for.
Multiplicative Blending Blend DstColor Zero Multiplies the source with the destination, useful for effects like stained glass.
Multiplicative Blending x2 Blend DstColor SrcColor An intensified version of multiplicative blending, doubling the effect for richer colors.
Overlay Blending Blend SrcColor One Uses the source color as the dominant factor, creating an overlay effect.
Soft Light Blending Blend OneMinusSrcColor One Produces a soft lighting effect, ideal for subtle highlights and shadows.
Negative Color Blending Blend Zero OneMinusSrcColor Creates a negative color effect by inverting the source color’s contribution.
[ PIPELINE INTEGRITY: BLENDING ]

Pipeline-Specific Notes on Blending:
Built-in Render Pipeline: Blending commands are written directly in the shader. Depth writes (ZWrite) are typically disabled for transparent materials.
URP (2024): You can set blend factors in the shader; however, URP’s material system may also allow artists to adjust these settings via the Inspector. Use HLSLPROGRAM/ENDHLSL blocks in URP shaders.
HDRP: Blending is often managed indirectly via material settings—especially for transparency. In HDRP, you might not see explicit Blend commands in the shader code because transparency is handled through the Surface Type setting (Opaque vs. Transparent) in the material Inspector.

Common Blend Presets quick reference:

GLSL · 1. Traditional Alpha Blending (Transparent Materials)
// 1. Traditional Alpha Blending (Transparent Materials)
Blend SrcAlpha OneMinusSrcAlpha

// 2. Additive Blending (Fire, Lasers)
Blend One One

// 3. Multiplicative Blending (Projectors, Shadows)
Blend DstColor Zero

Option 1: Hardcode in the shader

GLSL · Shader code here...
SubShader {
    Tags { "Queue" = "Transparent" }
    Blend SrcAlpha OneMinusSrcAlpha
    ZWrite Off // Disable depth writes for proper transparency
    Pass {
        // Shader code here...
    }
}

Option 2: Let artists control blending via the Material Inspector

GLSL · Shader code here...
Properties {
    [Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend ("Src Factor", Float) = 1
    [Enum(UnityEngine.Rendering.BlendMode)] _DstBlend ("Dst Factor", Float) = 0
}
SubShader {
    Blend [_SrcBlend] [_DstBlend]
    Pass {
        // Shader code here...
    }
}

Pipeline-specific architectural blocks comparison:

Built-in Render Pipeline

GLSL · Blend Presets
SubShader {
    Tags { "Queue"="Transparent" }
    Blend SrcAlpha OneMinusSrcAlpha
    ZWrite Off  // Disable depth writes for correct transparency
}

URP (2024)

GLSL · Blend Presets
SubShader {
    Tags { "RenderPipeline"="UniversalPipeline" "Queue"="Transparent" }
    Blend [_SrcBlend] [_DstBlend]
    ZWrite Off
}

Troubleshooting Blending

Issue Fix
HDRP Transparency Not Working Set Surface Type → Transparent in Material Inspector.
URP Additive Artifacts Adjust render queue: Tags { "Queue"="Transparent+100" }.
Depth Sorting Issues Use Offset -1, -1 to manually adjust depth in Built-in Pipeline.

03 ShaderLab AlphaToMask

In some cases, standard blending (such as using the "SrcAlpha OneMinusSrcAlpha" blend mode) produces smooth gradients of transparency using fractional alpha values. However, for certain effects—like vegetation cutouts or space portal effects—you might require a binary (on/off) approach to transparency. This is where AlphaToMask comes into play.

How AlphaToMask Works

  • Purpose: AlphaToMask forces the shader to treat the alpha channel as a binary mask rather than a continuous gradient. That means the alpha output can only be 0 or 1 (off or on), producing a harsher, more defined transparency edge.
  • Usage: This technique is particularly useful when you need crisp, hard-edged transparency (for example, for foliage or portal effects) that blending cannot provide.
  • Declaration: The command accepts only two values: On or Off (with the default being Off). It can be declared at either the SubShader or Pass level. When enabled, the shader automatically converts the alpha output to a binary mask.
GLSL · Define your texture and other properties here
Shader "Custom/AlphaToMaskExample" {
    Properties {
        // Define your texture and other properties here
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader {
        Tags { "RenderType" = "Opaque" }
        // Activate the AlphaToMask command
        AlphaToMask On

        Pass {
            // Shader code that writes to the alpha channel
            CGPROGRAM
                // Your shader code here...
            ENDCG
        }
    }
}
[ MASK CHANNELS SPECIFICATION ]

Note: Unlike blending, you don't need to modify the Render Queue or add additional transparency tags when using AlphaToMask. The fourth color channel “A” is automatically treated as a binary mask.

Pipeline-Specific Considerations for AlphaToMask

  • General Behavior:
    AlphaToMask forces the shader’s alpha channel to be treated as a binary mask (0 or 1) rather than allowing smooth gradients. This produces hard-edged transparency effects, which are ideal for vegetation, portals, or any scenario where crisp cutouts are needed.
  • Built-in Render Pipeline:
    Works as expected when enabled. Simply adding AlphaToMask On in the SubShader or Pass converts the alpha output into a binary mask without any further changes.
  • URP (2024/2025):
    In URP, AlphaToMask is fully supported. Just as in the Built-in pipeline, you declare it (preferably within an HLSLPROGRAM block for full compatibility), and it forces the alpha channel into a binary state. No additional transparency tags are needed.
  • HDRP (2024/2025):
    HDRP primarily manages transparency via material settings (like the Surface Type property). Although HDRP often relies on these high-level controls for transparency, AlphaToMask remains available for cases where a hard, masked transparency is required. The command works the same way as in other pipelines, but you might see it used less often because HDRP typically employs its own transparency workflow.

04 ShaderLab ColorMask

The ColorMask command allows you to restrict the GPU to writing only specific color channels (Red, Green, Blue, or Alpha). By default, the GPU writes all channels (RGBA), but you might want to limit the output for certain effects or optimizations.

How ColorMask Works

Purpose: ColorMask lets you select which components of the output color should be written to the render target. This is useful, for example, if you want to create a red-only effect or isolate one channel for debugging.

Usage Examples:

  • ColorMask R: Only the red channel is written, so the output appears red.
  • ColorMask G: Only the green channel is written.
  • ColorMask B: Only the blue channel is written.
  • ColorMask A: Only the alpha channel is written, which can be used to debug transparency.
  • ColorMask RG: Writes both red and green channels, allowing for channel mixing.
GLSL · Limit output to the RGB channels (no alpha)
Shader "Custom/ColorMaskExample" {
    Properties {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader {
        Tags { "Queue"="Geometry" }
        // Limit output to the RGB channels (no alpha)
        ColorMask RGB

        Pass {
            CGPROGRAM
                // Your shader code here...
            ENDCG
        }
    }
}
[ PIPELINE INTEGRITY: COLOR MASK ]

Pipeline Note: The ColorMask command is compatible with both the Built-in Render Pipeline and Scriptable Render Pipelines (URP/HDRP). You can declare it at either the SubShader or Pass level, depending on the desired scope.

Pipeline-Specific Considerations for ColorMask

  • General Behavior:
    The ColorMask command restricts the GPU to writing only specific color channels (R, G, B, and/or A). By default, all channels (RGBA) are written, but you can limit this to isolate or blend specific outputs (e.g., output only the red channel).
  • Built-in Render Pipeline:
    ColorMask works identically to how it’s defined in ShaderLab—its syntax and function are the same. It’s commonly used for effects like channel isolation or performance optimizations.
  • URP (2024/2025):
    URP supports ColorMask without any changes. When writing custom shaders using HLSLPROGRAM blocks, you can still use ColorMask in the SubShader or Pass as usual. Artists can also control these settings via the material’s inspector if exposed.
  • HDRP (2024/2025):
    HDRP fully supports ColorMask as well. However, HDRP’s advanced color management (including HDR tonemapping and color space conversion) means that if you’re isolating channels or mixing them, you may need to ensure that your shader’s color values are correctly tagged (e.g., using the [HDR] attribute) so that the final output appears as expected.
// END OF PART // UNITY_SHADERLAB // EOF
[SHARE]