Unity3D coordinates and UI coordinate conversion are too different

In the Render Mode of UI Canvas, it is Screen Space-Camera mode. It is extremely easy to make errors in converting 3D coordinate values ​​to UI coordinates.
**The specific reason is: **Canvas's Rect Transform is locked, and its Scale multiple value is not 1, so problems will occur when converting from 3D coordinate values ​​to UI coordinates.
Correct approach:

      1、 声明变量: 3D物体、 UI的RectTransform、 Canvas的RectTransform、 Canvas所使用的Camera
      2、将物体的世界坐标转换为Canvas内的局部坐标
      3、设置UI元素的位置为Canvas内的局部坐标

Code:

public class TitileMove : MonoBehaviour
{
    
    
    // 3D物体
    public Transform object3D;

    // UI Image的RectTransform
    public RectTransform uiImageRectTransform;

    // Canvas的RectTransform
    public RectTransform canvasRectTransform;

    // Canvas所使用的Camera
    public Camera canvasCamera;
    public GameObject lastSelectedObject;
    private bool isDragging = false;
    private bool isRotating = false;

    private Vector3 lastMousePosition;
    private void OnBecameInvisible()
    {
    
    
        // 当物体不可见时,隐藏UI元素
        uiImageRectTransform.gameObject.SetActive(false);
    }

    void Update()
    {
    
    
        // 如果鼠标左键按下
        if (Input.GetMouseButtonDown(0))
        {
    
    
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;

            // 射线检测是否点击到物体
            if (Physics.Raycast(ray, out hit))
            {
    
    
                GameObject selectedObject = hit.collider.gameObject;

                // 判断是否点击到了我们想要拖拽的物体
                if (selectedObject.transform.name == "3")
                {
    
    
                    uiImageRectTransform.gameObject.SetActive(true);
                    // 开始拖拽
                    // 将物体的世界坐标转换为Canvas内的局部坐标
                    Vector2 localPos;
                    RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRectTransform, Camera.main.WorldToScreenPoint(selectedObject.transform.position), canvasCamera, out localPos);

                    // 设置UI元素的位置为Canvas内的局部坐标
                    localPos = new Vector2(localPos.x - 249, localPos.y + 70);
                    uiImageRectTransform.localPosition = localPos;
                    lastSelectedObject = selectedObject;
                    Vector3 objectPosition = selectedObject.transform.position;
                  
                    lastMousePosition = Input.mousePosition;
                }
                else
                {
    
    
                    // 隐藏UI元素
                    uiImageRectTransform.gameObject.SetActive(false);
                }
            }
            isRotating = true;
            // 检测物体是否不可见并隐藏UI元素
            if (lastSelectedObject != null && IsObjectInvisible(lastSelectedObject))
            {
    
    
                uiImageRectTransform.gameObject.SetActive(false);
            }
        }
        if (isRotating && object3D != null)
        {
    
    
            // 获取当前鼠标位置和上一帧鼠标位置之间的差值
            Vector3 deltaMouse = Input.mousePosition - lastMousePosition;

            // 根据差值来计算旋转角度
            float rotationSpeed = 0.25f; // 调整旋转速度
            float rotationY = deltaMouse.x * rotationSpeed;

            // 应用旋转
            object3D.transform.Rotate(Vector3.up, -rotationY, Space.World);

            // 更新上一帧鼠标位置
            lastMousePosition = Input.mousePosition;
            if (uiImageRectTransform != null)
            {
    
    
              //  uiImageRectTransform.GetComponent<RectTransform>().anchoredPosition = new Vector2(uiImageRectTransform.GetComponent<RectTransform>().anchoredPosition.x + deltaMouse.x, uiImageRectTransform.GetComponent<RectTransform>().anchoredPosition.y);
           

                // 将物体的世界坐标转换为屏幕坐标
                Vector2 screenPos = RectTransformUtility.WorldToScreenPoint(null, uiImageRectTransform.position);

                // 将屏幕坐标转换为Canvas内的局部坐标
                RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRectTransform, screenPos, null, out Vector2 localPos);


                localPos = new Vector2(localPos.x + deltaMouse.x, localPos.y);
                // 设置物体的局部坐标
                uiImageRectTransform.anchoredPosition = localPos;


            }

        }
        // 如果鼠标左键释放
        if (Input.GetMouseButtonUp(0))
        {
    
    
            isRotating = false;
        
        }

       
    }
    // 检测物体是否不可见
    private bool IsObjectInvisible(GameObject obj)
    {
    
    
        // 获取物体的包围盒
        Bounds bounds = obj.GetComponent<Renderer>().bounds;

        // 获取摄像机的视锥体平面
        Plane[] frustumPlanes = GeometryUtility.CalculateFrustumPlanes(Camera.main);

        // 检查包围盒是否与视锥体相交
        return !GeometryUtility.TestPlanesAABB(frustumPlanes, bounds);
    }


    // 检测物体是否被遮挡
    private bool IsObjectOccluded(GameObject obj)
    {
    
    
        // 获取摄像机到物体的方向
        Vector3 directionToTarget = obj.transform.position - Camera.main.transform.position;

        // 发射射线
        Ray ray = new Ray(Camera.main.transform.position, directionToTarget);
        RaycastHit hit;

        // 射线检测是否有其他碰撞器位于射线路径上
        if (Physics.Raycast(ray, out hit, directionToTarget.magnitude))
        {
    
    
            // 如果射线击中的物体不是目标物体,则表示目标物体被遮挡
            if (hit.collider.gameObject != obj)
            {
    
    
                return true;
            }
        }

        return false;
    }
}

focus

// 将物体的世界坐标转换为Canvas内的局部坐标
                Vector2 localPos;
                RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRectTransform, Camera.main.WorldToScreenPoint(selectedObject.transform.position), canvasCamera, out localPos);

                // 设置UI元素的位置为Canvas内的局部坐标
                localPos = new Vector2(localPos.x - 249, localPos.y + 70);
                uiImageRectTransform.localPosition = localPos;

Guess you like

Origin blog.csdn.net/weixin_44047050/article/details/131992502