【Shader案例】实现UGUI裁剪功能

using UnityEngine;
using UnityEngine.UI;

/// <summary>
/// 挂于裁剪物体身上的脚本,用于设置裁剪区域_ClipRect [Vector4]
/// </summary>
public class ClipTest : MonoBehaviour
{
    //作为裁剪区域的物体
    public GameObject go;
    Material mat;
    Vector2 localLbPos;
    Vector2 localrtPos;
    void Start()
    {
        //获取go物体的RectTransform四个角落点的世界坐标位置Vector3
        RectTransform rectTras = go.GetComponent<RectTransform>();
        Vector3[] worldPos = new Vector3[4];
        rectTras.GetWorldCorners(worldPos);

        //获取左下角位置
        mat = GetComponent<Image>().material;

        Vector3 lbPos = worldPos[0];
        Vector3 rtPos = worldPos[2];

        //获取其所在的Canvas
        Canvas canvas = GetComponentInParent<Canvas>();
        RectTransform rectTransCanvas = canvas.GetComponent<RectTransform>();

        //世界转屏幕
        lbPos = Camera.main.WorldToScreenPoint(lbPos);
        //屏幕转Canvas本地坐标点, 若不正确可将第三参数置null
        //Vector2 localLbPos;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransCanvas, lbPos, Camera.main, out localLbPos);

        //同理
        rtPos = Camera.main.WorldToScreenPoint(rtPos);
        //Vector2 localrtPos;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransCanvas, rtPos, Camera.main, out localrtPos);

        //设置Shader的裁剪区域
        //用于shader代码:UnityGet2DClipping(IN.worldPosition.xy, _CustomClipRect); //注意:IN.modelPosition是模型空间坐标
        mat.SetVector("_CustomClipRect", new Vector4(localLbPos.x, localLbPos.y, localrtPos.x, localrtPos.y));
        //以此达到裁剪目的, UnityGet2DClipping函数满足模型空间坐标在裁剪区域内就会返回1,否则返回0,可根据具体需求利用好这个返回值进行裁剪(例如乘以最终输出颜色alpha)
    }
}
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)

Shader "UI/Default123"
{
	Properties
	{
		[PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
		_Color("Tint", Color) = (1,1,1,1)

		_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
		
		[Toggle(UI_CLIP_RECT)] _UIClipRect("Use Clip Rect", Float) = 0
		[Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip("Use Alpha Clip", 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 "Default1"
			CGPROGRAM
				#pragma vertex vert
				#pragma fragment frag
				#pragma target 2.0

				#include "UnityCG.cginc"
				#include "UnityUI.cginc"
				
				#pragma multi_compile __ UI_CLIP_RECT
				#pragma multi_compile __ UNITY_UI_ALPHACLIP

				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
				};


				sampler2D _MainTex;
				fixed4 _Color;
				fixed4 _TextureSampleAdd;
				float4 _MainTex_ST;
				float4 _CustomClipRect;

				v2f vert(appdata_t v)
				{
					v2f OUT;
					UNITY_SETUP_INSTANCE_ID(v);
					UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
					OUT.worldPosition = v.vertex;
					OUT.vertex = UnityObjectToClipPos(v.vertex);

					OUT.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);

					OUT.color = v.color * _Color;
					return OUT;
				}

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

					//需激活UI_CLIP_RECT变体即可产生效果
					#ifdef UI_CLIP_RECT
					color.a *= UnityGet2DClipping(IN.worldPosition.xy, _CustomClipRect);
					#endif

					#ifdef UNITY_UI_ALPHACLIP
					clip(color.a - 0.001);
					#endif

					return color;
				}
			ENDCG
			}
		}
}

ClipTest脚本挂在被遮罩的UI身上并赋上材质(Default123着色器的材质),必须勾选上UseClipRect选项(激活变体裁剪效果生效),RectMask物体是充当遮罩区域的UI物体。

有什么问题,可以评论留言一下,基本都会回复~

猜你喜欢

转载自blog.csdn.net/qq_39574690/article/details/110201093