本文同時發(fā)布在我的個人博客上:https://dragon_boy.gitee.io
坐標(biāo)系
有左手坐標(biāo)系和右手坐標(biāo)系兩種锋八,Unity使用的是右手坐標(biāo)系扣讼。
點(diǎn)和矢量
我們使用兩個或三個以上的實(shí)數(shù)來表示一個點(diǎn)的坐標(biāo),如秋度。
矢量是指n維空間中一種包含了模和方向的有向線段买决。矢量的表示方法和點(diǎn)類似,如欺旧。
矢量通常由一個箭頭表示,由起點(diǎn)指向終點(diǎn)蛤签。矢量常被用于表示相對于某個點(diǎn)的偏移辞友,只要矢量的模和方向保持不變,無論在哪里震肮,都是同一個矢量称龙。
矢量運(yùn)算
矢量和標(biāo)量乘除
對乘法,將矢量的每個分量和標(biāo)量相乘即可:
對除法戳晌,同理:茵瀑,標(biāo)量需非零。
矢量加減法
兩個矢量加減法躬厌,把對應(yīng)的分量進(jìn)行相加或相減即可:
幾何意義上马昨,矢量相加即前者起點(diǎn)連接至后者終點(diǎn),矢量相減即后者終點(diǎn)指向前者終點(diǎn)扛施。
矢量的模
矢量的模即矢量的長度:
單位矢量
單位矢量即模為1的矢量鸿捧。將某個非零矢量轉(zhuǎn)化為單位矢量的過程稱為歸一化。
矢量乘法
矢量之間的乘法有兩種疙渣,點(diǎn)積和叉積匙奴。
點(diǎn)積公式有兩個:
1:
2(為兩個矢量的夾角):
點(diǎn)積的結(jié)果在幾何意義上是獲得矢量在
上的投影與
的模的乘積,如果二者都是單位矢量妄荔,那么點(diǎn)積結(jié)果就是前者在后者上的投影泼菌。
叉積公式:
下面是另一種表示:
上述表明矢量叉積的結(jié)果的模是兩矢量構(gòu)成平行四邊形的面積。
在幾何意義的上啦租,叉積的結(jié)果是一個新的矢量哗伯,分別垂直于和
,且沿
篷角、
和叉積的方向可構(gòu)成一個右手坐標(biāo)系焊刹。
矩陣
矩陣有行列之分,以矩陣為例:
矢量的矩陣表示法
矢量可以看作時的列矩陣或
的行矩陣恳蹲。
矩陣運(yùn)算
矩陣和標(biāo)量的乘法
將矩陣的每個元素和標(biāo)量相乘即可虐块。
矩陣和矩陣的乘法
兩個矩陣相乘,要求前一個矩陣的列數(shù)等于后一個矩陣的行數(shù)嘉蕾,相乘得到的矩陣的行數(shù)是第一個矩陣的行數(shù)贺奠,列數(shù)是第二個矩陣的列數(shù)。如的維度是
错忱,
的維度是
儡率,那么
的維度是
颁糟。
矩陣的乘法即前一個矩陣的每一行(行)與后一個矩陣的每一列(
列)相乘(可看作行構(gòu)成的矢量和列構(gòu)成的矢量點(diǎn)積),每次相乘的結(jié)果填寫在對應(yīng)的
行
列上喉悴。
注意棱貌,矩陣乘法不滿足交換律,但滿足結(jié)合律箕肃。
特殊矩陣
方陣
方陣即行列數(shù)相等的矩陣婚脱。
同時,如果除對角線的元素外全是0的方陣稱為對角矩陣勺像。
單位矩陣
針對上述的對角矩陣障贸,如果對角線的元素全是0的話,那么就稱為單位矩陣吟宦。
轉(zhuǎn)置矩陣
對于一個的矩陣
,它的轉(zhuǎn)置
為
的矩陣篮洁。轉(zhuǎn)置運(yùn)算即將原矩陣的行列翻轉(zhuǎn)。原矩陣的
行變?yōu)?img class="math-inline" src="https://math.jianshu.com/math?formula=i" alt="i" mathimg="1">列殃姓,
列變?yōu)?img class="math-inline" src="https://math.jianshu.com/math?formula=j" alt="j" mathimg="1">行袁波。
注意,矩陣的轉(zhuǎn)置的轉(zhuǎn)置等于原矩陣蜗侈。
矩陣的串接的轉(zhuǎn)置等于反向串接各個矩陣的轉(zhuǎn)置:
逆矩陣
只有方陣才有逆矩陣篷牌。
一個矩陣和它的逆矩陣的乘積為單位矩陣:
零矩陣沒有逆矩陣。如果一個矩陣有逆矩陣踏幻,那么這個矩陣是可逆的枷颊,或非奇異的,相反則是不可逆的或奇異的该面。
如果一個矩陣的行列式為不為0夭苗,那么該矩陣就是可逆的(具體不解釋)。
注意隔缀,逆矩陣的逆矩陣為原矩陣题造。
單位矩陣的逆矩陣是它本身。
轉(zhuǎn)置矩陣的逆矩陣是逆矩陣的轉(zhuǎn)置:
矩陣串接相乘后的逆矩陣等于反向串接各個矩陣的逆矩陣:
注意蚕泽,如果某個矩陣或矢量進(jìn)行了一個矩陣變化晌梨,那么使用逆矩陣可以還原這個變換:
正交矩陣
如果一個方陣和它的轉(zhuǎn)置矩陣的乘積是單位矩陣桥嗤,那么這個方陣就是正交矩陣:
將正交矩陣與逆矩陣的概念結(jié)合起來须妻,就可以得到,如果一個矩陣正交泛领,那么它的轉(zhuǎn)置矩陣和逆矩陣相等:
上述式子在實(shí)際計(jì)算中非常有用荒吏,因?yàn)槟婢仃嚨挠?jì)算量很大(涉及伴隨矩陣),所以如果能判斷某個變換矩陣是正交的話渊鞋,可以很簡單地用轉(zhuǎn)置矩陣代替它的逆矩陣進(jìn)行計(jì)算绰更。
那么如何判斷一個矩陣是否正交瞧挤,我們把一個矩陣的列看作是一個矢量,稱為基矢量儡湾,那么根據(jù)正交矩陣定義:
根據(jù)上述等式特恬,得:
,
,
都是單位矢量,且兩兩垂直徐钠。那么滿足這樣條件的矩陣的就是正交矩陣癌刽。
矢量的矩陣表示
在Unity中,常將矢量當(dāng)做是列矩陣來使用尝丐,即放到矩陣的右邊來進(jìn)行乘法显拜。這種情況下,矩陣乘法通常是右乘爹袁,即:
變換
概念
變換是將一些數(shù)據(jù)通過某種方式進(jìn)行轉(zhuǎn)換的過程远荠。
一個非常常見的變換是線性變換,指的是可以保留矢量加和標(biāo)量乘的變換失息。數(shù)學(xué)公式為:
縮放是一種線性變換譬淳,旋轉(zhuǎn)也是一種線性變換,我們可以使用一個的矩陣就可以對一個三維向量進(jìn)行線性變換盹兢。除此之外還有錯切瘦赫,鏡像,正交投影蛤迎。
但平移變換不是線性變換确虱,我們不能使用一個的矩陣對一個三維向量進(jìn)行變換。
由此出現(xiàn)仿射變換替裆,即合并線性變換和平移變換的變換類型校辩。仿射變換使用一個的矩陣來表示,這樣我們需要將矢量擴(kuò)展到四維空間下辆童,即齊次坐標(biāo)空間宜咒。
齊次坐標(biāo)
對于一個三維向量,我們擴(kuò)展一個維度把鉴,分量稱為故黑。對于坐標(biāo),
常設(shè)為1庭砍,而對于方向场晶,常設(shè)為0。因?yàn)槲覀冎幌雽ξ恢眠M(jìn)行平移變換怠缸,方向不行诗轻。
基礎(chǔ)變換矩陣
我們使用一個的矩陣來表示平移、旋轉(zhuǎn)和縮放揭北。一個基礎(chǔ)的變換矩陣可以分解為4個部分:
表示旋轉(zhuǎn)縮放的矩陣扳炬,
表示平移吏颖。
平移矩陣
下面是一個平移矩陣(針對點(diǎn))的例子:
如果是方向矢量的話,由于分量為0恨樟,平移變換不會有影響:
平移變換的逆矩陣就是反向平移得到的矩陣:
平移矩陣并不是正交矩陣半醉。
縮放矩陣
下面是一個縮放矩陣(針對點(diǎn))的例子:
對方向矢量縮放:
如果,那么這樣的縮放為統(tǒng)一縮放,否則為非統(tǒng)一縮放劝术。由于非統(tǒng)一縮放會改變角度和比例信息奉呛,所以針對方向向量的縮放不能使用上述的方式。
縮放矩陣的逆矩陣如下:
縮放矩陣不是正交矩陣夯尽。
上面的矩陣只適合沿坐標(biāo)軸方向縮放瞧壮,如果要在任意方向縮放,就要使用一個復(fù)合變換匙握,先縮放軸咆槽,再沿坐標(biāo)軸縮放。
旋轉(zhuǎn)矩陣
繞x軸旋轉(zhuǎn):
繞y軸旋轉(zhuǎn):
繞z軸旋轉(zhuǎn):
旋轉(zhuǎn)矩陣是正交矩陣圈纺。
復(fù)合變換
大多數(shù)情況下秦忿,將平移、旋轉(zhuǎn)蛾娶、縮放結(jié)合起來的順序往往是:先縮放灯谣,后旋轉(zhuǎn),再平移蛔琅,也就是:
注意胎许,針對旋轉(zhuǎn)的順序,Unity的順序是zxy罗售,即旋轉(zhuǎn)變換矩陣是:
旋轉(zhuǎn)時的坐標(biāo)系有兩種可以選擇:
- 繞坐標(biāo)系E的z軸旋轉(zhuǎn)辜窑,繞y軸旋轉(zhuǎn),再繞x軸旋轉(zhuǎn)寨躁。即進(jìn)行一次旋轉(zhuǎn)時不一起旋轉(zhuǎn)當(dāng)前坐標(biāo)系穆碎。
- 繞E的z軸旋轉(zhuǎn),E繞z軸旋轉(zhuǎn)相同角度的E'职恳,繞E‘的y軸旋轉(zhuǎn)所禀,E’繞y軸旋轉(zhuǎn)相同角度的E'',最后繞E''的x軸旋轉(zhuǎn)放钦。即再旋轉(zhuǎn)時色徘,把坐標(biāo)系一起轉(zhuǎn)動。
在上述兩種方式中最筒,旋轉(zhuǎn)的結(jié)果不一樣邮偎,Unity是第一種暑竟。
坐標(biāo)空間
模型空間
模型空間即模型的局部坐標(biāo)系繁扎,在Unity中是左手坐標(biāo)系油航。
世界空間
世界空間被用來描述物體在場景中的位置,在Unity中邢锯,世界空間是左手坐標(biāo)系扬蕊。
將頂點(diǎn)從模型空間變換到世界空間的變換稱為模型變換(Model)。這一變換通常由組成丹擎。
觀察空間
也被稱為攝像機(jī)空間尾抑。
攝像機(jī)決定了我們渲染游戲所使用的視角。在觀察空間中蒂培,攝像機(jī)位于原點(diǎn)再愈,在Unity中,+x指向攝像機(jī)的右方护戳,+y指向攝像機(jī)的上方翎冲,+z指向攝像機(jī)的后方,即攝像機(jī)指向-z軸媳荒。
將頂點(diǎn)從世界空間轉(zhuǎn)換到觀察空間的變換為觀察變換(View)抗悍。
為得到頂點(diǎn)在觀察空間中的位置,有兩種方法:一是計(jì)算觀察空間的三個坐標(biāo)軸在世界空間下的表示钳枕,然后構(gòu)建出從觀察空間變換到世界空間的變換矩陣缴渊,再對矩陣求逆來得到從世界空間變換到世界空間的矩陣。二是想象平移整個觀察空間鱼炒,讓攝像機(jī)的原點(diǎn)位于世界坐標(biāo)的原點(diǎn)衔沼,坐標(biāo)軸與世界空間的坐標(biāo)軸重合即可。
這里使用第二種方法昔瞧,即想辦法讓攝像機(jī)變換到世界空間的原點(diǎn)即可(注意俐巴,由于觀察空間使用右手坐標(biāo)系,因此需要對z分量取反)硬爆。
裁剪空間
將頂點(diǎn)從觀察空間轉(zhuǎn)換到裁剪空間的變換矩陣稱為裁剪矩陣欣舵,也被稱為投影矩陣(Projection)。裁剪空間由視錐體決定缀磕。
視錐體是空間中的一塊區(qū)域缘圈,視錐體內(nèi)的區(qū)域是攝像機(jī)可以看到的空間。視錐體由六個平面構(gòu)成袜蚕,這些平面稱為裁剪平面糟把。視錐體有兩種類型,透視投影和正交投影牲剃。
在視錐體的裁剪平面中有兩塊很特殊遣疯,分別稱為近裁剪平面和遠(yuǎn)裁剪平面,它們決定了攝像機(jī)可以看到的深度范圍凿傅。
投影矩陣有兩個目的:
- 為投影做準(zhǔn)備
- 對x缠犀、y数苫、z分量進(jìn)行縮放
透視投影
我們利用上圖的參數(shù)可以計(jì)算出近裁剪平面和遠(yuǎn)裁剪平面的高度:
裁剪平面的寬度我們可以通過橫縱比得到。假設(shè)攝像機(jī)的橫縱比為:
根據(jù)上述信息辨液,投影矩陣為:
使用上述投影矩陣后:
可以看到虐急,投影矩陣本質(zhì)上是對x、y滔迈、z坐標(biāo)進(jìn)行一些縮放止吁,同時z分量也進(jìn)行了平移,縮放的目的是為了方便裁剪燎悍。此時w分量不再是1敬惦,而是-z,通過這個w谈山,我們可以判斷一個頂點(diǎn)是否在視錐體內(nèi)俄删,在的話必須滿足下面條件:
透視投影后,空間從右手坐標(biāo)系變?yōu)樽笫肿鴺?biāo)系勾哩。
正交投影
假設(shè)橫縱比為抗蠢,那么:
正交投影矩陣:
使用正交投影矩陣后:
使用正交投影后,w分量仍是1思劳。
屏幕空間
這一步的變換迅矛,我們會得到真正的像素位置。
將頂點(diǎn)從裁剪空間投影到屏幕空間有兩個步驟:首先進(jìn)行透視除法潜叛,用x秽褒、y、z分量除以w分量威兜。這一步得到的坐標(biāo)被稱為NDC销斟,經(jīng)過透視除法的裁剪空間變換到一個立方體內(nèi):
對于正交投影沒什么區(qū)別。
在Unity中椒舵,屏幕空間左下角的像素坐標(biāo)是(0,0)蚂踊。接下來就是將NDC縮放值屏幕坐標(biāo)系。
透視除法和屏幕映射的過程總結(jié)如下:
法線變換
法線是一個方向矢量笔宿,垂直于表面犁钟,與其垂直的一個矢量被稱為切線。
切線由兩個頂點(diǎn)之間的差值計(jì)算得來泼橘,因此可以使用變換頂點(diǎn)的變換矩陣來變換切線涝动。假設(shè)不考慮平移變換,變換后的切線為:
不過炬灭,如何直接這么變換的話醋粟,法線就有可能不垂直于表面了:
下面我們可以來推導(dǎo)一下正確的法線變換矩陣。
首先,切線與法線垂直米愿,即厦凤,假設(shè)變換法線的矩陣為
,變換后法線仍與切線垂直吗货,那么:
經(jīng)推導(dǎo)得:
由于泳唠,如果
狈网,則上式成立宙搬,即
。
如果變換矩陣是正交矩陣拓哺,那么G = M_{A->B}勇垛,當(dāng)然,這限于只包含旋轉(zhuǎn)變換士鸥。如果只包含旋轉(zhuǎn)和統(tǒng)一縮放闲孤,那么
。
Unity Shader的內(nèi)置相關(guān)數(shù)學(xué)變量
內(nèi)置變量:Built-in shader variables
內(nèi)置方法:Built-in shader helper functions