【Unity3D】实现UGUI高亮引导点击

Unity版本2019.4.0f1 Personal <DX11>

cs 复制代码
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));
    }
}
cs 复制代码
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
        }
    }
}
相关推荐
董董灿是个攻城狮4 小时前
AI视觉连载8:传统 CV 之边缘检测
算法
AI软著研究员11 小时前
程序员必看:软著不是“面子工程”,是代码的“法律保险”
算法
FunnySaltyFish12 小时前
什么?Compose 把 GapBuffer 换成了 LinkBuffer?
算法·kotlin·android jetpack
颜酱13 小时前
理解二叉树最近公共祖先(LCA):从基础到变种解析
javascript·后端·算法
地平线开发者1 天前
SparseDrive 模型导出与性能优化实战
算法·自动驾驶
董董灿是个攻城狮1 天前
大模型连载2:初步认识 tokenizer 的过程
算法
地平线开发者1 天前
地平线 VP 接口工程实践(一):hbVPRoiResize 接口功能、使用约束与典型问题总结
算法·自动驾驶
罗西的思考1 天前
AI Agent框架探秘:拆解 OpenHands(10)--- Runtime
人工智能·算法·机器学习
HXhlx1 天前
CART决策树基本原理
算法·机器学习
Wect1 天前
LeetCode 210. 课程表 II 题解:Kahn算法+DFS 双解法精讲
前端·算法·typescript