当前位置: 代码迷 >> 综合 >> Unity修改Shader使UI支持Mask功能
  详细解决方案

Unity修改Shader使UI支持Mask功能

热度:32   发布时间:2024-03-06 21:08:21.0

当UI界面上有很多UI元素,在固定区域内显示不完全时,我们通常会添加UGUI自带的Scroll View,或者添加ScrollRect和Mask组件,使内容可滑动,辅助实现该功能。

但当UI元素里面有粒子特效的时候,我们就会发现特效滑动到Mask以外的区域时,界面上的粒子特效会穿透UI面板。

这时候你可以修改Mask组件,添加MaskPlus代码,将UI上的Mask替换成MaskPlus!

using UnityEngine;
using UnityEngine.UI;public class MaskPlus : Mask
{Camera cam;protected override void Start(){base.Start();ResetShaderMaskClip();}protected override void OnEnable(){base.OnEnable();ResetShaderMaskClip();}public void ResetShaderMaskClip(){Vector3[] points = new Vector3[4];(transform as RectTransform).GetWorldCorners(points);if (cam == null)cam = GameObject.Find("XXXXXXX").GetComponent<Camera>();float x;float y;float x1;float y1;Vector3 scPos = cam.WorldToScreenPoint(points[0]);x = scPos.x;y = scPos.y;x1 = scPos.x;y1 = scPos.y;for (int i = 0; i < points.Length; i++){scPos = cam.WorldToScreenPoint(points[i]);//取最小xyx = scPos.x < x ? scPos.x : x;y = scPos.y < y ? scPos.y : y;//取最大x1 = scPos.x > x1 ? scPos.x : x1;y1 = scPos.y > y1 ? scPos.y : y1;}Vector4 normalize = new Vector4(x / Screen.width, y / (float)Screen.height, x1 / (float)Screen.width, y1 / (float)Screen.height);Shader.SetGlobalVector("_MaskClip", normalize);}
}

接下来新加一个shader,替换掉粒子特效的shader。

//@@@DynamicShaderInfoStart
//自发光贴图材质 支持UGUI Mask
//@@@DynamicShaderInfoEnd//@@@DynamicShaderTitleRepaceStart
Shader "Custom/NoLight/Unlit - Color - UIMaskClip##" {
//@@@DynamicShaderTitleRepaceEndProperties{_MainTex("Texture", 2D) = "white" { }_TintColor("Color", Color) = (0.5,0.5,0.5,0.5)_Lighting("Lighting",  float) = 1_CutOut("CutOut", float) = 0.1//此段可以将 ZWrite 选项暴露在Unity的Inspector中[Enum(Off, 0, On, 1)] _zWrite("Zwrite", Float) = 0//此段可以将 Ztest  选项暴露在Unity的Inspector中[Enum(UnityEngine.Rendering.CompareFunction)] _zTest("ZTest", Float) = 4//此段可以将 Cull  选项暴露在Unity的Inspector中[Enum(UnityEngine.Rendering.CullMode)] _cull("Cull Mode", Float) = 2//此段可以将 Blend 选项暴露在Unity的Inspector中[Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend("Src Blend Mode", Float) = 5[Enum(UnityEngine.Rendering.BlendMode)] _DstBlend("Dst Blend Mode", Float) = 10[Enum(UnityEngine.Rendering.BlendMode)] _SrcAlphaBlend("Src Alpha Blend Mode", Float) = 1[Enum(UnityEngine.Rendering.BlendMode)] _DstAlphaBlend("Dst Alpha Blend Mode", Float) = 10}SubShader{//@@@DynamicShaderTagsRepaceStartTags {"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" }//@@@DynamicShaderTagsRepaceEndPass{//面板化Blend[_SrcBlend][_DstBlend],[_SrcAlphaBlend][_DstAlphaBlend]Zwrite[_zWrite]ZTest[_zTest]Cull[_cull]//@@@DynamicShaderBlendRepaceStart//@@@DynamicShaderBlendRepaceEndCGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"// #pragma multi_compile CLIP_OFF CLIP_ONsampler2D _MainTex;float4 _MainTex_ST;float _Lighting;float4 _MaskClip;struct v2f {float4  pos : SV_POSITION;float2  uv : TEXCOORD0;float4 color : COLOR;float4  projPos : TEXCOORD2;};struct appdata {float4 vertex : POSITION;float2 texcoord:TEXCOORD0;float4 color : COLOR;};//顶点函数没什么特别的,和常规一样 v2f vert(appdata v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);o.color = v.color;o.projPos = ComputeScreenPos(o.pos);return o;}fixed4 _TintColor;float4 frag(v2f i) : COLOR{float4 col = tex2D(_MainTex,i.uv);col = col* _TintColor*i.color;col.rgb *= _Lighting;//先clip,再fog 不然会出错	int o;o = sign(i.projPos.x - _MaskClip.x) + sign(i.projPos.y - _MaskClip.y) + sign(_MaskClip.z - i.projPos.x) + sign(_MaskClip.w - i.projPos.y);clip(o / 4 - 0.5);return col;}ENDCG}}
}

如果你使用的是UI特效,你会发现Unity一直报 doesn't have _Stencil property的警告,可以参考unity 让自定义 ui shader 支持 UGUI 的 Mask 功能  修改你的shader。

shader示例:

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'//@@@DynamicShaderInfoStart
//简单的UV双色控制
//@@@DynamicShaderInfoEnd//@@@DynamicShaderTitleRepaceStart
Shader "Custom/UI/Image-UVColor##"{
//@@@DynamicShaderTitleRepaceEndProperties{[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0_ColorStart ("Start Color", Color) = (1,1,1,1)_ColorEnd ("End Color", Color) = (1,1,1,1)_lerp ("Lerp", Range(0,1)) = 0[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//此段可以将 ZWrite 选项暴露在Unity的Inspector中[Enum(Off, 0, On, 1)] _zWrite("ZWrite", Float) = 1//此段可以将 Ztest  选项暴露在Unity的Inspector中[Enum(UnityEngine.Rendering.CompareFunction)] _zTest("ZTest", Float) = 4//此段可以将 Cull  选项暴露在Unity的Inspector中[Enum(UnityEngine.Rendering.CullMode)] _cull("Cull Mode", Float) = 2//此段可以将 Blend 选项暴露在Unity的Inspector中[Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend("Src Blend Mode", Float) = 5[Enum(UnityEngine.Rendering.BlendMode)] _DstBlend("Dst Blend Mode", Float) = 10[Enum(UnityEngine.Rendering.BlendMode)] _SrcAlphaBlend("Src Alpha Blend Mode", Float) = 1[Enum(UnityEngine.Rendering.BlendMode)] _DstAlphaBlend("Dst Alpha Blend Mode", Float) = 10}
Category {Tags{ "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane""CanUseSpriteAtlas"="True"}Stencil{Ref [_Stencil]Comp [_StencilComp]Pass [_StencilOp] ReadMask [_StencilReadMask]WriteMask [_StencilWriteMask]}Lighting OffFog { Mode Off }//@@@DynamicShaderBlendRepaceStart//面板化Blend[_SrcBlend][_DstBlend],[_SrcAlphaBlend][_DstAlphaBlend]ZWrite[_zWrite]ZTest[_zTest]Cull[_cull]//@@@DynamicShaderBlendRepaceEndSubShader{Pass{Name "SPRITE_BASE"CGPROGRAM#pragma vertex vert#pragma fragment frag#pragma multi_compile DUMMY PIXELSNAP_ON#include "UnityCG.cginc"struct appdata_t{float4 vertex   : POSITION;float4 color    : COLOR;float2 texcoord : TEXCOORD0;};struct v2f{float4 vertex   : SV_POSITION;fixed4 color    : COLOR;half2 texcoord  : TEXCOORD0;};v2f vert(appdata_t IN){v2f OUT;OUT.vertex = UnityObjectToClipPos(IN.vertex);OUT.texcoord = IN.texcoord;OUT.color = IN.color ;#ifdef PIXELSNAP_ONOUT.vertex = UnityPixelSnap (OUT.vertex);#endifreturn OUT;}sampler2D _MainTex;fixed4 _ColorStart;fixed4 _ColorEnd;float   _lerp;fixed4 frag(v2f IN) : COLOR{float lp= saturate((1-IN.texcoord.y)*_lerp*10);fixed4 lerpCol=lerp(_ColorStart,_ColorEnd,lp);fixed4	 col= tex2D(_MainTex, IN.texcoord) * IN.color * lerpCol;	return  col;}ENDCG}}}
}

 

  相关解决方案