🧱 Spine 材质替换避坑清单(Unity)
✅ 推荐做法总览
目的 | 推荐方法 | 原因 |
---|---|---|
替换材质 | SkeletonRendererCustomMaterials + 提前配置 | 官方推荐方式,适合静态替换 |
动态控制属性 | MaterialPropertyBlock + MeshRenderer | 不克隆材质,性能好,动画安全 |
大量实例共享材质 + 动态控制 | 使用 MaterialPropertyBlock | 减少 GC 和内存占用 |
溶解、透明等动态特效 | PropertyBlock 或 Shader Controller 脚本控制参数 | 避免 Spine 自动重置材质 |
☠ 常见坑点与规避
1. Spine 会在运行时自动恢复材质
- 触发方式: 动画切换 / Skeleton 刷新 / 设置新的 skin。
- 表现: 你修改的材质会突然被替换回原始材质。
- 规避: 使用 SkeletonRendererCustomMaterials 来替换原始材质。 不要只用 skeletonAnimation.GetComponent<MeshRenderer>().material = xxx,会被 Spine 重置。
2. .material
会克隆材质实例(Material Instancing)
- 问题: 每次调用 .material 都会 clone 材质,生成新实例。
- 后果: 内存暴涨,Inspector 材质变成 (Instance)。
- 规避: 用 .sharedMaterial(不可修改)或 MaterialPropertyBlock 来只改属性。
3. MaterialPropertyBlock
改不了贴图或 shader keywords
- 支持: _Float, _Color, _Vector, _Texture(部分支持)。
- 不支持: EnableKeyword、SetShaderPassEnabled 等。
- 解决: 需要提前配置好材质,属性只用来调参数。
4. Spine 插槽级别材质替换复杂
- 使用 SkeletonRenderer.CustomSlotMaterials: csharp复制编辑var slot = skeletonAnimation.skeleton.FindSlot("slot_name"); skeletonRenderer.CustomSlotMaterials[slot] = yourMaterial;
- 但这种方式同样不适合动态控制 shader 参数。
- 用 PropertyBlock 控制 MeshRenderer 是更实用的方式。
5. DOTween 与 PropertyBlock 搭配注意
- MaterialPropertyBlock 是临时结构,每次都要完整 Get ➜ Set。
- 示例: csharp复制编辑var mpb = new MaterialPropertyBlock(); DOTween.To(() => 0f, v => { renderer.GetPropertyBlock(mpb); mpb.SetFloat("_MyParam", v); renderer.SetPropertyBlock(mpb); }, 1f, 1f);
🔧 实战建议
✅ Spine 材质替换推荐组合方式(动态特效场景):
- 在编辑器中提前挂: SkeletonRendererCustomMaterials 将原始材质替换成你的特效材质(带 _DissolveAmount、_Alpha 等)。
- 在代码中只控制参数: 用 MeshRenderer.GetPropertyBlock 修改。
📌 工具与辅助方案
工具 | 用法 |
---|---|
SkeletonRenderer.CustomMaterialOverride | 全局材质替换(不区分 slot) |
SkeletonRenderer.CustomSlotMaterials | 单独 slot 替换(精细控制) |
MaterialPropertyBlock | 动态效果控制最佳实践 |
DOTween | 补间动画控制材质属性非常实用 |