Camera.ScreenPointToRay用法

var ray = Camera.ScreenPointToRay(screenPos);

1) screenPos需要是左下角为(0, 0), 单位为像素的屏幕坐标。

2) 得到的射线的开始为屏幕坐标在相机near平面上的点, 指向屏幕坐标在far平面上的点

 

在游戏代码中使用

using UnityEngine;

public class TestCameraRay : MonoBehaviour
{
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            var cam = Camera.main;
            if (cam)
            {
                var screenPos = Input.mousePosition;

                var ray = cam.ScreenPointToRay(screenPos);
                var v1 = ray.origin;
                var v2 = v1 + ray.direction * 60;
                Debug.Log($"ray: {ray}, {v2}");
                Debug.DrawLine(v1, v2, Color.red, 5);

                screenPos.z = -cam.transform.position.z; //如果用0得到的将是相机的z值
                var worldPos = cam.ScreenToWorldPoint(screenPos); //z=camWorldPos.z+screenPos.z, 所以将得到z值在0处的世界坐标
                Debug.Log($"screen:{screenPos} -> world:{worldPos}");
                Debug.DrawLine(v1, worldPos, Color.blue, 5);
            }
        }
    }
}

效果

 

在编辑器代码中使用,会用到 HandleUtility.GUIPointToWorldRay(mousePos);

实际也是调用Camera.ScreenPointToRay

public class TestCameraRay : MonoBehaviour
{
    public Camera m_SceneCam;
    
    private void OnDrawGizmos()
    {
        var curEvent = Event.current;
        if (curEvent.isMouse)
        {
            var cam = Camera.current;
            if (cam)
            {
                var sceneCam = SceneView.currentDrawingSceneView.camera;
                if (cam == sceneCam)
                    Debug.Log($"cam equals");

                var ray = HandleUtility.GUIPointToWorldRay(curEvent.mousePosition);
                var v1 = ray.origin;
                var v2 = v1 + ray.direction * 999;
                Debug.Log($"ray: {ray}, {v2}");
                Debug.DrawLine(v1, v2, Color.blue, 10);

                Vector3 screenPos = HandleUtility.GUIPointToScreenPixelCoordinate(curEvent.mousePosition); //转换成像素单位以及左下角(0, 0)
                screenPos.z = -cam.transform.position.z;
                var worldPos = cam.ScreenToWorldPoint(screenPos); //z=camWorldPos.z+screenPos.z, 所以将得到z值在0处的世界坐标
                Debug.Log($"mousePos:{curEvent.mousePosition} -> screen:{screenPos} -> world:{worldPos}");
                //Debug.DrawLine(v1, worldPos, Color.blue, 5);

                if (m_SceneCam) //把场景相机显示出来, 不然没法看到场景相机
                {
                    var tempCamTf = m_SceneCam.transform;
                    tempCamTf.position = camTf.position;
                    tempCamTf.forward = camTf.forward;
                    m_SceneCam.orthographic = cam.orthographic;
                    m_SceneCam.fieldOfView = cam.fieldOfView;
                    m_SceneCam.orthographicSize = cam.orthographicSize;
                    m_SceneCam.nearClipPlane = cam.nearClipPlane;
                    m_SceneCam.farClipPlane = cam.farClipPlane;
                }
            }
        }
    }

}

效果

 

一些API的用法

游戏代码中使用:
Input.mousePosition: 拿到的是游戏窗口的屏幕坐标, 左下角为(0, 0), 右上角为游戏窗口宽高, 单位为像素
Event.PopEvent(evt).mousePosition: 拿到的是游戏窗口的屏幕坐标, 左上角为(0, 0), , 右上角为游戏窗口宽高, 单位为像素

编辑器代码中使用:
EditorGUIUtility.pixelsPerPoint: win10将显示设置中的缩放设置为125%时, 值为1.25; 设置为100%时, 值为1.0
Event.current.mousePosition: 拿到的是Scene窗口的屏幕坐标, 左上角为(0, 0), 右上角为Scene窗口宽高, 单位为点数, 要转pixel的需乘EditorGUIUtility.pixelsPerPoint

均可使用:
Screen.width, Screen.height: 在游戏代码中拿到的是游戏窗口的大小, 在编辑器代码中拿到的是Scene窗口的大小, 单位为像素
Screen.dpi: win10将显示设置中的缩放设置为125%时, 值为120; 设置为100%时, 值为96

 

参考 

Unity编辑器/运行时屏幕坐标转世界坐标问题 - 哔哩哔哩 (bilibili.com)

Unity SceneView 鼠标转世界坐标 - 【Winco】 - 博客园 (cnblogs.com)

 

posted @ 2023-10-19 00:35  yanghui01  阅读(175)  评论(0编辑  收藏  举报