From 994cda07491be0e460c78bd9c8400780530ad07c Mon Sep 17 00:00:00 2001
From: hch <305670599@qq.com>
Date: 星期五, 07 十一月 2025 16:42:32 +0800
Subject: [PATCH] 0312 增加椭圆形遮罩
---
Main/Component/UI/Effect/EllipseMask.cs.meta | 11 +
Main/Component/UI/Effect/EllipseMask.cs | 307 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 318 insertions(+), 0 deletions(-)
diff --git a/Main/Component/UI/Effect/EllipseMask.cs b/Main/Component/UI/Effect/EllipseMask.cs
new file mode 100644
index 0000000..b12ec51
--- /dev/null
+++ b/Main/Component/UI/Effect/EllipseMask.cs
@@ -0,0 +1,307 @@
+using UnityEngine;
+using UnityEngine.UI;
+using System.Collections.Generic;
+
+/// <summary>
+/// 妞渾褰㈤伄缃╃粍浠�
+/// 鍩轰簬妯℃澘娴嬭瘯瀹炵幇妞渾褰㈤伄缃╂晥鏋�
+/// </summary>
+[RequireComponent(typeof(RectTransform))]
+[AddComponentMenu("UI/Effects/Ellipse Mask")]
+[ExecuteInEditMode]
+public class EllipseMask : MonoBehaviour
+{
+ [Header("妞渾鍙傛暟")]
+ [SerializeField] private Vector2 m_EllipseCenter = new Vector2(0.5f, 0.5f);
+ [SerializeField] private Vector2 m_EllipseRadius = new Vector2(0.5f, 0.5f);
+ [SerializeField] [Range(0, 0.5f)] private float m_Softness = 0f; //鏆傛棤鏁堟灉
+ [SerializeField] private int m_StencilID = 1; //澶氫釜閬僵鏃�
+ [SerializeField] private bool m_ShowMaskGraphic = false;
+
+ private Material m_MaskMaterial;
+ private Image m_MaskImage;
+ private RectTransform m_RectTransform;
+ private List<Graphic> m_MaskedChildren = new List<Graphic>();
+
+ public Vector2 EllipseCenter
+ {
+ get => m_EllipseCenter;
+ set
+ {
+ if (m_EllipseCenter != value)
+ {
+ m_EllipseCenter = value;
+ UpdateMask();
+ }
+ }
+ }
+
+ public Vector2 EllipseRadius
+ {
+ get => m_EllipseRadius;
+ set
+ {
+ if (m_EllipseRadius != value)
+ {
+ m_EllipseRadius = value;
+ UpdateMask();
+ }
+ }
+ }
+
+ public float Softness
+ {
+ get => m_Softness;
+ set
+ {
+ if (m_Softness != value)
+ {
+ m_Softness = Mathf.Clamp(value, 0, 0.5f);
+ UpdateMask();
+ }
+ }
+ }
+
+ public int StencilID
+ {
+ get => m_StencilID;
+ set
+ {
+ if (m_StencilID != value)
+ {
+ m_StencilID = value;
+ UpdateMask();
+ UpdateChildrenStencil();
+ }
+ }
+ }
+
+ public bool ShowMaskGraphic
+ {
+ get => m_ShowMaskGraphic;
+ set
+ {
+ if (m_ShowMaskGraphic != value)
+ {
+ m_ShowMaskGraphic = value;
+ UpdateMaskVisibility();
+ }
+ }
+ }
+
+ protected virtual void Awake()
+ {
+ m_RectTransform = GetComponent<RectTransform>();
+
+ // 鍒涘缓閬僵鍥惧儚
+ CreateMaskImage();
+
+ // 鍒涘缓閬僵鏉愯川
+ CreateMaskMaterial();
+
+ UpdateMask();
+ }
+
+ protected virtual void OnEnable()
+ {
+ CreateMaskMaterial();
+ UpdateMask();
+
+ // 涓烘墍鏈夊瓙瀵硅薄娣诲姞妯℃澘娴嬭瘯
+ UpdateChildrenStencil();
+ }
+
+ protected virtual void OnDisable()
+ {
+ if (m_MaskMaterial != null)
+ {
+ DestroyImmediate(m_MaskMaterial);
+ m_MaskMaterial = null;
+ }
+
+ // 绉婚櫎瀛愬璞$殑妯℃澘娴嬭瘯
+ RemoveChildrenStencil();
+ }
+
+ protected virtual void OnDestroy()
+ {
+ if (m_MaskMaterial != null)
+ {
+ DestroyImmediate(m_MaskMaterial);
+ }
+ }
+
+ /// <summary>
+ /// 鍒涘缓閬僵鍥惧儚
+ /// </summary>
+ private void CreateMaskImage()
+ {
+ if (m_MaskImage == null)
+ {
+ m_MaskImage = GetComponent<Image>();
+ if (m_MaskImage == null)
+ {
+ m_MaskImage = gameObject.AddComponent<Image>();
+ m_MaskImage.color = Color.white;
+ }
+ }
+ }
+
+ /// <summary>
+ /// 鍒涘缓閬僵鏉愯川
+ /// </summary>
+ private void CreateMaskMaterial()
+ {
+ if (m_MaskMaterial == null)
+ {
+ Shader ellipseShader = Shader.Find("GUI/EllipseMask");
+ if (ellipseShader != null)
+ {
+ m_MaskMaterial = new Material(ellipseShader);
+ }
+ else
+ {
+ Debug.LogError("EllipseMask shader not found!");
+ }
+ }
+ }
+
+ /// <summary>
+ /// 鏇存柊閬僵
+ /// </summary>
+ private void UpdateMask()
+ {
+ if (m_MaskMaterial != null && m_MaskImage != null)
+ {
+ UpdateMaterialProperties();
+
+ // 璁剧疆鏉愯川鍒癐mage
+ m_MaskImage.material = m_MaskMaterial;
+
+ // 寮哄埗閲嶇粯
+ m_MaskImage.SetMaterialDirty();
+ }
+ }
+
+ /// <summary>
+ /// 鏇存柊鏉愯川灞炴��
+ /// </summary>
+ private void UpdateMaterialProperties()
+ {
+ if (m_MaskMaterial != null)
+ {
+ m_MaskMaterial.SetVector("_EllipseCenter", new Vector4(m_EllipseCenter.x, m_EllipseCenter.y, 0, 0));
+ m_MaskMaterial.SetVector("_EllipseRadius", new Vector4(m_EllipseRadius.x, m_EllipseRadius.y, 0, 0));
+ m_MaskMaterial.SetFloat("_Softness", m_Softness);
+ m_MaskMaterial.SetInt("_Stencil", m_StencilID);
+ }
+ }
+
+ /// <summary>
+ /// 鏇存柊閬僵鍙鎬�
+ /// </summary>
+ private void UpdateMaskVisibility()
+ {
+ if (m_MaskImage != null)
+ {
+ m_MaskImage.enabled = m_ShowMaskGraphic;
+ }
+ }
+
+ /// <summary>
+ /// 涓哄瓙瀵硅薄娣诲姞妯℃澘娴嬭瘯
+ /// </summary>
+ private void UpdateChildrenStencil()
+ {
+ // 娓呴櫎涔嬪墠鐨勫垪琛�
+ m_MaskedChildren.Clear();
+
+ // 鑾峰彇鎵�鏈夊瓙瀵硅薄鐨凣raphic缁勪欢
+ Graphic[] childrenGraphics = GetComponentsInChildren<Graphic>();
+ foreach (var graphic in childrenGraphics)
+ {
+ // 璺宠繃閬僵鏈韩
+ if (graphic.gameObject == this.gameObject)
+ continue;
+
+ // 涓哄瓙瀵硅薄鍒涘缓閬僵鏉愯川
+ CreateChildMaskMaterial(graphic);
+ m_MaskedChildren.Add(graphic);
+ }
+ }
+
+ /// <summary>
+ /// 涓哄瓙瀵硅薄鍒涘缓閬僵鏉愯川
+ /// </summary>
+ private void CreateChildMaskMaterial(Graphic graphic)
+ {
+ if (graphic.material == null || !graphic.material.shader.name.Contains("EllipseMaskedContent"))
+ {
+ Shader maskedShader = Shader.Find("GUI/EllipseMaskedContent");
+ if (maskedShader != null)
+ {
+ Material maskedMaterial = new Material(maskedShader);
+ maskedMaterial.SetInt("_Stencil", m_StencilID);
+ maskedMaterial.SetInt("_StencilComp", 3); // Equal
+ graphic.material = maskedMaterial;
+ }
+ }
+ else
+ {
+ // 鏇存柊鐜版湁鏉愯川鐨勬ā鏉縄D
+ graphic.material.SetInt("_Stencil", m_StencilID);
+ }
+ }
+
+ /// <summary>
+ /// 绉婚櫎瀛愬璞$殑妯℃澘娴嬭瘯
+ /// </summary>
+ private void RemoveChildrenStencil()
+ {
+ foreach (var graphic in m_MaskedChildren)
+ {
+ if (graphic != null && graphic.material != null)
+ {
+ // 閲嶇疆鏉愯川
+ graphic.material = null;
+ }
+ }
+ m_MaskedChildren.Clear();
+ }
+
+ /// <summary>
+ /// 璁剧疆妞渾鍙傛暟
+ /// </summary>
+ /// <param name="center">妞渾涓績锛堝綊涓�鍖栧潗鏍囷級</param>
+ /// <param name="radius">妞渾鍗婂緞锛堝綊涓�鍖栧潗鏍囷級</param>
+ /// <param name="softness">杈圭紭鏌斿寲绋嬪害</param>
+ public void SetEllipseParameters(Vector2 center, Vector2 radius, float softness = 0.1f)
+ {
+ m_EllipseCenter = center;
+ m_EllipseRadius = radius;
+ m_Softness = Mathf.Clamp(softness, 0, 0.5f);
+ UpdateMask();
+ }
+
+ /// <summary>
+ /// 璁剧疆鍦嗗舰鍙傛暟锛堢壒娈婃儏鍐电殑妞渾锛�
+ /// </summary>
+ /// <param name="center">鍦嗗績锛堝綊涓�鍖栧潗鏍囷級</param>
+ /// <param name="radius">鍗婂緞锛堝綊涓�鍖栧潗鏍囷級</param>
+ /// <param name="softness">杈圭紭鏌斿寲绋嬪害</param>
+ public void SetCircleParameters(Vector2 center, float radius, float softness = 0.1f)
+ {
+ SetEllipseParameters(center, new Vector2(radius, radius), softness);
+ }
+
+#if UNITY_EDITOR
+ protected virtual void OnValidate()
+ {
+ if (m_MaskMaterial != null)
+ {
+ UpdateMaterialProperties();
+ UpdateChildrenStencil();
+ }
+ }
+#endif
+}
\ No newline at end of file
diff --git a/Main/Component/UI/Effect/EllipseMask.cs.meta b/Main/Component/UI/Effect/EllipseMask.cs.meta
new file mode 100644
index 0000000..3252759
--- /dev/null
+++ b/Main/Component/UI/Effect/EllipseMask.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d7b138cff435daf4e97efe03e10a756b
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
--
Gitblit v1.8.0