NLDClient-yudde/ProjectNLD/Assets/Code/Scripts/UI/Tween/UICustomBoundsFade.cs

102 lines
4.0 KiB
C#
Raw Normal View History

2026-03-09 16:26:18 +08:00
// UICustomBoundsFade.cs
// 挂在使用 UI/Default-Gama shader 的 Graphic 对象上。
// 指定一个目标 RectTransform每帧将其世界坐标四角范围同步到 _CustomFadeRect。
// 当前 Graphic 会在该范围内渐变,边缘外完全透明。
using UnityEngine;
using UnityEngine.UI;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace NLD.UI
{
[RequireComponent(typeof(Graphic))]
[DisallowMultipleComponent]
public class UICustomBoundsFade : MonoBehaviour
{
2026-03-09 17:22:35 +08:00
[Tooltip("使用 UI-Default-Gama shader 的基础材质(必须指定,否则脚本不生效)")]
[SerializeField] private Material _baseMaterial;
2026-03-09 16:26:18 +08:00
[Tooltip("目标 GameObject 的 RectTransform渐变范围以其世界坐标四角为准")]
public RectTransform targetRect;
2026-03-09 17:22:35 +08:00
[Tooltip("渐变过渡宽度UV 分数0 = 硬切边界0.5 = 渐变延伸到 bounds 中心。与 bounds 物理尺寸无关")]
[Range(0f, 0.5f)]
public float softness = 0.1f;
2026-03-09 16:26:18 +08:00
[Tooltip("渐变曲线指数1 = 线性,>1 慢起快收,<1 快起慢收")]
[Range(0.1f, 5f)]
public float curve = 1f;
// ── 内部状态 ──────────────────────────────────────────────────
private Graphic _graphic;
private Material _materialInstance;
private static readonly int _propRect = Shader.PropertyToID("_CustomFadeRect");
private static readonly int _propSoftness = Shader.PropertyToID("_CustomFadeSoftness");
private static readonly int _propCurve = Shader.PropertyToID("_CustomFadeCurve");
private const string _keyword = "USE_CUSTOM_BOUNDS_FADE";
// ── 生命周期 ──────────────────────────────────────────────────
private void OnEnable()
{
_graphic = GetComponent<Graphic>();
if (_graphic == null) return;
2026-03-09 17:22:35 +08:00
// 优先使用指定的 Gama 基础材质,否则回退到 Graphic 当前材质
Material original = _baseMaterial != null ? _baseMaterial : _graphic.material;
2026-03-09 16:26:18 +08:00
_materialInstance = new Material(original)
{
name = original.name + "_CustomBoundsFade"
};
_materialInstance.EnableKeyword(_keyword);
_graphic.material = _materialInstance;
SyncToMaterial();
}
private void OnDisable()
{
if (_graphic != null)
_graphic.material = null; // 置 null 即回退到 defaultMaterial
if (_materialInstance != null)
{
DestroyImmediate(_materialInstance);
_materialInstance = null;
}
}
private void LateUpdate() => SyncToMaterial();
// ── 核心同步 ──────────────────────────────────────────────────
private void SyncToMaterial()
{
if (_materialInstance == null || targetRect == null) return;
// GetWorldCorners: [0]=BL [1]=TL [2]=TR [3]=BR
var corners = new Vector3[4];
targetRect.GetWorldCorners(corners);
float xMin = corners[0].x;
float yMin = corners[0].y;
float xMax = corners[2].x;
float yMax = corners[2].y;
_materialInstance.SetVector(_propRect, new Vector4(xMin, yMin, xMax, yMax));
_materialInstance.SetFloat (_propSoftness, softness);
_materialInstance.SetFloat (_propCurve, curve);
}
#if UNITY_EDITOR
// Editor 下实时预览OnValidate 在 inspector 改值时调用)
private void OnValidate()
{
if (!Application.isPlaying && _materialInstance != null)
SyncToMaterial();
}
#endif
}
}