在 ShaderLab 中,通过 Properties 块 定义的材质属性是连接着色器代码与编辑器交互的核心。这些属性允许美术人员在材质面板中直观调整参数,同时支持通过脚本动态控制。以下是材质属性的定义规则、类型详解及跨管线最佳实践:
一、材质属性的核心作用
-
编辑器交互:
- 在材质面板中显示为可编辑字段(如滑块、颜色选择器、纹理预览)。
- 示例:通过
_MainTex
属性指定模型的基础纹理,通过_TintColor
控制颜色叠加。
-
数据持久化:
- 属性值随材质资产保存,支持跨会话保留修改(如退出 Unity 后重新打开项目,参数值不变)。
-
代码控制:
- 通过 C# 脚本调用
Material.SetFloat
/Material.GetTexture
等接口动态修改属性值。 - 示例:实时调整粒子系统的发光强度
material.SetFloat("_GlowIntensity", intensity);
。
- 通过 C# 脚本调用
二、属性定义语法与类型
材质属性声明格式为:
hlsl
[属性标签] 属性名 ("面板显示名", 类型) = 默认值
1. 基础类型与示例
类型 | 声明示例 | HLSL 对应类型 | 面板显示 |
---|---|---|---|
Integer | _IntProp ("整数", Integer) = 10 | int | 整数输入框 |
Float | _FloatProp ("浮点", Float) = 0.5 | float | 浮点滑块(默认 0~1) |
Range | _RangeProp ("范围", Range(0, 5)) = 2.3 | float | 限定范围滑块 |
Color | _ColorProp ("颜色", Color) = (1, 0.5, 0.5, 1) | float4 | 颜色选择器 |
Vector | _VectorProp ("向量", Vector) = (1, 2, 3, 4) | float4 | 四维浮点输入框 |
2D 纹理 | _MainTex ("基础纹理", 2D) = "white" {} | sampler2D | 纹理选择器(支持 Alpha) |
Cube 纹理 | _CubeMap ("反射立方图", Cube) = "" {} | samplerCUBE | 立方体贴图选择器 |
3D 纹理 | _VolumeTex ("体积纹理", 3D) = "" {} | sampler3D | 三维纹理选择器 |
- 默认值规则:
- 纹理类型默认值可指定为
"white"
/"black"
等内置纹理,或留空使用灰色纹理。 - 颜色类型默认值需包含 RGBA 四个分量(如
(R,G,B,A)
)。
- 纹理类型默认值可指定为
2. 旧版类型(Legacy)
- Int:基于浮点的伪整数类型(如
_LegacyInt ("旧版整数", Int) = 1
),不推荐新代码使用,优先选择Integer
。 - Rect:二维矩形参数(已被
Vector
替代,Vector
的 XY 表示左上角,ZW 表示宽高)。
3. 特殊类型
- Texture2DArray:二维纹理数组,用于多切片纹理(如地形多层材质)。
- CubemapArray:立方体贴图数组,支持多视角反射纹理。
三、属性标签(Attributes)
通过标签修饰属性,控制编辑器行为或渲染逻辑:
标签 | 作用 | 示例 |
---|---|---|
[Gamma] | 声明属性值为 sRGB 颜色空间(如纹理颜色需符合伽马校正) | [Gamma]_Color ("伽马颜色", Color) = (1,1,1,1) |
[HDR] | 启用高动态范围(如自发光颜色支持超亮值) | [HDR]_Emission ("HDR 发光", Color) = (5,5,5,1) |
[Normal] | 标记为法线贴图(编辑器验证纹理格式并显示警告) | [Normal]_NormalMap ("法线", 2D) = "bump" {} |
[NoScaleOffset] | 隐藏纹理平铺 / 偏移字段(适用于不需要 UV 动画的纹理) | [NoScaleOffset]_DetailTex ("细节纹理", 2D) = "" {} |
[MainTexture] | 指定主纹理(替代默认 _MainTex 名称,如纹理名为 _TextureMap 时) | [MainTexture]_TextureMap ("主纹理", 2D) = "" {} |
[HideInInspector] | 从材质面板隐藏属性(仅通过脚本控制) | [HideInInspector]_InternalParam ("内部参数", Float) = 0 |
- 最佳实践:
- 法线贴图始终添加
[Normal]
标签,确保编辑器提示正确纹理格式。 - 移动端避免使用
[HDR]
以减少显存占用,除非必要(如动态光照探针)。
- 法线贴图始终添加
四、跨渲染管线兼容性
-
SRP Batcher 支持:
- 在 HLSL 中,需将材质属性变量放入同一
CBUFFER
块,确保 SRP Batcher 合并材质实例。
hlsl
CBUFFER_START(UnityPerMaterial) float4 _MainTex_ST; fixed4 _TintColor; CBUFFER_END
- 在 HLSL 中,需将材质属性变量放入同一
-
URP/HDRP 特殊要求:
- URP 中,主纹理需通过
_MainTex
或[MainTexture]
声明,否则可能无法正确应用光照。 - HDRP 支持更多高级属性(如体积雾参数),需引用对应 HLSL 库(如
Packages/com.unity.render-pipelines.high-definition/ShaderLibrary/
)。
- URP 中,主纹理需通过
五、属性与代码的交互
1. 在 ShaderLab 指令中使用属性
通过 [属性名]
语法在渲染状态指令中引用属性值:
hlsl
Pass {
// 使用 _OffsetScale 属性控制深度偏移
Offset 0, [_OffsetScale]
CGPROGRAM
// ... HLSL 代码 ...
ENDCG
}
2. 在 HLSL 中引用属性
属性名需与 HLSL 变量名一致,类型匹配:
hlsl
Properties {
_MainTex ("Texture", 2D) = "white" {}
_TintFactor ("混合因子", Range(0, 1)) = 0.5
}
CGPROGRAM
sampler2D _MainTex; // 对应 2D 纹理属性
float _TintFactor; // 对应 Range/Float 属性
fixed4 frag(v2f i) : SV_TARGET {
fixed4 tex = tex2D(_MainTex, i.uv);
return tex * _TintFactor; // 混合因子控制颜色强度
}
ENDCG
3. 通过 C# 脚本控制属性
csharp
public class MaterialController : MonoBehaviour {
public Material targetMaterial;
void Update() {
// 设置浮点属性
targetMaterial.SetFloat("_GlowIntensity", Mathf.Sin(Time.time) * 2);
// 设置纹理属性
targetMaterial.SetTexture("_MainTex", newTexture);
}
}
六、高级技巧与优化
-
属性分组与折叠
通过注释在 Properties 块中添加空行或// [Group Name]
注释,实现面板分组:hlsl
Properties { // [基础属性] _MainTex ("基础纹理", 2D) = "" {} _Color ("染色", Color) = (1,1,1,1) // [光照属性] _Metallic ("金属度", Range(0,1)) = 0 _Roughness ("粗糙度", Range(0,1)) = 0.5 }
-
减少材质变体(Shader Variant)
- 使用
ShaderVariantCollection
管理属性组合,避免为每个参数值生成独立着色器变体。 - 示例:通过
#pragma multi_compile _ _USE_SPECULAR
动态切换是否启用高光属性。
- 使用
-
移动端优化
- 避免使用高精度类型(如
double
),优先用fixed
(单精度)或half
(半精度)。 - 合并属性:将颜色与向量属性的 RGBA 分量拆分到同一
float4
变量中,减少寄存器占用。
- 避免使用高精度类型(如
七、完整示例:带属性的 PBR 材质
hlsl
Shader "URP/PBR_Material" {
Properties {
[MainTexture]_MainTex ("基础纹理", 2D) = "white" {}
[Normal]_NormalMap ("法线贴图", 2D) = "bump" {}
_Metallic ("金属度", Range(0,1)) = 0
_Roughness ("粗糙度", Range(0,1)) = 0.5
[HDR]_EmissionColor ("自发光", Color) = (0,0,0,1)
}
SubShader {
Tags { "RenderType"="Opaque" "LightMode"="UniversalForward" }
LOD 300
Pass {
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
CBUFFER_START(UnityPerMaterial)
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _NormalMap;
float _Metallic;
float _Roughness;
float4 _EmissionColor;
CBUFFER_END
// ... 顶点/片元着色器代码(使用上述属性计算 PBR 光照)...
ENDHLSL
}
}
Fallback "Universal Render Pipeline/Lit"
}
八、注意事项
-
命名冲突:
- 避免使用 Unity 保留名(如
_Time
、_LightColor0
),这些名称对应内置变量。 - 保留名列表:
_TransparencyLM
(光照贴图透明通道)、_Emission
(自发光)等。
- 避免使用 Unity 保留名(如
-
性能影响:
- 每个属性在 GPU 端对应寄存器资源,过多属性可能导致着色器编译时间增加或寄存器溢出。
- 移动端建议单个材质的属性数量不超过 16 个。
-
调试技巧:
- 在材质面板中按住
Ctrl
点击属性名,快速定位 HLSL 代码中的变量声明。 - 使用
[HideInInspector]
隐藏调试用临时属性,避免污染面板。
- 在材质面板中按住
总结
材质属性是 ShaderLab 的核心交互机制,通过合理定义属性类型与标签,可在编辑器便利性、代码灵活性和性能之间取得平衡。在实际项目中,需根据渲染管线(内置 / URP/HDRP)和平台特性(PC / 移动端)优化属性结构,同时结合脚本与着色器代码实现动态效果。掌握属性定义规则是进阶着色器开发的基础,尤其在多人协作或美术主导的项目中,清晰的属性设计能显著提升工作效率。