[Shader case] Implement UGUI cropping function

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

The ClipTest script is hung on the masked UI body and assigned a material (the material of the Default123 shader), and the UseClipRect option must be checked (the variant clipping effect is activated). The RectMask object is the UI object that serves as the masked area.

If you have any questions, you can comment and leave a message, and you will basically reply~

Guess you like

Origin blog.csdn.net/qq_39574690/article/details/110201093
Recommended