You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Shader中ColorMask与ScrollView Mask冲突致材质无法更新的解决方法咨询

解决Unlit/AlphaCutoffAA_UI Shader中_ColorMask导致的材质更新异常问题

我之前碰到过完全类似的UI Shader与ScrollRect遮罩兼容的坑,核心问题出在**_ColorMask作为渲染状态参数在SubShader层级直接引用时,Unity UI系统动态修改它后,材质没有正确触发重渲染**——尤其是被ScrollRect遮罩的区域,因为遮罩本质是通过临时把_ColorMask设为0来实现像素裁剪的,参数变化没有同步到渲染管线。

下面是具体的修复方案,分两步走:

1. 调整Shader结构,适配Unity UI的参数更新机制

我们需要引入Unity UI的内置库,使用标准的UI顶点输入结构,同时把ColorMask的控制逻辑从SubShader移到Pass内部,确保参数变化能被正确捕获并生效:

修改后的完整Shader代码:

Shader "Unlit/AlphaCutoffAA_UI" {
 Properties {
 _MainTex ("Base (RGB)", 2D) = "white" {}
 _Color("Color Multiplier", Color) = (1, 1, 1, 1)
 _Cutoff ("Cutoff", Range(0,1)) = 0.5
 _Blend ("Blend Range", Range(0,.2)) = 0.1
 [HideInInspector]_StencilComp("Stencil Comparison", Float) = 8
 [HideInInspector]_Stencil("Stencil ID", Float) = 0
 [HideInInspector]_StencilOp("Stencil Operation", Float) = 0
 [HideInInspector]_StencilWriteMask("Stencil Write Mask", Float) = 255
 [HideInInspector]_StencilReadMask("Stencil Read Mask", Float) = 255
 [HideInInspector]_ColorMask("Color Mask", Float) = 15
 [HideInInspector]_UseUIAlphaClip("Use Alpha Clip", Float) = 0
 }
 SubShader {
 Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="TransparentCutout" "PreviewType"="Plane" "CanUseSpriteAtlas"="True"}
 LOD 100
 Lighting Off
 ZWrite Off
 Blend SrcAlpha OneMinusSrcAlpha

 Stencil {
 Ref[_Stencil]
 Comp[_StencilComp]
 Pass[_StencilOp]
 ReadMask[_StencilReadMask]
 WriteMask[_StencilWriteMask]
 }

 Pass {
 CGPROGRAM
 #pragma vertex vert
 #pragma fragment frag
 #pragma target 2.0

 #include "UnityCG.cginc"
 #include "UnityUI.cginc" // 引入UI内置工具库

 struct appdata_t {
 float4 vertex : POSITION;
 float2 texcoord : TEXCOORD0;
 float4 color : COLOR; // 增加UI顶点颜色输入,符合Unity UI渲染逻辑
 };

 struct v2f {
 float4 vertex : SV_POSITION;
 half2 texcoord : TEXCOORD0;
 fixed4 color : TEXCOORD1;
 float4 worldPosition : TEXCOORD2;
 };

 sampler2D _MainTex;
 float4 _MainTex_ST;
 fixed _Cutoff;
 fixed _Blend;
 float4 _Color;
 fixed4 _TextureSampleAdd;
 float _ClipRect[4];
 float _ColorMask; // 在Pass内声明参数,确保能实时获取最新值

 v2f vert (appdata_t v) {
 v2f o;
 o.worldPosition = v.vertex;
 o.vertex = UnityObjectToClipPos(o.worldPosition);
 o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
 o.color = v.color * _Color; // 合并UI顶点颜色与自定义Color参数

 // 处理UI矩形裁剪逻辑
 #ifdef UNITY_UI_CLIP_RECT
 o.worldPosition.xy -= _ClipRect.xy;
 o.worldPosition.xy /= _ClipRect.zw;
 #endif

 return o;
 }

 fixed4 frag (v2f i) : SV_Target {
 fixed4 col = tex2D(_MainTex, i.texcoord) * i.color;
 col.rgb += _TextureSampleAdd.rgb;

 // 保留你的Alpha Cutoff AA逻辑
 if(col.a < _Cutoff) {
 col.a = 0;
 } else if (col.a < _Cutoff + _Blend) {
 col.a = saturate((col.a - _Cutoff) / _Blend);
 } else {
 col.a = 1.0;
 }

 // 应用UI裁剪
 #ifdef UNITY_UI_CLIP_RECT
 col.a *= UnityGet2DClipping(i.worldPosition.xy, _ClipRect);
 #endif

 // 用Fragment逻辑替代静态ColorMask渲染状态,确保参数变化即时生效
 if (_ColorMask == 0) {
 discard; // 完全裁剪像素
 } else {
 // 根据_ColorMask的值屏蔽对应通道
 col.r *= (_ColorMask & 1) ? 1 : 0;
 col.g *= (_ColorMask & 2) ? 1 : 0;
 col.b *= (_ColorMask & 4) ? 1 : 0;
 col.a *= (_ColorMask & 8) ? 1 : 0;
 }

 return col;
 }
 ENDCG
 }
 }
 FallBack "UnityUI/Default"
}

2. 关键修改点说明

  • 引入UnityUI.cginc:这个库包含了UI系统必备的裁剪、顶点颜色处理宏,让Shader完美适配Unity的UI组件(包括ScrollRect的遮罩逻辑)。
  • 将ColorMask逻辑移到Fragment Shader:原来在SubShader层级的ColorMask[_ColorMask]是静态渲染状态,参数变化时可能不会触发材质重绘。现在在Fragment中通过动态判断_ColorMask的值来控制像素输出,确保参数修改能即时反映到渲染结果。
  • 添加UI裁剪处理:通过UNITY_UI_CLIP_RECT宏处理ScrollRect的矩形裁剪,与Stencil遮罩逻辑互补,同时兼容原有功能。
  • 使用标准UI顶点结构:加入顶点颜色输入,合并自定义_Color和UI的顶点颜色,完全贴合Unity UI的渲染流程。

额外验证步骤

  1. 替换Shader后,给UI Image绑定该材质,调整_Color、_Cutoff等参数,观察被ScrollRect遮罩的区域是否能正常更新。
  2. 如果仍有偶发的更新延迟,可以在代码中修改材质参数后,调用material.SetDirty()强制标记材质为脏,触发立即重渲染。

内容的提问来源于stack exchange,提问作者Draco18s no longer trusts SE

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:42:18