【Unity3D】世界坐标与屏幕坐标

Unity3D由于是在三维世界中编程,而最终的结果是需要反馈到肉眼所示的2D屏幕之上的。这就产生了一种比较需要考虑的问题,尤其在一些涉及屏幕与Unity3D的3D世界交互的情况。网络上对于这方面的文字,大部分罗列了许许多多文字与代码或者API,甚至连什么视口坐标也带上了。其实在于我个人看来,关键是世界坐标与屏幕坐标之间的互转。

在Unity3D中一打开就会有一个主照相机Main Camera,根据版本不同的初始坐标会在不同的位置。拿Unity3D 4.x的(0,-1,-10)做例子,他的视距,默认是0.3~1000。


主摄像机会对外无间断的发出投影面,将投影面所截取得到的东西,通通投影到屏幕。比如下图,这是一张极其简单的图,(0,-1,-10)的主摄像机将(0,0,0)的正方体投影出来的结果。


现在这个正方体的世界坐标是(0,0,0),如果我们要获取屏幕坐标该怎么做呢?这注定需要用脚本来获取的,而且根据上面的示意图大家也可以知道,屏幕的大小的不同导致最后产生出来的屏幕坐标是不同的。因为Unity3D对屏幕坐标定义是这样的:


以下脚本展示了屏幕坐标和世界坐标的互转:

using UnityEngine;
using System.Collections;

public class CoordinateChange : MonoBehaviour
{
    void Start()
    {
        Debug.Log("屏幕宽:" + Screen.width + "高:" + Screen.height);//获取屏幕的长和宽
        Vector2 screenPos = Camera.main.WorldToScreenPoint(new Vector3(0, 0, 0));//世界坐标(0,0,0),一般可以用transform.position获取->屏幕坐标

        //屏幕坐标->世界坐标
        Debug.Log(screenPos.x + "," + screenPos.y);
        Vector3 worldPos1 = Camera.main.ScreenToWorldPoint(new Vector3(0, 0, Camera.main.nearClipPlane));
        Debug.Log(worldPos1.x + "," + worldPos1.y + "," + worldPos1.z);
        Vector3 worldPos2 = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, -Camera.main.transform.position.z));
        Debug.Log(worldPos2.x + "," + worldPos2.y + "," + worldPos2.z);
    }
}
运行结果如下:


上面脚本有几点需要说明的:

1、Camera.main.XX能够直接对主摄像机操作,无须像网上部分文章需要利用的GameObject.Find之类的找主摄像机。

2、世界坐标与屏幕坐标互转直接就是用WorldToScreenPoint/ScreenToWorldPoint两个方法,这方法凡是照相机对象就有。在部分设置多摄像机编程的程序,就是转换到调用的摄像机所对应的屏幕的世界。

3、WorldToScreenPoint世界坐标转屏幕坐标,很好理解,大家也看到(0,0,0)这个世界的三维坐标转到的(431.5,174.4537)这个屏幕的二维坐标Vector2 screenPos。这里屏幕宽:863高:422,处于(0,0,0)的长方体被投影到屏幕的中央偏下的位置,这和实际是吻合的。

当然实际操作中,其实这个屏幕坐标的多少对于我们来说是没意义的,但这个屏幕坐标所处的位置是在屏幕的百分之多少是很有意义的。所以,这一般还要配合Screen.width/height求屏幕的宽和高用。

4、对于ScreenToWorldPoint,屏幕坐标转世界坐标,可能有人会有疑问,屏幕坐标不是一个二维坐标,怎么这里试图对一个三维坐标转换?还在Z轴附带一些奇怪奇怪的位置。这里的Z轴,是投影面底部所处的Z轴位置距离摄像机Z轴的多少。上面的投影示意图,已经可以说明投影面是多个的,但只会投影到一个2D屏幕平面而已,世界中的物体/对象只能有一个,那么就形成一种 一个世界坐标只会对应一个屏幕坐标,一个屏幕坐标可能对应多个世界坐标。所以我们要补上一个Z轴,告诉程序,我要的是哪个屏幕坐标。

这里展示了将(0,0)这个左下角的屏幕坐标,转到距离摄像机最近的投影面上面,要拿这个投影面,如脚本所示,可以直接用Camera.main.nearClipPlane来取。还展示了将(Screen.width, Screen.height)这个右上角的屏幕坐标,放到Z轴为0,也就是世界屏幕的这个位置,因为摄像机所处的Z=-10,要放到世界坐标z=0,所以这里的Z轴要填上-Camera.main.transform.position.z,刚好就是-10-0。结果如上图所示。

理论上,投影面距离摄像头越近,他的投影面越小。所以大家看到如果转到距离摄像机最近的投影面上面,边角的坐标是0.x级别的,放到z=0这个投影面上面,边角的坐标则去到个位数级别。

  • 12
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Unity3D中,uGUI是一个用户界面系统,它可以让开发者创建和管理游戏中的UI元素,如按钮、文本等。在uGUI中,世界坐标是指相对于场景原点的坐标系,而屏幕坐标是指相对于屏幕坐标系。 在实际运用中,我们可以通过以下方式将世界坐标转换为屏幕坐标: ```csharp Vector3 worldPosition = new Vector3(10, 5, 0); Vector3 screenPosition = Camera.main.WorldToScreenPoint(worldPosition); ``` 这里我们使用了Camera.main.WorldToScreenPoint()方法,将世界坐标转换为屏幕坐标。这个方法需要指定一个摄像机,它将根据该摄像机的位置和朝向来计算屏幕坐标。在这个例子中,我们使用的是场景中的主摄像机,也就是Camera.main。 同样地,我们也可以将屏幕坐标转换世界坐标: ```csharp Vector3 screenPosition = new Vector3(100, 100, 0); Vector3 worldPosition = Camera.main.ScreenToWorldPoint(screenPosition); ``` 这里我们使用了Camera.main.ScreenToWorldPoint()方法,将屏幕坐标转换世界坐标。同样地,这个方法也需要指定一个摄像机。 在实际开发中,我们可以使用这些方法来处理鼠标点击、UI元素的位置调整等操作。例如,我们可以通过以下代码来将一个UI元素移动到鼠标点击的位置: ```csharp public void OnPointerClick(PointerEventData eventData) { Vector3 worldPosition = Camera.main.ScreenToWorldPoint(eventData.position); transform.position = worldPosition; } ``` 这里我们使用了Unity3D中的事件系统,当鼠标点击时,OnPointerClick()方法会被调用。在这个方法中,我们通过Camera.main.ScreenToWorldPoint()方法将屏幕坐标转换世界坐标,然后将UI元素的位置设置为该世界坐标。这样,当我们点击鼠标时,UI元素就会移动到鼠标点击的位置。 总之,在uGUI中,世界坐标屏幕坐标的转换是非常重要的,它们可以帮助我们处理一些常见的UI操作。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值