Shader编写指南(十一):ShaderLab 通道(Pass)定义

在 ShaderLab 中,通道(Pass)是着色器对象的核心执行单元,负责定义一次完整的渲染流程,包括 GPU 状态设置(如混合模式、深度测试)和着色器程序(顶点 / 片元着色器)。每个子着色器(SubShader)可包含多个 Pass,用于实现复杂渲染效果(如多光源处理、阴影投射)。以下是 Pass 的核心概念、语法规则及跨管线实践:

一、Pass 的核心作用
  1. 渲染状态控制

    • 配置 GPU 状态(如 Blend SrcAlpha OneMinusSrcAlpha 透明混合、Cull Off 关闭背面剔除)。
    • 示例:透明物体需开启混合并调整渲染队列,阴影投射 Pass 需禁用颜色输出仅写入深度。
  2. 着色器程序载体

    • 包含顶点着色器(Vertex Shader)和片元着色器(Fragment Shader)代码,实现坐标变换、光照计算等核心逻辑。
    • 支持 GLSL、HLSL 等着色语言,通过CGPROGRAM/ENDCG块嵌入 HLSL 代码(内置管线 / URP/HDRP)。
  3. 多 Pass 渲染

    • 单个 SubShader 通过多个 Pass 实现多重渲染(如先渲染主颜色,再叠加高光或环境光)。
    • 示例:正向渲染中,主光源 Pass(LightMode="ForwardBase")与附加光源 Pass(LightMode="ForwardAdd")分离。
二、Pass 的语法与结构

hlsl

Pass {  
    // 可选:Pass名称(用于被其他着色器引用)  
    Name "PassName"  
    // 可选:标签(控制光照模式、渲染顺序等)  
    Tags { "LightMode"="ForwardBase" }  
    // 可选:渲染状态指令  
    ZTest LEqual  
    Blend One One  
    // 可选:着色器代码块  
    CGPROGRAM  
    #pragma vertex vert  
    #pragma fragment frag  
    #include "UnityCG.cginc"  
    // 顶点/片元着色器函数  
    ENDCG  
}  
三、关键组件详解
1. 标签(Tags)

Pass 标签用于控制渲染流程,核心标签包括:

标签作用典型值
LightMode定义光照模式(内置管线 / URP/HDRP)ForwardBase(主光源)、ShadowCaster(阴影投射)
RenderType配合 SubShader 标签实现着色器替换(如渲染深度纹理)OpaqueTransparentCutout
Queue覆盖 SubShader 的渲染队列(较少使用,优先在 SubShader 层级设置)Transparent+1

URP/HDRP 光照模式示例

hlsl

// URP 正向渲染主光源  
Tags { "LightMode"="UniversalForward" }  
// HDRP 体积渲染  
Tags { "LightMode"="HDRenderPipeline" }  
2. 渲染状态指令

直接在 Pass 中设置 GPU 状态,常见指令:

  • 深度与模板缓冲

    hlsl

    ZWrite On       // 开启深度写入  
    ZTest LessEqual // 深度测试:当前片元深度小于等于缓冲深度时通过  
    Stencil { Ref 1 ZFail Keep } // 模板测试  
    
  • 混合模式

    hlsl

    Blend SrcAlpha OneMinusSrcAlpha // 透明混合  
    Blend One One // 相加混合(如粒子发光)  
    
  • 剔除与面渲染

    hlsl

    Cull Back    // 剔除背面(默认)  
    Cull Front   // 剔除正面  
    Cull Off     // 渲染双面  
    
3. 着色器代码块

通过CGPROGRAM/ENDCG嵌入 HLSL 代码,需声明顶点 / 片元着色器入口:

hlsl

