在 ShaderLab 中,命令(Commands)用于控制 GPU 渲染状态、定义特殊用途的 Pass 或实现传统固定功能着色器逻辑。这些命令是构建着色器渲染流程的核心,可分为渲染状态设置、Pass 定义和传统固定功能三类。以下是核心命令的详解及实践示例:
一、渲染状态设置命令
此类命令用于配置 GPU 的渲染状态(如混合模式、深度测试、模板缓冲等),可作用于单个 Pass 或整个 SubShader。
1. 混合(Blend)
- 作用:启用 alpha 混合,控制源颜色与目标颜色的混合方式。
- 语法:
hlsl
Blend [源混合因子] [目标混合因子] BlendOp [混合操作] // 可选,设置混合后的颜色操作(如Add、Subtract)
- 示例:
hlsl
Blend SrcAlpha OneMinusSrcAlpha // 标准透明混合(如玻璃、UI) Blend One One // 相加混合(如粒子发光) BlendOp Min // 取最小值混合
2. 深度测试与写入(ZTest / ZWrite)
- ZTest:设置深度测试条件(如当前片元深度是否通过测试)。
hlsl
ZTest LessEqual // 仅当片元深度≤缓冲区深度时通过(默认值) ZTest Always // 始终通过(用于UI覆盖)
- ZWrite:控制是否写入深度缓冲。
hlsl
ZWrite On // 启用深度写入(不透明物体默认) ZWrite Off // 禁用深度写入(透明物体常用)
3. 模板测试(Stencil)
- 作用:通过模板缓冲实现复杂遮挡或特效(如贴花、轮廓渲染)。
- 语法:
hlsl
Stencil { Ref [参考值] // 用于比较的参考值 Comp [比较函数] // 如Equal、NotEqual Pass [通过时操作] // 如Replace、Keep Fail [失败时操作] }
- 示例:仅渲染模板值为 1 的区域:
hlsl
Stencil { Ref 1 Comp Equal Pass Keep }
4. 剔除模式(Cull)
- 作用:控制渲染正面 / 背面三角形,优化性能。
- 取值:
hlsl
Cull Back // 剔除背面(默认,适用于闭合网格) Cull Front // 剔除正面 Cull Off // 渲染双面(如薄片物体、透明布料)
5. 深度偏移(Offset)
- 作用:解决深度缓冲冲突(Z-Fighting),通过偏移值调整片元深度。
- 语法:
hlsl
Offset [深度系数] [深度 bias]
- 示例:
hlsl
Offset 1, 1 // 增加深度值,确保物体在其他物体前方渲染
二、Pass 定义命令
用于创建特殊用途的 Pass,简化常见渲染流程。
1. UsePass:引用其他着色器的 Pass
- 作用:复用其他着色器中的 Pass 代码,避免重复编写(如阴影投射 Pass)。
- 语法:
hlsl
UsePass "ShaderName/PassName"
- 注意:
- 名称需为全大写(如原 Pass 名为 "ShadowCaster",引用时写作 "SHADOWCASTER")。
- 示例:引用内置着色器的阴影投射 Pass:
hlsl
UsePass "Legacy Shaders/VertexLit/SHADOWCASTER"
2. GrabPass:抓取屏幕内容
- 作用:将当前屏幕图像抓取到纹理中,用于反射、折射等效果(内置管线常用)。
- 语法:
hlsl
GrabPass [纹理名称] // 可选,指定纹理名称,默认名为"_GrabTexture"
- 示例:
hlsl
GrabPass "CustomGrabTex" // 在片元着色器中使用该纹理: float4 frag(v2f i) : SV_TARGET { float4 screen = tex2Dlod(_CustomGrabTex, float4(i.uv, 0, 0)); return screen * _TintColor; }
三、传统固定功能命令(Legacy)
适用于无需编写 HLSL 的简单着色器,仅支持内置管线,不推荐用于现代项目。
1. 颜色与纹理设置
- Color:设置固定颜色。
hlsl
Color (1, 0.5, 0, 1) // 橙色
- SetTexture:设置纹理采样状态。
hlsl
SetTexture [_MainTex] { Combine texture * primary // 纹理与固定颜色相乘 }
2. 光照模型
- Lighting:启用 / 禁用光照。
hlsl
Lighting On // 启用光照(默认) Lighting Off // 禁用光照(如自发光材质)
- Material:定义材质属性(漫反射、高光等)。
hlsl
Material { Diffuse (1, 1, 1, 1) // 漫反射颜色 Shininess 0.5 // 光泽度 Specular (1, 1, 1, 1) // 高光颜色 }
四、命令作用域与优先级
-
SubShader 级 vs Pass 级:
- SubShader 级命令:作用于该 SubShader 的所有 Pass(如
Cull Back
)。 - Pass 级命令:仅作用于当前 Pass,覆盖 SubShader 级设置(如 Pass 中
Cull Off
会覆盖 SubShader 的Cull Back
)。
- SubShader 级命令:作用于该 SubShader 的所有 Pass(如
-
执行顺序:
- 渲染状态命令需在 HLSL 代码块前声明(如
Blend
需在CGPROGRAM
之前)。
hlsl
Pass { Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM // 着色器代码 ENDCG }
- 渲染状态命令需在 HLSL 代码块前声明(如
五、跨渲染管线注意事项
-
URP/HDRP 限制:
- 传统固定功能命令(如
Color
、SetTexture
)在 URP/HDRP 中无效,需使用 HLSL 实现。 GrabPass
在 URP/HDRP 中性能较低,建议使用ScriptableRenderContext
或 RenderTexture 替代。
- 传统固定功能命令(如
-
SRP 兼容性:
- 自定义 SRP 中,部分命令(如
ZTest
)需配合管线的渲染设置使用,可能需通过代码动态配置。
- 自定义 SRP 中,部分命令(如
六、完整示例:透明物体渲染
hlsl
Shader "Example/TransparentShader" {
Properties {
_MainTex ("基础纹理", 2D) = "white" {}
_TintColor ("颜色", Color) = (1, 1, 1, 1)
}
SubShader {
Tags { "RenderType"="Transparent" "Queue"="Transparent" }
// SubShader级设置:关闭深度写入
ZWrite Off
Pass {
Tags { "LightMode"="UniversalForward" } // URP正向渲染
// Pass级设置:启用混合
Blend SrcAlpha OneMinusSrcAlpha
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
sampler2D _MainTex;
float4 _MainTex_ST;
float4 _TintColor;
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 = TransformObjectToHClip(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
float4 frag (v2f i) : SV_TARGET {
float4 tex = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv);
return tex * _TintColor;
}
ENDHLSL
}
}
}
七、性能优化建议
-
减少状态切换:
- 相邻 Pass 尽量复用相同的渲染状态(如相同的
Blend
、ZTest
),减少 GPU 状态切换开销。
- 相邻 Pass 尽量复用相同的渲染状态(如相同的
-
避免滥用 GrabPass:
- 屏幕抓取操作性能较高,URP/HDRP 中优先使用渲染纹理或管线内置功能(如 URP 的屏幕空间反射)。
-
现代管线优先使用 HLSL:
- 对复杂效果(如自定义光照模型),使用 HLSL 编程而非传统固定功能命令,以获得更好的性能和灵活性。
总结
ShaderLab 命令是控制渲染流程的底层工具,通过合理组合渲染状态命令和 Pass 定义命令,可实现从简单透明效果到复杂阴影系统的各种渲染逻辑。在实践中,需根据目标渲染管线选择合适的命令集,优先使用 HLSL 实现现代效果,并利用状态复用和管线特性优化性能。