Unity中屏幕坐標(biāo)、視圖坐標(biāo)和世界坐標(biāo)的相互轉(zhuǎn)換


    我們?cè)谠O(shè)計(jì)游戲的時(shí)候乞旦,經(jīng)常會(huì)進(jìn)行坐標(biāo)系的變換贼穆,Unity為我們提供了多個(gè)變換的API,這里主要對(duì)它們的使用做一個(gè)總結(jié)整理兰粉!

在Unity中我們通常會(huì)用到以下幾個(gè)坐標(biāo)系下的點(diǎn):

    世界坐標(biāo)系故痊、觀察坐標(biāo)系、ViewPort玖姑、屏幕坐標(biāo)系
  • 世界坐標(biāo)系World Space
    簡(jiǎn)單來(lái)講愕秫,我們通過(guò) transform.position | transform.rotattion 獲取得到的位置和旋轉(zhuǎn)信息都是基于世界坐標(biāo)系的,可以說(shuō)焰络,我們的很大一部分操作都是基于世界坐標(biāo)系戴甩。
  • 觀察坐標(biāo)Eye Space
    我們?cè)赨nity的Game視圖中觀察的畫(huà)面始終是由攝像機(jī)提供的,基于攝像機(jī)的一個(gè)坐標(biāo)系也就是"Eye Space"(簡(jiǎn)單來(lái)講就是把攝像機(jī)看作原點(diǎn)位置)闪彼。
  • 視口坐標(biāo)View Port
    視口是針對(duì)游戲顯示的畫(huà)面進(jìn)行描述的甜孤,View Port用于描述整個(gè)游戲畫(huà)面的坐標(biāo),左下角為(0,0),右上角為(1,1)畏腕,我們?cè)谠O(shè)計(jì)分屏游戲的時(shí)候可以通過(guò)設(shè)置攝像機(jī)所占據(jù)的視口空間來(lái)控制缴川。
  • 屏幕坐標(biāo)Screen Space
    屏幕坐標(biāo)開(kāi)始和像素扯上關(guān)系了,也就是說(shuō)屏幕坐標(biāo)和分辨率有關(guān)描馅,屏幕的左下角為(0,0),但右上角為(screen.width,screen.height)把夸。比如游戲的分辨率為500*600,則screen.width=500;screen.height=600铭污。

這里需要說(shuō)明的是恋日,我們?cè)讷@取鼠標(biāo)位置的時(shí)候膀篮,Input.mousePosition來(lái)獲取鼠標(biāo)的位置,這里獲取到的鼠標(biāo)位置是基于屏幕坐標(biāo)的谚鄙。通過(guò)該函數(shù)返回的是Vector3類(lèi)型的變量各拷,但z分量始終為0。讀者可以自行進(jìn)行嘗試闷营。


這里,我們先來(lái)看一下Unity提供的相關(guān)常見(jiàn)函數(shù):

//1.屏幕轉(zhuǎn)世界坐標(biāo)
Vector3 Camera.main.ScreenToWorldPoint(new Vector3(screenPos.x , screenPos.y , zInfo));
//2.世界轉(zhuǎn)屏幕坐標(biāo)
Vector3 Camera.main.WorldToScreenPoint(new Vector3(worldPos.x , worldPos.y , worldPos.z));
//3.世界轉(zhuǎn)視口坐標(biāo)
Vector3 Camera.main.WorldToViewportPoint();
//4.視口轉(zhuǎn)世界坐標(biāo)
Vector3 Camera.main.ViewportToWorldPoint(new Vector3(viewPortPos.x , viewPortPos.y , zInfo));
//5.視口轉(zhuǎn)屏幕坐標(biāo)
Vector3 Camera.main.ViewportToScreenPoint();
//6.屏幕轉(zhuǎn)視口坐標(biāo)
Vector3 Camera.main.ScreenToViewportPoint();

作者作為初學(xué)者的一員知市,認(rèn)為先搞清楚這幾個(gè)暫時(shí)足夠傻盟,日后若有使用更多的變換,則再進(jìn)行補(bǔ)充吧嫂丙。

