Unity3D MaterialPropertyBlock 的一个坑

遇到的问题

项目中有个预制体里面包含了 SpriteRender、Spine 的 MeshRenderer ,以及粒子系统特效。需求是要求游戏里的这个预制体对象在某一种状态下半透明。使用 MaterialPropertyBlock 修改预制体对象中的一个 Sprite 的材质颜色时,该对象直接变成了全白显示。

产生问题的原因

Sprite 的着色器中的 _Color 属性使用了 [PerRendererData] 标签。因为 Unity 在内部使用 MaterialPropertyBlock 进行 Sprite 渲染,所以使用 MaterialPropertyBlock 发送一些 [PerRendererData] 时,必须首先使用 Renderer.GetMaterialPropertyBlock 获取默认的材质属性,然后在获取的 MaterialPropertyBlock 对象的基础上修改指定的某个属性,直接修改会覆盖掉 默认材质属性块的其他属性,如 _MainTex 等。

解决办法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function SetAlpha(alpha)
if self._renderList == nil then
return
end

if self._matPropBlock == nil then
self._matPropBlock = UnityEngine.MaterialPropertyBlock.New()
else
self._matPropBlock:Clear()
end

for __, v in ipairs(self._renderList) do
local mat = v.sharedMaterial
if v:HasPropertyBlock() then
v:GetPropertyBlock(self._matPropBlock)
end

if mat:HasProperty("_Color") then
local color = mat:GetColor("_Color")
color.a = alpha
self._matPropBlock:SetColor("_Color", color)
v:SetPropertyBlock(self._matPropBlock)
end
end
end

参考资料

  • Unity3D PerRendererData