Unity版本2019.4.0f1 Personal <DX11>
using UnityEngine;
using UnityEngine.UI;
public class GuideMask : MonoBehaviour, ICanvasRaycastFilter
{
public Canvas canvas;
public Transform guideTargetTrans;
public Image image;
private Vector3 guideTargetWorldPos;
private Vector2 lbPos;
private Vector2 rtPos;
private Rect rect;
/// <summary>
/// ICanvasRaycastFilter接口所实现的方法
/// </summary>
/// <param name="sp"></param>
/// <param name="eventCamera"></param>
/// <returns></returns>
public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
{
//sp位于屏幕坐标系,(0,0)位于屏幕左下角
//rect是基于UGUI坐标构建的矩形,UGUI坐标系(0,0)位于屏幕中心, 因此将sp减去一半屏幕宽高得到以屏幕中心为中心点的点
//简单理解就是sp的中心点是(Screen.width / 2, Screen.height / 2), 实际rect矩形所在坐标系的中心点是(0,0) 故需减去(Screen.width / 2, Screen.height / 2)还原回以(0,0)作为中心点
//若不转化,不位于同一个坐标系的点和矩形无法进行计算是否处于矩形内。
Vector2 offsetSp = sp - new Vector2(Screen.width / 2, Screen.height / 2);
return rect.Contains(offsetSp) ? false : true; //位于矩形内返回false 代表穿透射线, 否则返回true代表正常接收射线
//穿透射线是指让这个引导黑幕的矩形区域内的射线检测raycast无效化,射线穿透到下一层UGUI 让它下层UI响应点击。
}
// Start is called before the first frame update
void Start()
{
guideTargetWorldPos = guideTargetTrans.position;
//世界转屏幕点
Vector3 pos = Camera.main.WorldToScreenPoint(guideTargetWorldPos);
//屏幕点转UGUI坐标系点
Vector2 localPoint;
RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.GetComponent<RectTransform>(), pos, Camera.main, out localPoint);
lbPos = new Vector2(localPoint.x - 250, localPoint.y - 100);
rtPos = new Vector2(localPoint.x + 250, localPoint.y + 100);
//注意:Rect原点是左下角,故需偏移localPoint到左下角传入第一个参数, 第二个参数是Size(矩形右上角是原点左下角+Size得到)
rect = new Rect(localPoint - new Vector2(250, 100), new Vector2(500, 200));
Material mat = image.material;
mat.SetVector("_CustomClipRect", new Vector4(lbPos.x, lbPos.y, rtPos.x, rtPos.y));
}
}
Shader "Hidden/GuideImageEffectShader"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_CustomClipRect("CustomClipRect", vector) = (0,0,0,0)
}
SubShader
{
// No culling or depth
Cull Off ZWrite Off ZTest Always
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "UnityUI.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 screenPosition : TEXCOORD1;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.screenPosition = v.vertex;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
float4 _CustomClipRect;
fixed4 _Color;
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = _Color;
col.a *= (1 - UnityGet2DClipping(i.screenPosition.xy, _CustomClipRect));
return col;
}
ENDCG
}
}
}