觀察這些個(gè)函數(shù)娘赴,首先一個(gè)很明顯的共同點(diǎn),就是這些函數(shù)都是Camera的成員函數(shù)跟啤,輸入和輸出都為Vector3類(lèi)型的變量诽表。也即這些函數(shù)都是針對(duì)當(dāng)前攝像機(jī)的一個(gè)變換操作。這很容易理解隅肥,因?yàn)?D游戲中的坐標(biāo)從模型空間到最終的屏幕空間經(jīng)過(guò)了model,view,projection,以及之后的NDC變換等竿奏,其中除model是用于從模型空間到世界空間的變換外,之后的view腥放,projection都是基于攝像機(jī)的泛啸。他們會(huì)隨著使用相機(jī)的變化而變化。至于具體的內(nèi)容秃症,變化過(guò)程候址,這里不做過(guò)多描述,讀者可以查看網(wǎng)上的相關(guān)文章种柑。

當(dāng)然岗仑,我們?cè)谑褂眠@些API的時(shí)候,只需要清楚我們的輸入和輸出的內(nèi)容及其關(guān)系就好了聚请。

接下來(lái)荠雕,我們來(lái)聊一聊這些函數(shù):


首先是屏幕坐標(biāo)和世界坐標(biāo)的相互轉(zhuǎn)換:

    WorldToScreenPoint函數(shù)接收一個(gè)世界空間下的位置信息,然后返回其所在的屏幕空間位置良漱,以及其相對(duì)于攝像機(jī)的深度信息舞虱,該深度信息由世界空間下攝像機(jī)和輸入位置的z值來(lái)決定。
        一個(gè)例子是:攝像機(jī)的位置為(0.0, 0.0 , -10.0),輸入的位置為(0.0,0.0,1.0)母市。則返回的結(jié)果為(screen.width/2 , screen.height/2 , 1-(-10));
        注意攝像機(jī)指向-z方向矾兜!
    ScreenToWorldPoint則是與之相反,輸入屏幕空間位置以及相應(yīng)的深度信息(注意深度信息應(yīng)該為目標(biāo)z值金和相機(jī)z值的差值)患久,可以返回其所在的世界坐標(biāo)位置椅寺。

視口坐標(biāo)和世界坐標(biāo)與之相似:

    WorldToViewportPoint:輸入世界坐標(biāo)浑槽,返回的是對(duì)應(yīng)的點(diǎn)所在的視口位置,當(dāng)然以及其相對(duì)于攝像機(jī)的深度信息(距離)
    ViewportToWorldPoint:輸入視口坐標(biāo)(記得對(duì)應(yīng)的深度信息)返帕,返回點(diǎn)所在的世界坐標(biāo)

視口坐標(biāo)和屏幕坐標(biāo)非常簡(jiǎn)單桐玻,正如上面的說(shuō)明,只要知道分辨率就可以輕松轉(zhuǎn)換荆萤,這里不再贅述镊靴。


一個(gè)簡(jiǎn)單的應(yīng)用

我們?cè)谠O(shè)計(jì)某些游戲的時(shí)候(比如攝像機(jī)固定不動(dòng)的類(lèi)型),會(huì)對(duì)物體的運(yùn)動(dòng)范圍進(jìn)行限制链韭,以防止其跑出邊界偏竟。比如一盒橫屏的飛行射擊游戲(雷電),我們可以獲得物體的位置信息:transform.position敞峭,我們希望對(duì)物體的x,y兩個(gè)軸向的移動(dòng)進(jìn)行限制(同時(shí)凍結(jié)物體的z軸移動(dòng))踊谋。一個(gè)簡(jiǎn)單的思路如下:

public float leftBorder;
public float rightBorder;
public float topBorder;
public float bottomBorder;

....

Vector3 leftBtm_cornerPos = Camera.main.ViewportToWorldPoint(new Vector3(0f, 0f,
            Mathf.Abs(-Camera.main.transform.position.z))); //這里的z軸在正交視圖下意義不大
Vector3 rightTop_cornerPos = Camera.main.ViewportToWorldPoint(new Vector3(1f, 1f,
            Mathf.Abs(-Camera.main.transform.position.z)));
....

leftBorder = leftBtm_cornerPos.x;
rightBorder = rightTop_cornerPos.x;
topBorder = rightTop_cornerPos.y;
bottomBorder = leftBtm_cornerPos.y;

....

