close

最近案子常碰到的問題,各種座標的轉換,因此找了許多資料,所以在這裡同整一下

參考網址 : 

一、Unity3D中的坐標系目前可以分為以下四類:世界坐標螢幕坐標視圖坐標GUI坐標。下面來對這幾類坐標進行詳細說明:

世界坐標

  世界坐標按照笛卡爾坐標系定義出來的絕對坐標系,下面的各種坐標系都建立在世界坐標的基礎上。我們知道二維平面內任意一個點可以用二維坐標(x,y)來表示,如果將這個概念延伸到三維空間內,那麼三維空間內任意一個點都可以用三維坐標(x,y,z)來表示。這就是世界坐標的概念啦,坐標系通常可以分為左手坐標系和右手坐標系,而Unity3D採用的是左手坐標系。在Unity3D中我們可以使用transform.position來獲取場景中一個物體的世界坐標,通常情況下編輯器中的Inspector窗口是以世界坐標來描述一個3D物體的位置的,除非當一個3D物體存在父物體的時候,它會以相對坐標來描述其位置。

螢幕坐標

  螢幕坐標是以像素來定義的,它的範圍是以左下角為(0,0),右上角為(Screen.width,Screen.height)定義的這樣一個矩形。螢幕坐標是一個3D坐標,Z軸是以相機的世界單位來衡量的。螢幕坐標和相機之間滿足:Screen.width=Camera.pixelWidth和Screen.height=Camera.pixelHeight這兩個條件。例如我們將相機正對著場景中的原點(0,0,0),相機的Z軸分量為-10,按照螢幕坐標的定義,假設螢幕為800X640的大小,則此時原點轉化為螢幕坐標後應該是(400,320,10)。在Unity3D中我們可以使用WorldToScreenPoint來將一個世界坐標轉換為螢幕坐標。

視口坐標

  視口坐標是標準化後的螢幕坐標。標準化的概念我們可以引申到向量的標準化中,比如一個向量(x,y)將過標準化後可以得到一個單位向量( , )。類似地,視口坐標是以0到1間的數字來表示的,它的範圍是以左下角為(0,0),右上角為(1,1)定義的這樣一個矩形。視口坐標是一個3D坐標,Z軸是以相機的世界單位來衡量的。通過對比可以發現視口坐標和螢幕坐標特別的相似,所以這裡大家可以對比著來學習。同樣以螢幕坐標中的例子來將這裡的轉換,例如我們將相機正對著場景中的原點(0,0,0),相機的Z軸分量為-10,按照螢幕坐標的定義,假設螢幕為800X640的大小,則此時原點轉化為螢幕坐標後應該是(0.5,0.5,10)。在Unity3D中我們可以使用WorldToViewportPoint來將一個世界坐標轉換為視口坐標。

GUI坐標

  GUI坐標是指通過OnGUI方法繪製UI時使用的坐標。這個坐標系和螢幕坐標類似,它同樣是以像素來定義的,它的範圍是以左上角為(0,0),右下角為(Screen.width,Screen.height)定義的這樣一個矩形,GUI坐標是一個2D坐標(絕對坐標)。因為GUI在早期的文章中曾有所設計,屬於Unity3D中較為基礎的內容,此外我們知道使用絕對坐標來進行布局的話是沒有辦法做自適應的,所以這部分內容我們就不展開講了,UI自適應的一個主要觀點就是不要使用絕對坐標!不要使用絕對坐標!不要使用絕對坐標!重要的事情要說三遍的嘛!這裡想特別說說Unity4.6以後推出的全新UI支持:uGUI。在uGUI的Screen Space模式下,Unity3D的編輯器以螢幕坐標來顯示UI元素的位置;在World Space模式下,Unity3D的編輯器以世界坐標來顯示UI元素的位置。相信這一點大家在使用的時候都沒有注意到,最近在看一個論壇帖子的時候發現對uGUI坐標轉換的相關知識一片茫然,所以對這部分內容進行了深入的研究,最終得出的結論是:uGUI的坐標本質上是特殊的螢幕坐標,因為uGUI的Anchor決定了該坐標系的原點,pivot決定了元素本身坐標系的原點,正是這兩個屬性讓uGUI的坐標看起來顯得撲朔迷離。RectTransform組件繼承自Transform,所以它們的position和localPosition是等價的,都是世界坐標;anchoredPosition是UI元素的螢幕坐標,在對UI元素進行操作的時候應該考慮使用這個坐標。

  Unity3D各種坐標系間轉換的FAQ

