177 lines
4.5 KiB
C#
177 lines
4.5 KiB
C#
using System.Linq;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
[ExecuteInEditMode]
|
|
public class UIImageAlphaMask : MonoBehaviour
|
|
{
|
|
private Canvas canvas;
|
|
private RectTransform rectTransform;
|
|
private Image maskImage;
|
|
|
|
[SerializeField, HideInInspector]
|
|
private Image[] targetImageList;
|
|
|
|
[SerializeField, Tooltip("需要保证 mask 图边缘预留 1-2 像素空白")]
|
|
public Texture2D MaskTex;
|
|
|
|
private Canvas RootCanvas
|
|
{
|
|
get
|
|
{
|
|
if (canvas == null)
|
|
{
|
|
var canvas = GetComponentInParent<Canvas>();
|
|
if (canvas != null)
|
|
{
|
|
if (canvas.rootCanvas != null)
|
|
{
|
|
this.canvas = canvas.rootCanvas;
|
|
}
|
|
else
|
|
{
|
|
this.canvas = canvas;
|
|
}
|
|
}
|
|
}
|
|
return canvas;
|
|
}
|
|
}
|
|
|
|
private void Awake()
|
|
{
|
|
maskImage = GetComponent<Image>();
|
|
rectTransform = GetComponent<RectTransform>();
|
|
|
|
if (targetImageList == null || targetImageList.Length <= 0)
|
|
{
|
|
targetImageList = GetComponentsInChildren<Image>(true);
|
|
targetImageList = targetImageList.Where(o => o.transform != this.transform).ToArray();
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
#if UNITY_EDITOR
|
|
if (!IsValid())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (targetImageList == null || targetImageList.Length <= 0)
|
|
{
|
|
targetImageList = GetComponentsInChildren<Image>(true);
|
|
targetImageList = targetImageList.Where(o => o.transform != this.transform).ToArray();
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
SetProperties();
|
|
}
|
|
|
|
private bool IsValid()
|
|
{
|
|
if (RootCanvas == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (RootCanvas.renderMode == RenderMode.ScreenSpaceOverlay)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if(MaskTex == null)
|
|
{
|
|
#if UNITY_EDITOR
|
|
var path = AssetDatabase.GetAssetPath(maskImage.sprite);
|
|
if(!string.IsNullOrEmpty(path))
|
|
{
|
|
MaskTex = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
|
|
}
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void SetProperties()
|
|
{
|
|
var camera = GetCamera();
|
|
if (camera == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var matrix = CalculateMatrix(camera);
|
|
for (int i = 0; i < targetImageList.Length; i++)
|
|
{
|
|
var imgMat = targetImageList[i].material;
|
|
imgMat.SetTexture("_Alpha_MaskTex", MaskTex);
|
|
imgMat.SetMatrix("_MaskMatrix", matrix);
|
|
}
|
|
}
|
|
|
|
private Camera GetCamera()
|
|
{
|
|
return RootCanvas.worldCamera;
|
|
}
|
|
|
|
private Matrix4x4 CalculateMatrix(Camera camera)
|
|
{
|
|
var rect = CalculateViewportRect(camera);
|
|
|
|
Matrix4x4 result = Matrix4x4.identity;
|
|
|
|
var halfSize = rect.size * 0.5f;
|
|
result = Matrix4x4.Ortho(
|
|
rect.center.x - halfSize.x,
|
|
rect.center.x + halfSize.x,
|
|
rect.center.y - halfSize.y,
|
|
rect.center.y + halfSize.y,
|
|
camera.nearClipPlane,
|
|
camera.farClipPlane
|
|
);
|
|
result = Matrix4x4.TRS(Vector3.one * 0.5f, Quaternion.identity, Vector3.one * 0.5f) * GL.GetGPUProjectionMatrix(result, false) * camera.worldToCameraMatrix;
|
|
return result;
|
|
}
|
|
|
|
private Rect CalculateViewportRect(Camera camera)
|
|
{
|
|
var corners = new Vector3[4];
|
|
|
|
rectTransform.GetWorldCorners(corners);
|
|
|
|
var p1 = RectTransformUtility.WorldToScreenPoint(camera, corners[1]);
|
|
var p3 = RectTransformUtility.WorldToScreenPoint(camera, corners[3]);
|
|
|
|
var x = p1.x - (Screen.width * 0.5f);
|
|
var y = p3.y - (Screen.height * 0.5f);
|
|
var width = p3.x - p1.x;
|
|
var height = p1.y - p3.y;
|
|
|
|
x /= (Screen.width * 0.5f);
|
|
width /= (Screen.width * 0.5f);
|
|
y /= (Screen.height * 0.5f);
|
|
height /= (Screen.height * 0.5f);
|
|
|
|
var size = camera.orthographicSize;
|
|
var aspect = Screen.width / (float)Screen.height;
|
|
x *= size * aspect;
|
|
width *= size * aspect;
|
|
y *= size;
|
|
height *= size;
|
|
|
|
var rect = new Rect()
|
|
{
|
|
x = x,
|
|
width = width,
|
|
y = y,
|
|
height = height
|
|
};
|
|
return rect;
|
|
}
|
|
}
|