Unity UI跟随3D物体,世界坐标转UI坐标

Posted 真鬼123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity UI跟随3D物体,世界坐标转UI坐标相关的知识,希望对你有一定的参考价值。

1.世界坐标转屏幕坐标,再转换UI坐标

RectTransformUtility.ScreenPointToWorldPointInRectangle将一个屏幕空间点转换为 RectTransform 的本地空间中位于其矩形平面上的一个位置。

ScreenPointToWorldPointInRectangle的RectTransform参数,最好使用此UI的Canvas。这样计算的ui坐标z轴比较稳定。

cam 参数应为与此屏幕点关联的摄像机。对于设置为 Screen Space - Overlay 模式的 Canvas 中的 RectTransform,cam 参数应为 null。

//此方法的摄像机用可以看到物体的摄像机。
Vector2 screenPos = Camera.main.WorldToScreenPoint(targetObj.transform.position); 
//此方法的摄像机用UI摄像机,。
RectTransformUtility.ScreenPointToWorldPointInRectangle(rt, screenPos, Camera.main,out Vector3 outPos);
rt.position = outPos;

注意:由于基于摄像机进行了两次运算,此方法计算的结果,由于精度问题,会有一点偏差,导致ui抖动。

如写在Update或LateUpdate中,可能会随Camera移动,产生大幅抖动。卸载FixedUpdate会抖动小一些。因此我是用了第二种方法。

2.世界坐标转屏幕坐标,将屏幕坐标计算为UI的localPosition

首先还是世界坐标转换为屏幕坐标

//此方法的摄像机用可以看到物体的摄像机。
Vector2 screenPos = Camera.main.WorldToScreenPoint(targetObj.transform.position); 

屏幕坐标的原点(0,0)在左下角,右上角为(Screen.width,Screen.heigth)

UI坐标的原点(0,0)在正中心,所以我们要减去偏移量(Screen.width / 2, Screen.heigth / 2)。

考虑到UI的层级关系,需减去父物体的localPosition。

    	  screenPos.x -= Screen.width / 2;
            screenPos.y -= Screen.height / 2;
            while (rt.parent != null && rt.parent.GetComponent<Canvas>() == null)
            
                screenPos -= rt.parent.localPosition;
                rt = rt.parent;
            

再将最后得到的坐标赋值给ui。

完整代码

	//此方法的摄像机用可以看到物体的摄像机。
	Vector2 screenPos = Camera.main.WorldToScreenPoint(targetObj.transform.position); 
    screenPos.x -= Screen.width / 2;
    screenPos.y -= Screen.height / 2;
	while (rt.parent != null && rt.parent.GetComponent<Canvas>() == null)
    
            screenPos -= rt.parent.localPosition;
            rt = rt.parent;
    
    rt.position = outPos;

此方式不会造成UI抖动。

Unity世界坐标转换屏幕坐标(详解)

        我们先通过简单的操作实现一下基础的UI跟随物体移动的功能,首先我们在场景中建立一个Canvas并且添加一个图片作为按钮,之后我们添加一个3d物体作为跟随目标,效果如下图所示

        

        我们配置一下UICanvas的属性,书写对应的自定义类并添加至UI物体

         

        接下来我们书写对应的代码

using UnityEngine;

public class ClickItem : MonoBehaviour

    public GameObject target;
    public Canvas parentCanvas;

    // Update is called once per frame
    private void Update()
    
        transform.localPosition = GetScreenPosition(target.gameObject);
    

    public Vector3 GetScreenPosition(GameObject target)
    
        Vector3 viewportPos = Camera.main.WorldToViewportPoint(target.transform.position);
        RectTransform canvasRtm = parentCanvas.GetComponent<RectTransform>();
        Vector2 uguiPos = Vector2.zero;
        uguiPos.x = (viewportPos.x - 0.5f) * canvasRtm.sizeDelta.x;
        uguiPos.y = (viewportPos.y - 0.5f) * canvasRtm.sizeDelta.y;
        return uguiPos;
    

        这段代码中我们使用的是WorldToViewportPoint这个函数,WorldToViewportPoint函数在上篇文章中介绍过,屏幕左下角为(0,0),右上角为(1,1),由于我们要返回一个屏幕上的坐标,屏幕坐标是以中心点作为(0,0)点,所以我们需要再WorldToViewportPoint的返回值上再减去(0.5,0.5),得到一个-0.5到0.5之间的数值,并且将这个数值乘以屏幕的宽度和高度(屏幕的宽度和高度可以由一个全局填充的Canvas的宽高来获取)我们运行项目,可以得到下面的效果,完全符合我们的需求,我们更改Canvas的Match属性,或者将Canvas的类型改为Camera(如果要使用Camera类型,对应的Camera应该改为正交模式,UI摄像机未来会详细介绍),发现结果都是正确的(有的小伙伴将Canvas类型改为Camera之后,发现图标不见了,这是因为改为Camera之后,UI就不会在最上层显示,会和其他物体按照position的Z值进行前后关系的遮挡)

       现在我们测试一下另一个函数WorldToScreenPoint,WorldToScreenPoint是以屏幕的左下角为(0,0),右上角为(Screen.width, Screen.height),想要获取当前屏幕UI的真实的宽度和高度,接着对函数获取的x值和y值,根据宽高与屏幕宽度高度的比值进行处理,计算出最后的结果,具体代码如下

    public Vector3 GetScreenPosition(GameObject target)
    
        RectTransform canvasRtm = parentCanvas.GetComponent<RectTransform>();
        float width = canvasRtm.sizeDelta.x;
        float height = canvasRtm.sizeDelta.y;
        Vector3 pos = Camera.main.WorldToScreenPoint(target.transform.position);
        pos.x *= width / Screen.width;
        pos.y *= height / Screen.height;
        pos.x -= width * 0.5f;
        pos.y -= height * 0.5f;
        return pos;
    

 下一篇我们要验证我们当前写法对于Editor和安装包是否都可以使用(Up上一期写的有一些问题,一些旧的写法比较麻烦,所以更新了一下代码,下一章会说一下当时犯的错误,大家一起进步😂)

 贴一下其余几篇文章,方便大家阅读。

Unity世界坐标转换屏幕坐标(概览)_Unity鼓励师的博客-CSDN博客

Unity世界坐标转换屏幕坐标(测试)_Unity鼓励师的博客-CSDN博客

以上是关于Unity UI跟随3D物体,世界坐标转UI坐标的主要内容,如果未能解决你的问题,请参考以下文章

unity UGUI跟随3D物体的坐标转换

unity中UI坐标转3d世界坐标

unity制作血条怎么一点一点加血

unity怎么设置物体坐标?

unity碰到物体血条减少

查找 Unity UI 元素的世界空间坐标