CGPROGRAM  
#pragma vertex vert   // 顶点着色器函数名  
#pragma fragment frag // 片元着色器函数名  
#include "UnityCG.cginc"  // 引用Unity内置函数库  
// 顶点输入结构(对应模型顶点数据)  
struct appdata {  
    float4 vertex : POSITION;  
    float2 uv : TEXCOORD0;  
};  
// 顶点输出结构(传递给片元着色器)  
struct v2f {  
    float2 uv : TEXCOORD0;  
    float4 pos : SV_POSITION;  
};  
// 顶点着色器:坐标转换  
v2f vert (appdata v) {  
    v2f o;  
    o.pos = UnityObjectToClipPos(v.vertex); // 模型空间→裁剪空间  
    o.uv = v.uv;  
    return o;  
}  
// 片元着色器:纹理采样  
fixed4 frag (v2f i) : SV_TARGET {  
    fixed4 col = tex2D(_MainTex, i.uv);  
    return col;  
}  
ENDCG  
4. 特殊 Pass 类型
  • UsePass:引用其他着色器的 Pass,避免重复代码:

    hlsl

    UsePass "ExampleShader/ShadowCasting" // 引用名为ShadowCasting的Pass  
    
  • GrabPass:抓取屏幕图像到纹理,用于反射 / 折射效果(内置管线常用,URP/HDRP 建议使用 RenderTexture 替代):

    hlsl

    GrabPass { "GrabTex" } // 抓取结果存储到名为GrabTex的纹理  
    
四、跨渲染管线的 Pass 设计
1. 内置管线(Built-in RP)
  • 特点:支持传统光照模式(Forward/Deferred),Pass 需明确声明LightMode标签。
  • 示例:正向渲染主光源 Pass

    hlsl

    Pass {  
        Tags { "LightMode"="ForwardBase" }  
        CGPROGRAM  
        #pragma multi_compile_fwdbase // 主光源编译变体  
        // 包含光照计算代码  
        ENDCG  
    }  
    
2. 通用渲染管线(URP)
  • 特点:轻量级,使用UniversalForward等标签,需引用 URP HLSL 库。
  • 示例:URP 不透明物体 Pass

    hlsl

    Pass {  
        Tags { "LightMode"="UniversalForward" }  
        HLSLPROGRAM  
        #pragma vertex vert  
        #pragma fragment frag  
        #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"  
        // 使用URP光照函数 UniversalForwardLighting()  
        ENDCG  
    }  
    
3. 高清渲染管线(HDRP)
  • 特点:支持高级渲染,Pass 需匹配 HDRP 光照模式,使用集群光照等特性。
  • 示例:HDRP 体积雾 Pass

    hlsl

    Pass {  
        Tags { "LightMode"="HDRenderPipeline" }  
        HLSLPROGRAM  
        #include "Packages/com.unity.render-pipelines.high-definition/ShaderLibrary/Volumetric.hlsl"  
        // 体积雾计算逻辑  
        ENDCG  
    }  
    
4. 自定义 SRP
  • 策略:通过标签匹配自定义管线的渲染逻辑,例如:

    hlsl

    Pass {  
        Tags { "CustomSRP"="MyPipeline" }  
        // 自定义管线专属渲染指令  
    }  
    
五、Pass 的性能优化
  1. 减少 Pass 数量

    • 合并渲染状态相同的 Pass,使用MultiCompile生成变体而非多个独立 Pass。
    • 示例:通过#pragma multi_compile _ USE_SPECULAR 控制是否包含高光计算,避免拆分 Pass。
  2. 状态复用

    • 相邻 Pass 尽量复用渲染状态(如相同的混合模式、深度设置),减少 GPU 状态切换开销。
  3. 管线适配优化

    • URP:避免使用GrabPass,改用ScriptableRenderContext抓取屏幕。
    • HDRP:利用 GPU 实例化(GPU Instancing)减少多 Pass 渲染的 Draw Call 次数。
  4. 移动端优化

    • 避免复杂的多 Pass 渲染(如延迟渲染),优先使用单 Pass 完成光照计算。
    • 使用half精度变量(如half2 uv)替代float,减少寄存器占用。
