3D坐標系是在做3D項目開發中的基礎概念,一般來說3D軟件或者開發工具都是采用笛卡爾坐標系來描述物體的坐標信息。笛卡爾坐標系分為左手坐標系和右手坐標系,左手坐標系是Y軸指向上方,X軸指向右方,Z軸指向前方;左,右手坐標系的X、Y軸方向相同,而Z軸是相反的,如圖1.1:
在Unity中使用的是左手坐標系,其中X軸代表水平方向,Y軸代表垂直方向,Z軸代表深度,Unity中游戲對象的坐標信息是放在一對括號里面,依次按照X、Y、Z軸的順序來寫的,例如(2,2,2)。
在Unity項目開發過程中經常會用到不同的坐標系來描述場景空間中的物體位置,下面就介紹幾種常用的坐標系。
1、全局(世界)坐標系
全局坐標系是用于描述場景內所有物體位置和方向的基準,也稱為世界坐標系。在Unity場景中創建的的物體都是以全局坐標中的坐標原點(0,0,0)來確定各自的位置。如圖1.2,我們就創建一個Cube物體
在Inspector視圖的Transform組件中可以觀察到Cube的坐標信息,此時的Position屬性是(0,0,0)就表示了該物體的全局坐標。我們通常在代碼中用transform.position來獲取全局坐標。
2、局部坐標
Unity場景中,每一個物體都有自己獨立的坐標系,并且會隨著物體的旋轉或者移動而改變,也稱為模型坐標系或物體坐標系;模型mesh保存的頂點均為局部坐標系下的坐標。Transform組件中Position表示的其實也是局部坐標,圖1.2中之所以表示的是世界坐標,是因為新創建的Cube并沒有父級,此時Cube自己就相當于自己的父級,所以它的Position表示的既是自己的局部坐標也是世界坐標。在工具欄中單擊Global按鈕可以切換現實全局坐標系和局部坐標系,如圖1.3就是局部坐標系
在Unity中,可以在Hierarchy視圖中將一個游戲對象拖到另一個對象上來建立父子關系,這樣就使得被拖動的物體成為了另一個物體的子物體,父子物體的坐標系是關聯的,此時子物體會以父物體的局部坐標點為自身的坐標原點,此時子物體的Position屬性值顯示的就是該物體相對于父物體的局部坐標。如圖1.4表示了新建的Sphere物體,將以該物體為父物體:
然后我們就把Cube拖到Sphere下,后觀察Cube的Transform組件的變化。如圖1.5:
可以看出Cube的Position值變成了在相對于其父物體Sphere局部坐標系時的位置。在代碼中我們可以用transform.localposition來獲取局部坐標。
3、相機坐標系
根據觀察位置和方向建立的坐標系。使用此坐標系可以方便地判斷物體是否在相機前方以及物體之間的先后遮擋順序等。
4、屏幕坐標系
屏幕坐標系是一個三維坐標系,Z軸是以相機的世界單位來衡量的。該坐標系通常用來描述像素在屏幕上的位置,它的范圍是以左下角為(0,0),右上角為(Screen.width,Screen.height)定義的這樣一個矩形,就是屏幕的大小。也就是我們的Game視圖。
屏幕坐標和相機之間的關系:Screen.width=Camera.pixelWidth和Screen.height=Camera.pixelHeight這兩個條件。例如我們將相機正對著場景中的原點(0,0,0),相機的Z軸分量為-10,按照屏幕坐標的定義,假設屏幕為800X640的大小,則此時原點轉化為屏幕坐標后應該是(400,320,10)。下面我們就做一個屏幕坐標的實驗。
我們先創建一個腳本,寫好代碼讓它可以打印出我們鼠標點擊Game視圖時點擊位置的屏幕坐標。
腳本代碼:
<code>
void Start () {
}
void Update () {
if (Input.GetMouseButtonDown(0))//判斷是否按下鼠標左鍵
{
Vector3 vec = Input.mousePosition;//設一個三維向量用來存放鼠標點擊時的坐標,此時Z軸為0
vec.z = this.transform.position.z;//把Z的坐標換做相機的Z軸坐標,因為腳本在相機上,所以用this點出
print(vec);//打印出鼠標按下時的屏幕坐標
}
}
</code>
我們把這個腳本放到相機上面,然后調整一下Game視圖的大小,如圖1.6:
最后運行項目,在Game視圖中點擊鼠標左鍵,我們分別點擊Game視圖的左下角、右下角、左上角和右上角,觀察Console視圖的打印內容,如圖1.7:
有圖我們得以驗證:左下角就是屏幕坐標系的原點,水平方向就是X軸,垂直方向就是Y軸,Z軸就是相機的Z軸坐標-4。
5、視口坐標系
視口坐標是標準化后的屏幕坐標。標準化的概念我們可以引申到向量的標準化中,比如一個向量(x,y)將過標準化后可以得到一個單位向量(x’,y’)。類似地,視口坐標是以0到1間的數字來表示的,它的范圍是以左下角為(0,0),右上角為(1,1)定義的這樣一個矩形。視口坐標是一個3D坐標,Z軸是以相機的世界單位來衡量的。
通過對比可以發現視口坐標和屏幕坐標特別的相似,所以這里大家可以對比著來學習。同樣以屏幕坐標中的例子來將這里的轉換,例如我們將相機正對著場景中的原點(0,0,0),相機的Z軸分量為-10,按照屏幕坐標的定義,假設屏幕為800X640的大小,則此時原點轉化為屏幕坐標后應該是(0.5,0.5,10)。
介紹好坐標系,我們下面介紹一下幾種常用的坐標系之間的轉換方法
1、屏幕坐標轉世界坐標
在Unity3D中通過camera.ScreenToWorldPoint(Vector3 v)方法可以將一個屏幕坐標轉化為世界坐標。其中,camera是游戲場景中的場景相機(不一定非要是主相機)。通過Input.mousePosition或者 Input.touches[0].position可以獲得鼠標或者單根手指的屏幕坐標。
2、世界坐標轉屏幕坐標
在Unity3D中通過camera.WorldToScreenPoint(Vector3 v)方法可以將一個世界坐標轉化為屏幕坐標。其中,camera是游戲場景中的UI相機。比如我們需要將一個世界坐標轉換到NGUI坐標的時候,可以使用場景相機將世界坐標轉為屏幕坐標,然后再利用UI相機將屏幕坐標轉換為世界坐標,最后再賦值給NGUI控件。
3、屏幕坐標轉視口坐標
在Unity3D中可以通過camera.ScreenToViewportPoint()來將一個屏幕坐標轉換為視口坐標,其中camera是游戲場景中的場景相機。
4、世界坐標轉視口坐標
在Unity3D中可以通過camera.WorldToViewportPoint()來將一個世界坐標轉換為視口坐標,其中camera是游戲場景中的場景相機。