Unity关于坐标的区分

1.世界坐标系(transform.position),遵守左手坐标系的原则

2.局部坐标系(transform.localPosition),局部坐标系是对于子物体和父物体来说的,这里在inspector窗口中的transform中的position其实可以理解成是局部坐标,因为它们都有相同的父物体,那就是初始世界,这里局部坐标不仅仅考虑坐标点的参照,还有坐标轴,局部坐标的坐标轴是其本身的坐标轴所指向的方向,这个会在transform.Translate中用到;

3.屏幕坐标系(Screen.width和Screen.hight),这里是左下角为起点,右上角为终点,但是屏幕坐标系为三维坐标系,z值表示深度,与物体距离摄像机的远近有关

注意:获取鼠标位置的方法是Input.mousePosition,这里返回值是Vector3,鼠标坐标是参照的屏幕坐标系的x,y轴,z值默认为0

4.视口坐标系,它是屏幕坐标系的归一,也就是说视口坐标系起点也是左下角,终点也在右上角,但是它终点的坐标为(1,1)

5.GUI坐标系,起点从左上角开始为(0,0),右下角为终点(Screen.width,Screen.height)

 坐标之间的转换

1.世界坐标和屏幕坐标的相互转换

屏幕坐标转世界坐标
Camera.main.ScreenToWorldPoint(Vector3 Pos);

世界坐标转屏幕坐标
Camera.main.WorldToScreenPoint(Vector3 Pos);

 这里的最多使用场景就是做一个游戏物体跟随鼠标进行移动,物体是世界坐标,鼠标为屏幕坐标,把屏幕坐标转换成世界坐标,然后将转换后的值赋给物体的世界坐标就可以实现物体跟随鼠标移动,感觉上这里的转换是Camera.main.ScreenToWorldPoint(Input.mousePosition);(因为Input.mousePosition为Vector3所以可以),但是这里仔细想想回发现,屏幕坐标只有两个值,x和y值,缺少z值(z值为0,这个时候相机的投影模式为透视的话屏幕坐标转换为世界坐标直接就等于相机坐标,模式为正交的话,屏幕坐标转世界坐标,x,y轴正常转换,z轴和相机保持一致),因此不能直接这样使用

这里思考一个问题,那为什么不把物体的世界坐标转换成屏幕坐标,然后将鼠标的屏幕坐标赋值给物体的屏幕坐标,不久可以实现物体跟随鼠标了吗,其实这里是可以这样做,但是仅仅只能用于2d游戏物体跟随鼠标的移动,如果想要实现3d游戏中,物体物体跟随鼠标移动,xyz都移动,就还是需要使用到屏幕坐标转世界坐标

由于缺少z轴,因此解决方案为:

void Update()
    {

        //这里的物体相当于就一直在与相机距离相等的平面上运动
        // 首先将要操纵的物体的世界坐标转为屏幕坐标
        Vector3 screenPos = Camera.main.WorldToScreenPoint(transform.position);
        // 然后获取鼠标的屏幕坐标
        Vector3 mousePos = Input.mousePosition;
        // 然后将已经转换好的物体的屏幕坐标的Z值赋给缺失z值的鼠标屏幕坐标
        mousePos.z = screenPos.z;
        // 然后将已经完整的鼠标屏幕坐标转成世界坐标
        Vector3 worldPos = Camera.main.ScreenToWorldPoint(mousePos);
        // 最后每帧修改物体世界坐标位置
        transform.position = worldPos;
    }

 2.世界坐标和视口坐标的相互转换

世界坐标转视口坐标
Camera.main.WorldToViewportPoint(Vector3 Pos)

视口坐标转世界坐标
Camera.main.ViewportToWorldPoint(Vector3 Pos); 

 // 首先将要操纵的物体的世界坐标转为视口做坐标
        Vector3 screenPos = Camera.main.WorldToViewportPoint(transform.position);
        // 然后获取鼠标的屏幕坐标
        Vector3 mousePos = Input.mousePosition;
        // 然后将已经转换好的物体的屏幕坐标的Z值赋给缺失z值的鼠标屏幕坐标
        mousePos.z = screenPos.z;
        // 将屏幕坐标转为视口坐标
        mousePos = Camera.main.ScreenToViewportPoint(mousePos);

        // 然后将已经完整的视口坐标转成世界坐标
        Vector3 worldPos = Camera.main.ViewportToWorldPoint(mousePos);
        // 最后每帧修改物体世界坐标位置
        transform.position = worldPos;

3.屏幕坐标和视口坐标的相互转换

屏幕坐标转视口坐标
Camera.main.ScreenToViewportPoint(Vector3 Pos)

视口坐标转屏幕坐标
Camera.main.ViewportToScreenPoint(Vector3 Pos);

 4.世界坐标和局部坐标的相互转换(一般使用得很少,需要使用时再去查询)

5.新增转换:屏幕坐标转为矩形内的世界坐标(就是用来实现在UGUI中的物体随鼠标跟随的效果)

RectTransformUtility.ScreenPointToWorldPointInRectangle(RectTransform rect, Vector2 screenPoint, Camera cam, out Vector3 worldPoint);

//其中RectTransform​​​​​​​ rect为物体所在的层级最大的RectTransform中,一般来说就是Canvas

//Vector2​​​​​​​ screenPoint这里可以就是鼠标坐标

//Camera cam:与屏幕点相关的相机,对于Canvas设置为“Screen Space - Overlay mode”

模式的情况,cam参数应该为null

//Vector3 worldPoint是转换好的值通过Out参数传递出来

注意:在Unity中,不能对transform.position.x/y/z直接赋值,只能用一个Vector3对postion进行整体的赋值,这是因为 

原因就在于Vector3是一个结构体,而position是一个自动实现的属性。在C#里,结构体是值类型的,值类型在通过方法传递的时候,所传递的只是值的副本而当我们transform.position.x = 1时调用属性的Get方法得到position,但是这个position只是一个副本而对这个副本所作出的任何修改,都对原positon没有任何影响,因此这样的修改是毫无意义的。编译器会禁止这样的修改操作,也就是可以理解的了。

注意:struct属于值类型,可以不用new,如果不new,结构体内的值就都是未赋值状态,需要在使用之前赋值,不然编译器会报错。若new了,结构体会调用无参构造函数,会初始化内部的值,比如int就会初始化为0,现在使用编译器就不会报错了。

猜你喜欢

转载自blog.csdn.net/qq_62947569/article/details/128441051