1、螢幕坐標如何轉換為世界坐標?

在Unity3D中通過camera.ScreenToWorldPoint(Vector3 v)方法可以將一個螢幕坐標轉化為世界坐標。其中,camera是遊戲場景中的場景相機。通過Input.mousePosition或者 Input.touches[0].position可以獲得滑鼠或者單根手指的螢幕坐標。典型的應用場景是第一人稱射擊遊戲中子彈的發射RPG遊戲中點擊地面移動角色

2、世界坐標如何轉換為螢幕坐標?

在Unity3D中通過camera.WorldToScreenPoint(Vector3 v)方法可以將一個世界坐標轉化為螢幕坐標。其中,camera是遊戲場景中的UI相機。比如我們需要將一個世界坐標轉換到NGUI坐標的時候,可以使用場景相機將世界坐標轉為螢幕坐標,然後再利用UI相機將螢幕坐標轉換為世界坐標,最後再賦值給NGUI控制項。典型的應用場景是NPC頭頂的文字顯示怪物頭頂的血條顯示

3、螢幕坐標如何轉換為視口坐標?

在Unity3D中可以通過camera.ScreenToViewportPoint來將一個螢幕坐標轉換為視口坐標,其中camera是遊戲場景中的場景相機。當我們了解了視口坐標本質就是螢幕坐標的標準化坐標以後,這個真心沒有什麼可說的。

4、世界坐標如何轉換為視口坐標?

在Unity3D中可以通過camera.WorldToViewportPoint來將一個世界坐標轉換為視口坐標,其中camera是遊戲場景中的場景相機。當我們了解了視口坐標本質就是螢幕坐標的標準化坐標以後,這個真心沒有什麼可說的。

5、螢幕坐標如何轉化為GUI坐標?

我們注意到螢幕坐標和GUI坐標的根本差異在於坐標系原點選定不同,即螢幕坐標的原點在左下角,而GUI坐標的原點在左下角。因此我們可以定義一個ScreenToGUIPoint方法:

private Vector2 ScreenToGUIPoint(Vector2 v) {

         return new Vector2(v.x, Screen.height - v.y ) ;

}

6、GUI坐標如何轉換為螢幕坐標?

一個更為神奇的事情是你可以繼續調用ScreenToGUIPoint方法。

7、螢幕坐標如何轉換為uGUI坐標?

當我們接觸到uGUI以後常常會遇到類似NGUI需要為uGUI控制項坐標賦值的問題,此時我們我們有以下兩種思路處理:

* 直接把螢幕坐標賦值給transform.position,這種方式簡單粗暴在ScreenSpace-Overlay模式下沒有問題,然而在ScreenSpace-Camera模式下會出現因為深度數值不正確而引發的問題,需要注意(並且需要確保被賦值的物體在Canvas的根節點下) 。

  • 通過RectTransformUtility.ScreenPointToWorldPointInRectangle方法將螢幕坐標轉化為世界坐標然後再賦值給transform.position。兩種方法看起來大同小異,然而這種方法是更為保險的,因為它在這兩種模式下都能穩定地運行。更重要的是它可以和uGUI的事件系統完美地融合。 


 二、 獲取UGUI子節點在Canvas的螢幕座標 

transform.postion 和rectTransform.anchoredPosition 這兩個坐標是完全不一樣的。前面的是3D坐標,後面的是2D在Rect裡的坐標,並且還是相對坐標,那麼節點深了坐標就更不好換算了 

假設我想獲取某個子的子節點的2D坐標

可调用 
RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transformasRectTransform, transform.position, canvas.camera,out pos) 

而第三個參數是螢幕座標

RectTransformUtility. ScreenPointToLocalPointInRectangle (
          cvs.transform as RectTransform, Camera.main .WorldToScreenPoint( transform.position ),
          cvs.worldCamera , out local)
最後在想需要賦值的UI 用 rectTransform.anchoredPosition = pos 就可以了
arrow
arrow

    Kouhei 發表在 痞客邦 留言(0) 人氣()