if (pos.x <= leftBorder)
{
    pos.x = leftBorder;
}
else if (pos.x >= rightBorde
{
    pos.x = rightBorder;
}

if (pos.y <= bottomBorder)
{
    pos.y = bottomBorder;
}
else if (pos.y >= topBorder)
{
    pos.y = topBorder;
}

上面的代碼通過(guò)ViewportToWorldPoint獲取到了四個(gè)邊界。之后通過(guò)限制位置的x旋讹、y軸向移動(dòng)就可以控制避免移動(dòng)過(guò)度殖蚕。

說(shuō)明一下,這里假設(shè)了雷電類(lèi)型的游戲沉迹,使用的攝像機(jī)為正交類(lèi)型的投影方式睦疫,了解正交投影的朋友就知道,視錐體變成了長(zhǎng)方體形胚股,因子這里的z軸并無(wú)太大的作用笼痛。即使我使用ViewportToWorldPoint的時(shí)候使用0作為z軸數(shù)據(jù),也一樣沒(méi)關(guān)系琅拌。但是對(duì)于透視投影就不太一樣了缨伊。若這里使用的透視投影,在不同的深度下进宝,其的邊界范圍肯定也會(huì)變化刻坊,這個(gè)時(shí)候就必須輸入正確的z軸數(shù)據(jù)了!党晋。

最後編輯於
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末谭胚,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子未玻,更是在濱河造成了極大的恐慌灾而,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扳剿,死亡現(xiàn)場(chǎng)離奇詭異旁趟,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)庇绽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)锡搜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)橙困,“玉大人,你說(shuō)我怎么就攤上這事耕餐》哺担” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵肠缔,是天一觀的道長(zhǎng)夏跷。 經(jīng)常有香客問(wèn)我,道長(zhǎng)明未,這世上最難降的妖魔是什么拓春? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮亚隅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘庶溶。我一直安慰自己煮纵,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布偏螺。 她就那樣靜靜地躺著行疏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪套像。 梳的紋絲不亂的頭發(fā)上酿联,一...
    開(kāi)封第一講書(shū)人閱讀 49,071評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音夺巩,去河邊找鬼贞让。 笑死,一個(gè)胖子當(dāng)著我的面吹牛柳譬,可吹牛的內(nèi)容都是我干的喳张。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼美澳,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼销部!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起制跟,我...
    開(kāi)封第一講書(shū)人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤舅桩,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后雨膨,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體擂涛,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年哥放,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了歼指。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片爹土。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖踩身,靈堂內(nèi)的尸體忽然破棺而出胀茵,到底是詐尸還是另有隱情,我是刑警寧澤挟阻,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布琼娘,位于F島的核電站,受9級(jí)特大地震影響附鸽,放射性物質(zhì)發(fā)生泄漏脱拼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一坷备、第九天 我趴在偏房一處隱蔽的房頂上張望熄浓。 院中可真熱鬧,春花似錦省撑、人聲如沸赌蔑。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)娃惯。三九已至,卻和暖如春肥败,著一層夾襖步出監(jiān)牢的瞬間趾浅,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工馒稍, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留皿哨,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓筷黔,卻偏偏與公主長(zhǎng)得像往史,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子佛舱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 小姑是我的親姑姑椎例,我家父輩兄弟姐妹6人,她是老幺请祖。家庭雖然貧窮订歪,卻也是百般疼愛(ài)過(guò)的小公主。年輕的時(shí)候也是皮膚...
    不喜灰閱讀 1,430評(píng)論 9 25
  • 10月20日中午肆捕,垣曲縣老年大學(xué)組織全體學(xué)員開(kāi)展“喜慶十九大刷晋、歡度重陽(yáng)節(jié)”大聯(lián)歡活動(dòng)。 活動(dòng)場(chǎng)上學(xué)員們一個(gè)個(gè)精神抖...
    關(guān)愛(ài)網(wǎng)閱讀 257評(píng)論 0 1
  • 以前總是想著還有多少多少天,我們?cè)谝黄鸬娜兆泳蜐M夠一年眼虱,就是光想想也覺(jué)得激動(dòng)喻奥,可能對(duì)于他人來(lái)說(shuō),不就是才一年嗎捏悬,沒(méi)...
    心有所念的帆啊帆閱讀 321評(píng)論 0 0
  • 【韓喜文2018.05.30星期三】 好展館讓天下沒(méi)有賣(mài)不出去的產(chǎn)品 好展館讓天下沒(méi)有不能傳承的文化 日精進(jìn):87...
    韓喜文閱讀 163評(píng)論 0 0