Unity點擊RawImage獲取RenderTexture的映射物體

1、需要射線檢測的物體先加個collider組件,方便射線檢測到

2、第一種方式通過獲取點擊UI界面的UI座標A,將A轉換爲RawImage的相對座標B,再將B轉爲映射相機的視口(Viewport)座標C,然後在映射相機發射射線對穿過的物體進行檢測

    代碼如下:


using UnityEngine;
using UnityEngine.UI;

public class TestRenderTexture : MonoBehaviour
{
    // 點擊RawImage時,相對RawImage自身的座標
    private Vector2 ClickPosInRawImg;
    // 畫布
    public Canvas Canvas;
    // 預覽映射相機
    public Camera PreviewCamera;
    public RawImage PreviewImage;
    public Camera UiCamera;
    private Vector3 MousePos;

    void Start(){}

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            MousePos = Input.mousePosition;
        }
        if (MousePos != null)
        {
            CheckDrawRayLine(Canvas, Input.mousePosition, PreviewImage, PreviewCamera);
        }
    }

    /// <summary>
    /// 射線投射
    /// </summary>
    /// <param name="canvas">畫布</param>
    /// <param name="mousePosition">當前Canvas下點擊的鼠標位置</param>
    /// <param name="previewImage">預覽圖</param>
    /// <param name="previewCamera">預覽映射圖的攝像機</param>
    void CheckDrawRayLine(Canvas canvas, Vector3 mousePosition, RawImage previewImage, Camera previewCamera)
    {
        // 將UI相機下點擊的UI座標轉爲相對RawImage的座標
        if (RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transform as RectTransform, mousePosition, UiCamera, out ClickPosInRawImg))
        {
            // Lylibs.MessageUtil.Show("座標:x=" + ClickPosInRawImg.x + ",y=" + ClickPosInRawImg.y);

            //獲取預覽圖的長寬
            float imageWidth = previewImage.rectTransform.rect.width;
            float imageHeight = previewImage.rectTransform.rect.height;
            //獲取預覽圖的座標,此處RawImage的Pivot需爲(0,0),不然自己再換算下
            float localPositionX = previewImage.rectTransform.localPosition.x;
            float localPositionY = previewImage.rectTransform.localPosition.y;

            //獲取在預覽映射相機viewport內的座標(座標比例)
            float p_x = (ClickPosInRawImg.x - localPositionX) / imageWidth;
            float p_y = (ClickPosInRawImg.y - localPositionY) / imageHeight;

            //從視口座標發射線
            Ray p_ray = previewCamera.ViewportPointToRay(new Vector2(p_x, p_y));
            RaycastHit p_hitInfo;
            if (Physics.Raycast(p_ray, out p_hitInfo))
            {
                //顯示射線,只有在scene視圖中才能看到
                Debug.DrawLine(p_ray.origin, p_hitInfo.point);
                // Debug.Log(p_hitInfo.transform.name);
            }
        }
    }
}

3、第二種方式直接寫個繼承RawImage的類A,在A裏直接通過監聽RawImage的點擊事件獲取相對RawImage的點擊座標B,將A轉換爲RawImage的相對座標B,再將B轉爲映射相機的視口(Viewport)座標C,然後在映射相機發射射線對穿過的物體進行檢測,感覺比第一種方便些

代碼如下:


using System;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace Lylibs
{
    public class LyRawImage : RawImage, IPointerClickHandler
    {
        // 點擊RawImage時,相對RawImage自身的座標
        private Vector2 ClickPosInRawImg;
        // 預覽映射相機
        private Camera PreviewCamera;
        private XLua.LuaTable ObjTable;
        private Action<XLua.LuaTable, Vector2, Transform> CallFun = null;

        void Start()
        {
            // 初始獲取預覽映射相機
            if (PreviewCamera == null)
            {
                PreviewCamera = GameObject.Find("[CAMERAs]").transform.Find("[RENDER_TEXTURE_CAMERA]").GetComponent<Camera>();
            }
        }

        void Update()
        {
#if UNITY_EDITOR
            CheckDrawRayLine(false);
#endif
        }

        void IPointerClickHandler.OnPointerClick(PointerEventData eventData)
        {
            // 獲取相對RawImage的點擊座標
            if (RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, eventData.position, eventData.pressEventCamera, out ClickPosInRawImg))
            {
                // Lylibs.MessageUtil.Show("座標:x=" + ClickPosInRawImg.x + ",y=" + ClickPosInRawImg.y);
                CheckDrawRayLine(true);
            }
        }

        // 檢查是否需要繪製射線
        void CheckDrawRayLine(bool isCallBack)
        {
            if (PreviewCamera != null && ClickPosInRawImg != null)
            {
                //獲取預覽圖的長寬
                float p_imageWidth = rectTransform.rect.width;
                float p_imageHeight = rectTransform.rect.height;
                //獲取預覽圖的座標
                float p_localPositionX = rectTransform.localPosition.x;
                float p_localPositionY = rectTransform.localPosition.y;

                //獲取在預覽映射相機viewport內的座標(座標比例)
                float p_x = ClickPosInRawImg.x / p_imageWidth;
                float p_y = ClickPosInRawImg.y / p_imageHeight;

                //從預覽映射相機視口座標發射線
                Ray ray = PreviewCamera.ViewportPointToRay(new Vector2(p_x, p_y));
                RaycastHit hitInfo;
                if (Physics.Raycast(ray, out hitInfo))
                {
                    //顯示射線,只有在scene視圖中才能看到
                    Debug.DrawLine(ray.origin, hitInfo.point);
                    // Debug.Log(hitInfo.transform.name);

                    if (isCallBack == true && ObjTable != null && CallFun != null)
                    {
                        CallFun(ObjTable, ClickPosInRawImg, hitInfo.transform);
                    }
                }
            }
        }

        public void SetEventCall(XLua.LuaTable table, Action<XLua.LuaTable, Vector2, Transform> call)
        {
            ObjTable = table;
            CallFun = call;
        }
    }
}

4、此種實現諸如如下的效果方便:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章