200 lines
4.7 KiB
C#
200 lines
4.7 KiB
C#
|
|
using System.Linq;
|
||
|
|
using UnityEngine;
|
||
|
|
using UnityEngine.UI;
|
||
|
|
|
||
|
|
[ExecuteInEditMode]
|
||
|
|
[RequireComponent(typeof(Image))]
|
||
|
|
public class UIImageAlphaMask : MonoBehaviour
|
||
|
|
{
|
||
|
|
private Image m_MaskImage;
|
||
|
|
private Canvas m_Canvas;
|
||
|
|
private RectTransform m_RectTransform;
|
||
|
|
private Image[] m_TargetImageList;
|
||
|
|
private Material m_Material;
|
||
|
|
|
||
|
|
private Material Material
|
||
|
|
{
|
||
|
|
get
|
||
|
|
{
|
||
|
|
if (m_Material == null)
|
||
|
|
{
|
||
|
|
m_Material = new Material(Shader.Find("Hidden/UI/AlphaMask"));
|
||
|
|
}
|
||
|
|
return m_Material;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private Image MaskImage
|
||
|
|
{
|
||
|
|
get
|
||
|
|
{
|
||
|
|
if (m_MaskImage == null)
|
||
|
|
{
|
||
|
|
m_MaskImage = GetComponent<Image>();
|
||
|
|
}
|
||
|
|
return m_MaskImage;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private RectTransform SelfRect
|
||
|
|
{
|
||
|
|
get
|
||
|
|
{
|
||
|
|
if (m_RectTransform == null)
|
||
|
|
{
|
||
|
|
m_RectTransform = GetComponent<RectTransform>();
|
||
|
|
}
|
||
|
|
return m_RectTransform;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private Canvas RootCanvas
|
||
|
|
{
|
||
|
|
get
|
||
|
|
{
|
||
|
|
if (m_Canvas == null)
|
||
|
|
{
|
||
|
|
var canvas = GetComponentInParent<Canvas>();
|
||
|
|
if (canvas != null)
|
||
|
|
{
|
||
|
|
if (canvas.rootCanvas != null)
|
||
|
|
{
|
||
|
|
m_Canvas = canvas.rootCanvas;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
m_Canvas = canvas;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return m_Canvas;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
private void SetMaterial(Image[] imageList, Material material)
|
||
|
|
{
|
||
|
|
if (imageList == null)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i = 0; i < imageList.Length; i++)
|
||
|
|
{
|
||
|
|
var image = imageList[i];
|
||
|
|
image.material = material;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void Update()
|
||
|
|
{
|
||
|
|
if (!IsValid())
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_TargetImageList == null || m_TargetImageList.Length <= 0)
|
||
|
|
{
|
||
|
|
m_TargetImageList = GetComponentsInChildren<Image>(true);
|
||
|
|
m_TargetImageList = m_TargetImageList.Where(o => o.transform != this.transform).ToArray();
|
||
|
|
SetMaterial(m_TargetImageList, Material);
|
||
|
|
}
|
||
|
|
|
||
|
|
SetProperties();
|
||
|
|
}
|
||
|
|
|
||
|
|
private bool IsValid()
|
||
|
|
{
|
||
|
|
if (RootCanvas == null)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (RootCanvas.renderMode == RenderMode.ScreenSpaceOverlay)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (MaskImage.sprite == null)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
private void SetProperties()
|
||
|
|
{
|
||
|
|
var camera = GetCamera();
|
||
|
|
if (camera == null)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
var matrix = CalculateMatrix(camera);
|
||
|
|
|
||
|
|
Material.SetTexture("_MaskTex", MaskImage.sprite.texture);
|
||
|
|
Material.SetMatrix("_MaskMatrix", matrix);
|
||
|
|
}
|
||
|
|
|
||
|
|
private Camera GetCamera()
|
||
|
|
{
|
||
|
|
return RootCanvas.worldCamera;
|
||
|
|
}
|
||
|
|
|
||
|
|
private Matrix4x4 CalculateMatrix(Camera camera)
|
||
|
|
{
|
||
|
|
var rect = CalcurateViewportRect(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 CalcurateViewportRect(Camera camera)
|
||
|
|
{
|
||
|
|
var corners = new Vector3[4];
|
||
|
|
|
||
|
|
SelfRect.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;
|
||
|
|
}
|
||
|
|
}
|