六、调试与验证
  1. Pass 可视化

    • 在 Unity 编辑器中,通过 Frame Debugger 查看每个 Pass 的渲染结果,定位渲染顺序或状态错误。
    • 示例:检查阴影投射 Pass 是否正确写入深度缓冲。
  2. 编译错误处理

    • 着色器代码块需严格遵循 HLSL 语法,注意括号匹配和变量声明顺序。
    • 常见错误:未引用必要的头文件(如 URP 需#include "Core.hlsl")、标签拼写错误。
  3. 性能分析

    • 使用 Unity Profiler 查看Render.Pass耗时,识别瓶颈 Pass。
    • 移动端建议单 SubShader 的 Pass 数量不超过 3 个,PC / 主机可适当增加。
七、完整示例:多 Pass 着色器

hlsl

Shader "Example/MultiPassShader" {  
    Properties {  
        _MainTex ("基础纹理", 2D) = "white" {}  
        _GlowTex ("发光纹理", 2D) = "black" {}  
    }  
    SubShader {  
        Tags { "RenderType"="Opaque" }  
        LOD 200  
        // 主Pass:漫反射光照  
        Pass {  
            Name "BASE_PASS"  
            Tags { "LightMode"="ForwardBase" }  
            CGPROGRAM  
            #pragma vertex vert  
            #pragma fragment frag  
            #include "UnityCG.cginc"  
            sampler2D _MainTex;  
            float4 _MainTex_ST;  
            struct v2f {  
                float4 pos : SV_POSITION;  
                float2 uv : TEXCOORD0;  
            };  
            v2f vert (appdata_base v) {  
                v2f o;  
                o.pos = UnityObjectToClipPos(v.vertex);  
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);  
                return o;  
            }  
            fixed4 frag (v2f i) : SV_TARGET {  
                return tex2D(_MainTex, i.uv);  
            }  
            ENDCG  
        }  
        // 发光Pass:叠加自发光纹理(混合模式为相加)  
        Pass {  
            Name "GLOW_PASS"  
            Tags { "LightMode"="ForwardAdd" "Queue"="Transparent" }  
            Blend One One  
            CGPROGRAM  
            #pragma vertex vert  
            #pragma fragment frag  
            #include "UnityCG.cginc"  
            sampler2D _GlowTex;  
            float4 _GlowTex_ST;  
            struct v2f {  
                float4 pos : SV_POSITION;  
                float2 uv : TEXCOORD0;  
            };  
            v2f vert (appdata_base v) {  
                v2f o;  
                o.pos = UnityObjectToClipPos(v.vertex);  
                o.uv = TRANSFORM_TEX(v.uv, _GlowTex);  
                return o;  
            }  
            fixed4 frag (v2f i) : SV_TARGET {  
                return tex2D(_GlowTex, i.uv);  
            }  
            ENDCG  
        }  
    }  
    Fallback "Diffuse"  
}  
八、注意事项
  1. 标签作用域

    • Pass 标签仅影响当前 Pass,不继承 SubShader 标签(如 SubShader 设置Queue=Geometry,Pass 可通过Queue=Transparent覆盖)。
  2. 材质参数共享

    • 多个 Pass 间共享材质属性(如_MainTex)时,需确保 HLSL 变量名一致,且在每个 Pass 中正确声明。
  3. 管线兼容性测试

    • 跨管线项目需为每个 Pass 添加条件编译(如#if UNITY_URP),避免不同管线的语法冲突。

总结

Pass 是 ShaderLab 实现复杂渲染效果的基础,通过合理设计 Pass 的渲染状态、着色器逻辑和多 Pass 组合,可在不同渲染管线和硬件上实现高效渲染。在实践中,需结合项目的管线类型和性能目标,优化 Pass 数量与状态切换,并利用 Unity 的调试工具确保每个 Pass 按预期执行。掌握 Pass 的定义规则,是开发高性能着色器和复杂视觉效果的关键。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小李也疯狂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值