美文网首页Unity3d
Unity基础(10)-坐标系统

Unity基础(10)-坐标系统

作者: 元宇宙协会 | 来源:发表于2018-01-28 20:08 被阅读300次

    01-3D坐标系统

    • 什么是3D坐标系?

    3D坐标系是3D游戏开发与VR开发中的基础概念。一般而言3D坐标系都是使用的
    笛卡尔坐标系来描述物体的坐标信息,笛卡尔坐标系:分为左手坐标系右手坐标系

    笛卡尔坐标

    02-Unity中的坐标系统

    Unity中使用的是左手坐标系,X轴代表水平方向 horizontal, Y轴代表垂直方向vertical ,Z轴代表深度。Vector3(x,y,z)
    Unity中坐标系分类:

    • word Space (世界坐标系)
    • local Space (局部坐标系)
    • Screen Space(屏幕坐标系)
    • viewport (视口坐标)
    • GUI界面的坐标系
    2-1 世界坐标系

    世界坐标系:用来描述游戏场景内所有物体位置和方向的基准,Unity场景中创建的物体都是以全局坐标系中的坐标原点(0,0,0)来确定各自的位置。

    • 别名:全局坐标系


      全局坐标系
    • 怎么获取游戏对象的世界坐标?
    transform.position可以获得该坐标
    
    
    2-2 局部坐标系

    局部坐标系:是相对于父物体来说也就是当两个游戏对象互为父子关系,那么子物体会以父物体的坐标点为自身的坐标原点。如果游戏对象没有父物体,那么会以这个世界的0,0为自身的坐标原点.

    • 别名:物体坐标系,模型坐标系?(有的模型软件并不是如此)


      物体坐标系
      以父物体为坐标原点
    • 怎么获取游戏对象的局部坐标?

    transform.LocalPosition可以获得该局部坐标
    
    2-3 屏幕坐标系

    屏幕坐标系:以像素为单位,左下角是(0,0),右上角为(screen.width, screen.height),Z的位置是以相机的世界单位来衡量及物体离相机远近。

    • 怎么获取屏幕坐标系
    Input.mousePosition;
    Input.GetTouch(0).position;
    
    public Vector3 screenPos;
    void Update () {
            screenPos = Input.mousePosition; 
     }
    
    • 注意点

    相机如何渲染物体
    摄像机对游戏世界的渲染范围是一个平截头体,渲染边界是一个矩形,用与near clippingplane或者far clippingplane平行的平面截取这个平截头体,可以获得无数个平行的矩形面,也就是我们看到的屏幕矩形。离摄像机越远,矩形越大,离摄像机越近,矩形越小。所以,同样大小的物体,随着离摄像机越来越远,相对于对应屏幕矩形就越来越小,所看起来就越来越小。

    ScreenToWorldPoint:
    首先截取一个垂直于摄像机Z轴的,距离为Z的平面P,这样不管X,Y怎么变化,返回的点都只能在这个平面上,参数是一个三维坐标,而实际上,屏幕坐标只能是二维坐标。参数中的z坐标的作用就是:用来表示上述平面离摄像机的距离。X,Y表示像素坐标,根据(X,Y)相对于屏幕的位置,得到游戏世界中的点相对于截面P的位置,也就将屏幕坐标转换为了世界坐标。

    2-4 viewport (视口坐标)

    视口坐标:视口坐标是标准的和相对于相机的。相机的左下角为(0,0)点,右上角为(1,1)点,
    Z的位置是以相机的世界单位来衡量的。
    摄像机分为两种,一种是正交摄像机还有一种是透视摄像机。正交摄像机无论远近它的视口范围永远是固定的,但是透视摄像机是由原点向外扩散性发射,也就是距离越远它的视口区域也就越大。那么我们如何获取距离摄像机任意距离的视口区域呢?
    如下图所示,分别用红色和黄色两种颜色将计算出来的视口区域标记了出来。


    视口坐标
    • 视口坐标的转换
            // 视口坐标到屏幕坐标
            screenPos = Camera.main.ViewportToScreenPoint(cube.transform.position);
            // 屏幕坐标到视口坐标
            viewPos1 = Camera.main.ScreenToViewportPoint(screenPos);
            
            // 视口坐标到世界坐标
            worldPos = Camera.main.ViewportToWorldPoint(cube.transform.position);
            // 世界坐标到视口坐标
            viewPos =Camera.main.WorldToViewportPoint(cube.transform.position); 
    
    
    2-5 GUI界面坐标系

    GUI界面坐标系:这个坐标系与屏幕坐标系相似,不同的是该坐标系以屏幕的左上角为(0,0)点,右下角为(Screen.width,Screen.height)。

     private void OnGUI()
        {
            GUILayout.TextArea("顶部框" );
            GUILayout.TextArea("第二个框" );
            GUILayout.TextArea("第三个框:" );
            GUILayout.TextArea("第四个框:" );
    
            GUI.TextArea(new Rect(0, 400, Screen.width, Screen.height / 5), "整个屏幕宽度与整个屏幕高度为5分之一的框,");
        }
    

    03-局部坐标与世界坐标的转换

    局部坐标系转换到全局坐标系:
    Transform.TransformPoint()
    全局坐标系转换到局部坐标系:
    Transform.InVerseTransformPoint()
    
            Vector3 worldPos = GameObject.Find("Cube").transform.position;
            Vector3 localPos = GameObject.Find("Cube").transform.localPosition;
            Debug.Log("物体的世界坐标" + worldPos);
            Debug.Log("物体的局部坐标" + localPos);
    
            Vector3 SpWorldPos = GameObject.Find("Cube").transform.Find("Sphere").transform.position;
            Vector3 SpLocalPos = GameObject.Find("Cube").transform.Find("Sphere").transform.localPosition;
            Debug.Log("子物体的世界坐标" + SpWorldPos);
            Debug.Log("子物体的局部坐标" + SpLocalPos);
    
            // 世界坐标与局部坐标的转换  注意点:关于坐标的转换,使用父类对象Transform进行
            // 从局部坐标转世界坐标
            Vector3 SpWorldPos1 = GameObject.Find("Cube").transform.TransformPoint(SpLocalPos);
            // 从世界坐标转局部坐标
            Vector3 SpLocalPos1 = GameObject.Find("Cube").transform.InverseTransformPoint(SpWorldPos);
            Debug.Log("子物体的世界坐标转换" + SpWorldPos1);
            Debug.Log("子物体的局部坐标转换" + SpLocalPos1);
    
             // 局部向量转换到全局向量
           Transform.TransformDirection
            // 全局向量转换到局部向量
           Transform. InVerseTransformDirection
    
    
    

    04-屏幕坐标与世界坐标的转换

     public Vector3 screenPos;
     public Vector3 worldPos;
     // 将世界坐标转换成屏幕坐标
     screenPos = Camera.main.WorldToScreenPoint(cube.transform.position);
    
     // 如何将屏幕坐标转换成世界坐标(得到的是相机坐标)  ,注意:首先截取一个垂直于摄像机Z轴的,距离为Z的平面P,这样不管X,Y怎么变化,返回的点都只能在这个平面上,参数是一个三维坐标,而实际上,屏幕坐标只能是二维坐标。参数中的z坐标的作用就是:用来表示上述平面离摄像机的距离。X,Y表示像素坐标,根据(X,Y)相对于屏幕的位置,得到游戏世界中的点相对于截面P的位置,也就将屏幕坐标转换为了世界坐标。
     worldPos = Camera.main.ScreenToWorldPoint(Vector3.zero); 
    
     private void OnGUI()
        {
            GUILayout.TextArea("屏幕坐标:" + screenPos);
            GUILayout.TextArea("世界坐标:" + worldPos);
        }
    

    05-视口坐标与屏幕、世界坐标的转换

        public Vector3 screenPos;
        public Vector3 worldPos;
        public Vector3 viewPos;
        public Vector3 viewPos1;
        private GameObject cube;
        void Start() {
            cube = GameObject.Find("Cube");
    
            // 视口坐标到屏幕坐标
            screenPos = Camera.main.ViewportToScreenPoint(cube.transform.position);
            // 屏幕坐标到视口坐标
            viewPos1 = Camera.main.ScreenToViewportPoint(screenPos);
            
            // 视口坐标到世界坐标
            worldPos = Camera.main.ViewportToWorldPoint(cube.transform.position);
            // 世界坐标到视口坐标
            viewPos =Camera.main.WorldToViewportPoint(cube.transform.position);
    
        }
        private void OnGUI()
        {
            GUILayout.TextArea("屏幕坐标:" + screenPos);
            GUILayout.TextArea("世界坐标:" + worldPos);
            GUILayout.TextArea("视口坐标:" + viewPos);
            GUILayout.TextArea("视口坐标:" + viewPos1);
        }
    

    06-视口坐标绘制图像代码

    拷贝代码做成脚本挂载到相机就可以。

    using UnityEngine;
    using System.Collections;
    
    public class CameraView : MonoBehaviour
    {
    
    
        private Camera theCamera;
    
        //距离摄像机8.5米 用黄色表示
        public float upperDistance = 8.5f;
        //距离摄像机12米 用红色表示
        public float lowerDistance = 12.0f;
    
        private Transform tx;
    
    
        void Start()
        {
            if (!theCamera)
            {
                theCamera = Camera.main;
            }
            tx = theCamera.transform;
        }
    
    
        void Update()
        {
            FindUpperCorners();
            FindLowerCorners();
        }
    
    
        void FindUpperCorners()
        {
            Vector3[] corners = GetCorners(upperDistance);
    
            // for debugging
            Debug.DrawLine(corners[0], corners[1], Color.yellow); // UpperLeft -> UpperRight
            Debug.DrawLine(corners[1], corners[3], Color.yellow); // UpperRight -> LowerRight
            Debug.DrawLine(corners[3], corners[2], Color.yellow); // LowerRight -> LowerLeft
            Debug.DrawLine(corners[2], corners[0], Color.yellow); // LowerLeft -> UpperLeft
        }
    
    
        void FindLowerCorners()
        {
            Vector3[] corners = GetCorners(lowerDistance);
    
            // for debugging
            Debug.DrawLine(corners[0], corners[1], Color.red);
            Debug.DrawLine(corners[1], corners[3], Color.red);
            Debug.DrawLine(corners[3], corners[2], Color.red);
            Debug.DrawLine(corners[2], corners[0], Color.red);
        }
    
    
        Vector3[] GetCorners(float distance)
        {
            Vector3[] corners = new Vector3[4];
    
            float halfFOV = (theCamera.fieldOfView * 0.5f) * Mathf.Deg2Rad;
            float aspect = theCamera.aspect;
    
            float height = distance * Mathf.Tan(halfFOV);
            float width = height * aspect;
    
            // UpperLeft
            corners[0] = tx.position - (tx.right * width);
            corners[0] += tx.up * height;
            corners[0] += tx.forward * distance;
    
            // UpperRight
            corners[1] = tx.position + (tx.right * width);
            corners[1] += tx.up * height;
            corners[1] += tx.forward * distance;
    
            // LowerLeft
            corners[2] = tx.position - (tx.right * width);
            corners[2] -= tx.up * height;
            corners[2] += tx.forward * distance;
    
            // LowerRight
            corners[3] = tx.position + (tx.right * width);
            corners[3] -= tx.up * height;
            corners[3] += tx.forward * distance;
    
            return corners;
        }
    }
    

    相关文章

      网友评论

        本文标题:Unity基础(10)-坐标系统

        本文链接:https://www.haomeiwen.com/subject/mkuzaxtx.html