Unity之引导功能遮罩事件穿透

Posted 彩色墨水

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity之引导功能遮罩事件穿透相关的知识,希望对你有一定的参考价值。

Unity之新手引导shader遮罩事件穿透

效果图

设计思路

1.新手引导我们期待开发内容不影响正常的功能模块,意思就是分层,新手引导在正常功能之上
2.新手引导层级用一层深色bg显示遮住正常功能层级,在需要引导的位置留出高亮区域
3.在这个新手引导层做事件渗透,给指定的对象或UI做事件渗透,如果点击交互位置处于指定UI或对象范围内,让事件渗透新手引导层,到正常功能层。

场景搭建

搭建两个层级


一个正常功能层级为Canvas下,一个新手引导层级在GuideHolder下。

制作新手引导的预制体


材质使用我们特制的带镂空效果的材质shader,并挂载一个事件渗透作用的脚本

代码

这里有两个比较重要的内容,一个是遮罩层是深色的,并要镂空指定区域做高亮,这里使用shader去制作效果图。二是在合适时机做指定区域的事件渗透。

GuideMask.cs
    /// <summary>
    /// 创建圆形点击区域
    /// </summary>
    /// <param name="pos">圆心的屏幕位置</param>
    /// <param name="rad">圆的半径</param>
    /// <param name="CallBack">点击的回调</param>
    public void CreateCircleMask(Vector3 pos, float rad, GameObject target)
    
        ShowGuideMask(()=> 
            ShowTween = true;
            ev.SetTargetImage(target);
            _rectTrans.sizeDelta = Vector2.zero;
            _materia.SetFloat("_MaskType", 0f);
            CurRadNum = rad;
            _materia.SetVector("_Origin", new Vector4(pos.x, pos.y, rad + 1000, 20));
        );

    
        public  void ShowGuideMask(Action callback)
    
        ShowTween = false;
        if (_rectTrans == null)
        
            ResMgr.Instance.Load("GuideSystem", (obj) => 

                guide = Instantiate((GameObject)obj, ISceneManager.Instance.GuideHolder);
                _rectTrans = guide.GetComponent<RectTransform>();
                _rawImage = guide.GetComponent<RawImage>();
                _rawImage.color = new Color(1, 1, 1, 1);
                _materia = _rawImage.material;

                ev = guide.GetComponent<EventPenetrate>();
                callback();
            );
        
        else
        
            callback();
        
    
GuideMask.shader
Shader "UI/GuideMask"

	Properties
	
		[PerRendererData] _MainTex("Sprite Texture", 2D) = "white" 
		_Color("Tint", Color) = (1,1,1,1)
		_Blur("边缘虚化的范围", Range(1,1000)) = 100
		_StencilComp("Stencil Comparison", Float) = 8
		_Stencil("Stencil ID", Float) = 0
		_StencilOp("Stencil Operation", Float) = 0
		_StencilWriteMask("Stencil Write Mask", Float) = 255
		_StencilReadMask("Stencil Read Mask", Float) = 255		
		_ColorMask("Color Mask", Float) = 15
		//中心
		_Origin("Circle",Vector) = (0,0,0,0)
		//裁剪方式 0圆形 1圆形
		_MaskType("Type",Float) = 0	
	

		SubShader
	
		Tags
	
		"Queue" = "Transparent"
		"IgnoreProjector" = "True"
		"RenderType" = "Transparent"
		"PreviewType" = "Plane"
		"CanUseSpriteAtlas" = "True"
	

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

		Cull Off
		Lighting Off
		ZWrite Off
		ZTest[unity_GUIZTestMode]
		Blend SrcAlpha OneMinusSrcAlpha
		ColorMask[_ColorMask]

		Pass
	
		Name "Default"
		CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 2.0

#include "UnityCG.cginc"
#include "UnityUI.cginc"



		struct appdata_t
	
		float4 vertex : POSITION;
		float4 color : COLOR;
		float2 texcoord : TEXCOORD0;
		UNITY_VERTEX_INPUT_INSTANCE_ID
	;

	struct v2f
	
		float4 vertex : SV_POSITION;
		fixed4 color : COLOR;
		float2 texcoord : TEXCOORD0;
		float4 worldPosition : TEXCOORD1;
		UNITY_VERTEX_OUTPUT_STEREO
	;

	fixed4 _Color;
	fixed4 _TextureSampleAdd;
	float4 _ClipRect;
	float4 _Origin;
	float _MaskType;	
	float _Blur;
	v2f vert(appdata_t IN)
	
		v2f OUT;
		UNITY_SETUP_INSTANCE_ID(IN);
		UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
		OUT.worldPosition = IN.vertex;
		OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);
		OUT.texcoord = IN.texcoord;
		OUT.color = IN.color * _Color;
		return OUT;
	

	sampler2D _MainTex;

	fixed4 frag(v2f IN) : SV_Target
	
		half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;

		if (_MaskType == 0) 
			//if (distance(IN.worldPosition.xy, _Origin.xy) <= _Origin.z)
			//
			//	color.a = 0;
			//			
			  float dis = distance(IN.worldPosition.xy, _Origin.xy);
			  //过滤掉距离小于(半径-过渡范围)的片元
			  clip(dis - (_Origin.z - _Blur));
			  //优化if条件判断,如果距离小于半径则执行下一步,等于if(dis < _Radius)
			  fixed tmp = step(dis, _Origin.z);
			  //计算过渡范围内的alpha值
			  color.a *= (1 - tmp) + tmp * (dis - (_Origin.z - _Blur)) / _Blur;
		
		else if (_MaskType == 1) 
			//UnityGet2DClipping这个函数实现了判断2D空间中的一点是否在一个矩形区域中
			if (UnityGet2DClipping(IN.worldPosition.xy, _Origin))
			
				color.a = 0;

			

		
		else if (_MaskType == 2)
		
			if (UnityGet2DClipping(IN.worldPosition.xy, _Origin))
			
				color.a = 0;
				#ifdef UNITY_UI_CLIP_RECT
               color.a *= UnityGet2DClipping(IN.worldPosition.xy, _Origin);
                #endif
			               
		

		return color;
	
		ENDCG
	
	

调用
 GuideMask.Instance.CreateCircleMaskoffset(button2.gameObject, 0, null);
  GuideMask.Instance.CloseGuideMask();

工程项目

链接:https://pan.baidu.com/s/1v4laE9QdqRGWKqfKJpnkxQ
提取码:s8qc

以上是关于Unity之引导功能遮罩事件穿透的主要内容,如果未能解决你的问题,请参考以下文章

Unity之引导功能遮罩事件穿透

小功能⭐️Unity遮罩

小功能⭐️Unity遮罩

小功能⭐️Unity遮罩

iOS:如何实现遮罩视图事件穿透?

1.解决小程序遮罩层遮住页面后滚动穿透问题