在 ShaderLab 中,** 着色器对象(Shader Object)** 通过 Shader
块声明,用于组织着色器程序、材质属性和渲染逻辑。以下是其核心结构、语法规则及跨渲染管线的应用说明:
一、着色器对象的嵌套结构
着色器对象采用层级化结构,包含以下核心组件:
hlsl
Shader "着色器路径/名称" {
// 1. 材质属性(可选)
Properties { ... }
// 2. 子着色器(至少一个)
SubShader { ... }
// 3. 自定义编辑器(可选)
CustomEditor "自定义编辑器类名"
// 4. 回退着色器(可选)
Fallback "回退着色器路径"
}
- 层级关系:
Shader
→SubShader
→Pass
(每个 SubShader 包含一个或多个 Pass)。 - 渲染流程:
Unity 按顺序尝试每个 SubShader,直到找到硬件支持的版本,每个 SubShader 内的 Pass 依次执行渲染。
二、关键组件解析
1. 着色器名称与路径(Shader Name)
- 格式:
Shader "路径/名称"
(如Shader "URP/MyLitShader"
)。 - 作用:
- 决定材质在 Unity 编辑器中的分类路径(如 "Custom/Effects" 会显示在材质创建菜单的对应目录下)。
- 旧版着色器(Legacy Shaders)的功能由名称路径决定(如 "Transparent/Cutout" 启用 Alpha 裁剪)。
2. 属性块(Properties Block)
定义可在材质面板编辑的参数,语法为 属性名 ("显示名称", 类型) = 默认值
。
hlsl
Properties {
_MainTex ("基础纹理", 2D) = "white" {} // 二维纹理
_TintColor ("染色", Color) = (1,1,1,1) // 颜色
_Glossiness ("光泽度", Range(0,1)) = 0.5 // 浮点范围
_EmissionTex ("自发光纹理", 2D) = "black" {} // 带 Alpha 的纹理
}
- 参数类型:支持
Color
、2D
、Range
、Vector
等,参数值通过同名变量传递给 HLSL 代码。
3. 子着色器块(SubShader Block)
每个 SubShader 定义一组渲染指令,Unity 会根据硬件能力选择第一个支持的 SubShader。
hlsl
SubShader {
Tags { "RenderType"="Opaque" "Queue"="Geometry" } // 渲染标签
LOD 200 // 细节层级
Pass { ... } // 至少一个 Pass
// 可选:多个 Pass 或 UsePass 引用其他着色器的 Pass
}
- 核心标签(Tags):
RenderType
:定义渲染类型(如 "Opaque"、"Transparent"),影响渲染队列和后期处理。LightMode
:指定光照模式(如 "ForwardBase" 用于正向渲染主光源)。
- LOD(Level of Detail):当材质 LOD 等级低于当前值时,跳过该 SubShader(如 LOD 200 表示支持法线贴图)。
4. 通道块(Pass Block)
每个 Pass 代表一次完整的渲染流程,包含渲染状态设置和 HLSL 代码。
hlsl
Pass {
// 渲染状态指令
Blend SrcAlpha OneMinusSrcAlpha // 透明混合
ZTest LEqual // 深度测试
Cull Off // 关闭背面剔除(显示双面)
// 嵌入 HLSL 代码
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// 顶点和片元着色器函数
ENDCG
}
- 渲染状态:控制混合模式、深度缓冲、剔除等 GPU 状态,影响最终渲染效果。
- HLSL 代码:通过
CGPROGRAM
块嵌入,实现顶点变换、像素着色等核心逻辑。
5. 回退着色器(Fallback)
当所有 SubShader 均不被支持时,使用指定的回退着色器。
hlsl
Fallback "Legacy Shaders/VertexLit" // 回退到内置顶点光照着色器
- 最佳实践:回退至简单着色器(如
Diffuse
或VertexLit
),确保低端设备兼容。
6. 自定义编辑器(CustomEditor)
指定用于材质面板的自定义编辑器脚本,格式为 CustomEditor "脚本类名"
。
hlsl
CustomEditor "MyShaderEditor" // 引用 Assets 目录下的 MyShaderEditor.cs
- 用途:自定义材质参数的显示方式(如添加按钮、滑动条或条件显示参数)。
三、跨渲染管线的兼容性
ShaderLab 的 Shader
块兼容所有渲染管线,但需注意以下差异:
功能 | 内置管线 | URP | HDRP |
---|---|---|---|
材质属性 | ✅ | ✅ | ✅ |
SubShader 标签 | 传统标签(如 "LightMode") | URP 专用标签(如 "LightMode"="UniversalForward") | HDRP 专用标签(如 "LightMode"="HDRenderPipeline") |
HLSL 头文件引用 | UnityCG.cginc | Packages/.../Core.hlsl | Packages/.../ShaderLibrary/ |
自定义渲染流程 | 直接编写 Pass | 使用 URP 专用函数 | 使用 HDRP 专用函数 |
示例:URP 着色器的 SubShader 标签
hlsl
SubShader {
Tags {
"RenderType"="Opaque"
"LightMode"="UniversalForward" // URP 正向渲染标签
"UniversalPipeline"="UniversalPipeline"
}
// ...
}
四、旧版着色器名称规则(Legacy Shader Names)
在 Unity 5.0 前,部分着色器的功能由名称路径决定,修改名称可能导致功能异常:
- 示例:
- 名称包含 "Transparent/Cutout" 的着色器自动启用 Alpha 裁剪。
- 名称包含 "Reflective" 的着色器支持立方体贴图反射。
- 注意事项:
- 旧项目中的 legacy 着色器需保持名称不变。
- 新项目应避免依赖此机制,改用现代渲染管线的标签和代码逻辑。
五、完整示例:基础漫反射着色器
hlsl
Shader "Custom/BasicDiffuse" {
// 1. 属性定义
Properties {
_MainTex ("Base Texture", 2D) = "white" {}
_Color ("Tint Color", Color) = (1,1,1,1)
}
// 2. 子着色器定义
SubShader {
Tags { "RenderType"="Opaque" "Queue"="Geometry" }
LOD 100 // 最低细节层级(仅漫反射)
Pass {
Tags { "LightMode"="ForwardBase" } // 内置管线正向渲染主光源
// 渲染状态:开启深度测试
ZTest LEqual
// HLSL 代码块
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// 引用属性变量
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
// 顶点输入结构
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 = TRANSFORM_TEX(v.uv, _MainTex); // 应用 UV 缩放/偏移
return o;
}
// 片元着色器:纹理采样与颜色混合
fixed4 frag (v2f i) : SV_TARGET {
fixed4 tex = tex2D(_MainTex, i.uv);
return tex * _Color;
}
ENDCG
}
}
// 3. 回退至内置漫反射着色器
Fallback "Diffuse"
}
六、最佳实践建议
- 渲染管线适配:
- 新项目优先为 URP/HDRP 编写着色器,使用对应的标签和 HLSL 库。
- 通过
#if UNITY_URP
等条件编译区分不同管线的代码。
- 性能优化:
- 减少 SubShader 数量,通过
LOD
分级而非重复编写 SubShader。 - 合并 Pass,使用
MultiCompile
生成变体而非多个独立 Pass。
- 减少 SubShader 数量,通过
- 可维护性:
- 为属性和变量添加注释,说明其功能(如
// 控制皮肤光泽度
)。 - 将通用函数封装到
.cginc
头文件中,避免重复代码。
- 为属性和变量添加注释,说明其功能(如
总结
ShaderLab 的 Shader
块是定义 Unity 着色器的基础,通过合理组织属性、SubShader 和 Pass,可实现从简单漫反射到复杂 PBR 材质的各种效果。理解其嵌套结构与渲染管线兼容性,能帮助开发者高效编写跨平台、高性能的着色器,同时为后续使用 Shader Graph 或自定义渲染管线奠定基础。