MaterialPropertyBlock 是 Unity 提供的一个用于动态修改材质属性的轻量级工具,核心作用是避免材质实例化(Material Instantiation),从而优化性能。以下是它的关键特性和使用方法:
1. 核心作用
-
避免材质实例化
直接修改Material
对象(如material.color = ...
)会导致 Unity 创建该材质的独立副本(实例化),增加内存占用和 Draw Call。
MaterialPropertyBlock 允许多个对象共享同一材质,但拥有独立的属性值(如颜色、纹理)。 -
动态属性控制
适合在运行时频繁修改材质属性(如颜色渐变、纹理切换),同时保持渲染性能。
2. 基本用法
// 步骤 1: 获取 Renderer 组件
Renderer renderer = GetComponent<Renderer>();
// 步骤 2: 创建或获取 MaterialPropertyBlock
MaterialPropertyBlock mpb = new MaterialPropertyBlock();
renderer.GetPropertyBlock(mpb); // 获取当前属性块(保留未修改的属性)
// 步骤 3: 修改属性
mpb.SetColor("_BaseColor", Color.red); // 修改颜色
mpb.SetTexture("_BaseMap", myTexture); // 修改纹理
// 步骤 4: 应用到 Renderer
renderer.SetPropertyBlock(mpb);
3. 与直接修改 Material 的区别
特性 | 直接修改 Material | MaterialPropertyBlock |
---|---|---|
材质实例化 | 会创建材质副本(内存↑) | 共享材质,无副本(内存优化) |
性能 | 频繁调用可能导致卡顿 | 高效,适合动态属性修改 |
属性持久化 | 修改永久生效(保存到材质) | 临时修改(仅运行时有效) |
适用场景 | 需要持久化属性修改时 | 动态效果(如闪烁、颜色渐变) |
4. 关键优势
-
减少Draw Call
多个对象使用相同的材质和MaterialPropertyBlock时,Unity会自动合并渲染批次(Batching)。 -
内存友好
避免因频繁材质实例化导致的内存碎片和泄漏。 -
灵活控制
可动态修改材质属性,同时不影响其他使用相同材质的对象。
5. 注意事项
-
属性名称需匹配
必须使用着色器中定义的属性名称(如URP中的_BaseColor
,而非旧版的_Color
)。 -
属性块生命周期
MaterialPropertyBlock 是临时对象,需在每次修改时重新应用。
(例如:在Update()
中动态修改颜色时,需每帧调用SetPropertyBlock
) -
线程安全
只能在主线程中操作(Unity的渲染API非线程安全)。
6. 典型应用场景
- 角色受伤闪烁
动态修改_BaseColor
实现颜色变化,不影响其他角色。 - 动态环境切换
批量修改一组对象的纹理(如季节变化)。 - UI 动态样式
修改按钮的高光颜色或背景纹理。
示例:批量修改颜色(高效版)
public class BatchColorChanger : MonoBehaviour
{
public Renderer[] renderers;
public Color targetColor;
void Start()
{
MaterialPropertyBlock mpb = new MaterialPropertyBlock();
foreach (var renderer in renderers)
{
renderer.GetPropertyBlock(mpb); // 获取当前属性
mpb.SetColor("_BaseColor", targetColor); // 修改颜色
renderer.SetPropertyBlock(mpb); // 应用修改
}
}
}
总结:MaterialPropertyBlock 是优化运行时材质修改的核心工具,尤其在需要批量处理或动态效果时,能显著提升性能。在URP/HDRP项目中,建议优先使用它替代直接修改材质属性。