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:
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:
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-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).
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.)
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-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-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:
// 1. Traditional Alpha Blending (Transparent Materials)
Blend SrcAlpha OneMinusSrcAlpha
// 2. Additive Blending (Fire, Lasers)
Blend One One
// 3. Multiplicative Blending (Projectors, Shadows)
Blend DstColor ZeroOption 1: Hardcode in the shader
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
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
SubShader {
Tags { "Queue"="Transparent" }
Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off // Disable depth writes for correct transparency
}URP (2024)
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.
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
}
}
}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 addingAlphaToMask Onin 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.
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 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.
