我們先講基于世界或模型坐標(biāo)的法線貼圖(world/object space normal map).不常用,但是基礎(chǔ).
首先,請(qǐng)無(wú)視你之前google到的所謂通過(guò)photoshop生成法線貼圖類似文章,美術(shù)除外.那只是一種利用近似hack的手法利用法線貼圖原理.無(wú)助于理解真正的過(guò)程.不過(guò)看完這文章后,你應(yīng)能理解Photoshop的這種做法的來(lái)歷.
不搞清法線貼圖的生成原理,是無(wú)法正確理解之后shader中的計(jì)算使用的.法線貼圖的出現(xiàn),是為了低面數(shù)的模型模擬出高面數(shù)的模型的"光照信息".光照信息最重要的當(dāng)然是光入射方向與入射點(diǎn)的法線夾角.法線貼圖本質(zhì)上就是記錄了這個(gè)夾角的相關(guān)信息.光照的計(jì)算與某個(gè)面上的法線方向息息相關(guān).
我們知道計(jì)算機(jī)里的模型,是通過(guò)多個(gè)多邊形面組合來(lái)近似模擬一個(gè)物體的.它不是圓滑的.面數(shù)越多,則越接近真實(shí)物體.光照到某個(gè)面當(dāng)中的一點(diǎn)時(shí),法線是通過(guò)這個(gè)面的幾個(gè)頂點(diǎn)通過(guò)插值得到的.插值其實(shí)也是為了模擬這個(gè)點(diǎn)"正確"的法線方向,不然整個(gè)面所有點(diǎn)的法線一致的話,光照上去,我們看到的模型夸張點(diǎn)就像一面面鏡子拼接起來(lái)了.但法線插值不可避免的仍然會(huì)失真.模型的面數(shù)越高,失真的程度自然越小.要是能無(wú)限細(xì)分到人眼看不出的地步,根本不用插值了.
面數(shù)高,需要計(jì)算的量和內(nèi)存需求就高.前輩找到了法線貼圖(前身是凹凸貼圖)這個(gè)辦法,使低模能夠近似享受高模的光照細(xì)節(jié)信息.代價(jià)是有的,就是需要一個(gè)記錄這些信息的文件.這是程序中常用的存儲(chǔ)空間換計(jì)算時(shí)間的做法.3D程序中偏愛(ài)使用這個(gè)手法.誰(shuí)叫存儲(chǔ)硬件的單位價(jià)格比計(jì)算硬件的單位價(jià)格降低速度快很多呢.
顯卡包括包括與之相輔的圖形api,讀的數(shù)據(jù)最初來(lái)源是圖片.所以記錄這個(gè)信息的文件就被我們保存為圖片格式.法線貼圖后邊2個(gè)字就這么來(lái)的.很好你已經(jīng)明白一半了.
我們?cè)賮?lái)弄清另一半.
因?yàn)槊鏀?shù)少,低模上某個(gè)區(qū)域的一個(gè)面,可能就是高模上相同區(qū)域的幾個(gè)面.看下圖的高模與低模的對(duì)比(為了簡(jiǎn)便我們抽象為2維的線段)
上邊凹凹凸凸的曲線表示高模.下邊比較平滑的表示低模.因?yàn)楦吣<?xì)節(jié)多,所以在某段區(qū)域它的方向變化自然比平平板板的低模多.上圖看不懂我表示無(wú)能為力.
看到這圖,一些人應(yīng)該有所感覺(jué)了.沒(méi)感覺(jué)也不要緊,接下再來(lái).
不管高模還是低模,反正最后還是要被上色的.假設(shè)模型已經(jīng)被渲染完成有顏色了,現(xiàn)在我們想象用剪刀把模型展開(kāi)(類似給動(dòng)物扒皮的過(guò)程),得到2張差不多一樣大小的皮,畢竟面積不會(huì)差太多.高模的皮當(dāng)然膚白體嫩精度高,低模的皮就有些糙了.現(xiàn)在再想象這么個(gè)過(guò)程:逐漸把高模的皮移到低模的皮上方一定高度直到水平重疊.
現(xiàn)在這個(gè)樣子你有感覺(jué)沒(méi)有?沒(méi)感覺(jué)也不要緊,接下再來(lái).
雖然模型精度不一樣,無(wú)論如何,這2張皮每一點(diǎn)都是有顏色了的(插值的功勞).兩張皮上相同一點(diǎn)的顏色,高模這張皮上的更真實(shí),因?yàn)樵谟?jì)算最終顏色信息所依賴的法線,高模上的點(diǎn)比低模上的點(diǎn)更精確.我們?nèi)绾谓o低模這張皮美容,使它能夠接近高模的效果呢?換句話說(shuō),找到辦法,使土肥圓演變?yōu)楹谀径?質(zhì)變?yōu)榘赘幻朗遣豢赡艿?那得下輩子.
辦法很暴力.現(xiàn)在再想象你用一根針,從上往下,刺穿高模的皮,再刺到低模的皮.保證針垂直,這樣就刺到同一點(diǎn)了.再想象如果這針有魔力的話,它刺穿高模皮的過(guò)程中,盜取了一些信息,傳送到低模皮上邊.低模皮依靠這些信息計(jì)算,成功蛻變?yōu)楹谀径?這些信息是什么呢?當(dāng)然是法線信息了.現(xiàn)在高模這張皮被密密麻麻插滿了針眼,換句話說(shuō),保存高模泄漏來(lái)的信息,必定是點(diǎn)對(duì)點(diǎn)的.即這張皮上的每個(gè)點(diǎn),都得被保存.所以法線貼圖跟原始的貼圖是一樣大小的,貼圖內(nèi)每個(gè)點(diǎn)都保存了對(duì)應(yīng)高模某個(gè)點(diǎn)的法線信息.實(shí)際的計(jì)算,只會(huì)關(guān)心由貼圖里得來(lái)的法線信息,低模上的那些法線,被拋棄了.
現(xiàn)在這個(gè)樣子你有感覺(jué)沒(méi)有?沒(méi)感覺(jué)也不要緊,接下再來(lái).
如何賦予這根針魔力呢?宅男們,甘道夫是幫不了你的忙的.偉哥也幫不了你.只有數(shù)學(xué),才能拯救世界...
為什么我之前強(qiáng)調(diào)垂直呢?不只是為針能扎到同一點(diǎn).現(xiàn)在請(qǐng)把這個(gè)過(guò)程,想象到上圖中.圖中的箭頭,表示高模上某個(gè)點(diǎn)的法線方向.如何記錄這個(gè)方向信息?現(xiàn)在請(qǐng)想象逐漸把高模和低模重疊在一起,為了方便想象,低模小一些被高模包住了.或者你干脆想象高模的面在低模面的正上方,或一個(gè)圓球里有一個(gè)內(nèi)切的正多面體.再想象有一束光線(針的等價(jià)物),從上往下照射,把高模上的法線投射到低模上.
現(xiàn)在你有感覺(jué)了吧.
前戲大功告成,現(xiàn)在我們來(lái)處理稍微細(xì)節(jié)些的問(wèn)題了.這是一個(gè)投影過(guò)程.但是影子是2維的啊?向量是由x,y,z三個(gè)分量構(gòu)成的.高模上某點(diǎn)投影到低模上對(duì)應(yīng)點(diǎn)所在平面,只剩2個(gè)分量的投影了.好比我們現(xiàn)在只知道法線在x-y平面的投影方向,那在z軸的方向呢?只要我們確保投影前法線是單位向量,那很簡(jiǎn)單z=1-x*x-y*y.這樣我們還可以省下保存z的空間.其實(shí)我們既然已經(jīng)知道這個(gè)法線方向(高模object space內(nèi)的法線方向),而且被單位化了,直接保存也是可以的.投影過(guò)程只是個(gè)思想實(shí)驗(yàn),實(shí)際是不會(huì)有什么光線由上到下投射的.
到此可以明確了,"正統(tǒng)"的法線貼圖生成,是高模,低模不可缺一的.因?yàn)闆](méi)有高模就不知道法線方向,沒(méi)有低模,就不知道高模上某點(diǎn)的法線對(duì)應(yīng)于低模上哪個(gè)點(diǎn).
因?yàn)槟滁c(diǎn)的法線信息是被保存到法線貼圖上對(duì)應(yīng)像素點(diǎn)的.實(shí)際計(jì)算是把法線x,y,z方向大小映射到顏色空間rgb里.就是把x值存在r里,把y值存在g里,把z值存在b里.因?yàn)閞gb是8字節(jié)為單位的.所以高模的法線信息存儲(chǔ)到像素里是要丟失精度的.而且前面計(jì)算高模與低模對(duì)應(yīng)點(diǎn)也不可能完全匹配到,本來(lái)就是個(gè)模擬過(guò)程.自然法線貼圖也不是無(wú)敵的.
現(xiàn)在我們可以回答之前的Photoshop根據(jù)diffuse貼圖生成法線貼圖的問(wèn)題了.實(shí)際的diffuse貼圖是根本沒(méi)有包含模型上的法線信息的.因此它根據(jù)diffuse貼圖得出的法線貼圖根本就是錯(cuò)誤的.但為什么能夠應(yīng)用呢?請(qǐng)想象高模的精度高的嚇人,高到渲染后把高模皮扒下來(lái)后,就成了一張照片.再想象之前高模上的貼圖是布滿了鐵銹.于是你就得到了一張鐵銹照片.Photoshop處理這張鐵銹照片,其實(shí)是根據(jù)一些算法(sobel等等)把顏色值轉(zhuǎn)化為梯度值,近似模擬了法線.因?yàn)槲覀兤鋵?shí)不關(guān)心鐵銹的精確分布,像那么一回事就可以了,所以這種情況下如此處理是可以將就的,坑坑洼洼效果最適合如此做法.photoshop這種脫離高模低模的做法容易讓人迷惑,導(dǎo)致新手以為法線是從diffuse貼圖上來(lái)的,或者干脆被阻斷了思路.
我們上邊計(jì)算法線貼圖所用到的法線,又是從哪里來(lái)的.如果這個(gè)法線方向,是處于世界坐標(biāo)中的(world space),那稱為world space normal.如果是處于物體本身局部坐標(biāo)中的,那稱為object space normal.很容易想象,world space normal一旦從貼圖里解壓出來(lái)后,就可以直接用了,效率很高.但是有個(gè)缺點(diǎn),這個(gè)world space normal 是固定了,如果物體沒(méi)有保持原來(lái)的方向和位置,那原來(lái)生成的normal map就作廢了.因此又有人保存了object space normal.它從貼圖里解壓,還需要乘以model-view矩陣轉(zhuǎn)換到世界坐標(biāo),或者轉(zhuǎn)換到其他坐標(biāo)取決于計(jì)算過(guò)程及需求.object space normal生成的貼圖,物體可以被旋轉(zhuǎn)和位移.基本讓人滿意.但仍有一個(gè)缺點(diǎn).就是一張貼圖只能對(duì)應(yīng)特定的一個(gè)模型,模型不能有變形(deform).
>> tangent space normal map
為解決適應(yīng)變形的normal map,我們?nèi)阅軓倪@兩種方法中得到啟示.world space normal直接保存的是世界坐標(biāo)系中的高模法線方向.因此低模取出該點(diǎn)法線就可以直接使用,前提是低模的世界坐標(biāo)系與高模一致,一點(diǎn)旋轉(zhuǎn)都不能有,不然法線方向就改變了.object space normal保存的是模型空間坐標(biāo)系中的高模方向,低模取出該點(diǎn)取出來(lái)法線,還需要乘以所在的model-view矩陣,轉(zhuǎn)化為低模的世界坐標(biāo)系中的方向,也就是說(shuō)低模端還需要做一個(gè)運(yùn)算.因此即使低模任意旋轉(zhuǎn)也不怕,有model-view矩陣可以把法線貼圖中的值轉(zhuǎn)換兩者效率由高到低,靈活度由低到高.問(wèn)題來(lái)了,我們是否能找到高模上的另外一個(gè)坐標(biāo)系統(tǒng),使低模變形也時(shí)也能較正確的變換法線到世界坐標(biāo)系中?
我們考察一下object space.當(dāng)一個(gè)低模旋轉(zhuǎn)時(shí),因?yàn)槭莿傮w不變形,相當(dāng)于每個(gè)點(diǎn)都乘以一個(gè)旋轉(zhuǎn)矩陣R,之后各點(diǎn)關(guān)系保持不變.實(shí)際上,我們保持物體不旋轉(zhuǎn),將object space的坐標(biāo)系(x,y,z三個(gè)軸)旋轉(zhuǎn),得到的結(jié)果是一樣的.這個(gè)關(guān)系相信大家都能理解.換句話說(shuō),法線針對(duì)于object space是固定不動(dòng)的,物體保持在object space固定,只管跟隨坐標(biāo)系的移動(dòng),旋轉(zhuǎn)就行了.現(xiàn)在我們想象低模的某個(gè)點(diǎn)需要變形時(shí),那原則上也可以通過(guò)讓object space坐標(biāo)系乘以某個(gè)變形矩陣T來(lái)達(dá)到.但是不同的點(diǎn)有不同的變形,不可能存在一個(gè)矩陣T即適合這個(gè)點(diǎn)又適合這個(gè)點(diǎn).因此object space坐標(biāo)系是不能用的.會(huì)有哪個(gè)單一的坐標(biāo)系能存在一個(gè)所有點(diǎn)都共用的變形矩陣嗎?顯然無(wú)法想象.
變形時(shí),頂點(diǎn)關(guān)系改變了,即面的形狀,方向改變了.如果面上存在一個(gè)固定的坐標(biāo)系,那當(dāng)物體變形,移動(dòng),旋轉(zhuǎn)時(shí),這個(gè)坐標(biāo)系必定跟著面一起運(yùn)動(dòng),那么在這個(gè)坐標(biāo)系里的某個(gè)點(diǎn)或向量(比如我們把高模法線轉(zhuǎn)換到這個(gè)坐標(biāo)系里),不需要變動(dòng).當(dāng)整個(gè)面發(fā)生變化時(shí),我們只需要計(jì)算面上的坐標(biāo)系到世界坐標(biāo)系的轉(zhuǎn)換矩陣,那么定義在這個(gè)面上的點(diǎn)或坐標(biāo)(固定的),乘以這個(gè)矩陣即可得到在世界中的坐標(biāo).這個(gè)坐標(biāo)如何構(gòu)造目前對(duì)我們不重要,請(qǐng)務(wù)必理解這個(gè)概念.我們不過(guò)是尋求一個(gè)局部坐標(biāo)系,局部坐標(biāo)系中的點(diǎn)坐標(biāo),乘以局部坐標(biāo)系到世界坐標(biāo)系的轉(zhuǎn)換矩陣(這個(gè)矩陣是低模渲染時(shí)動(dòng)態(tài)計(jì)算的的),得到局部坐標(biāo)系中的點(diǎn)在世界坐標(biāo)系中的坐標(biāo).這樣法線貼圖中存儲(chǔ)的固定的值(法線方向),才能進(jìn)行有意義的計(jì)算.
看到這里很明顯的,這種做法需要數(shù)千個(gè)不同的定義在面上的坐標(biāo)系.低模上有多少個(gè)面,就得有多少個(gè)這樣的坐標(biāo)系.這種方法的計(jì)算量自然是比object space normal map要大一些的.在低模的每個(gè)面上,要構(gòu)造出這個(gè)坐標(biāo)系.這個(gè)坐標(biāo)系術(shù)語(yǔ)里稱為tangent space.
object space normal map的中,低模的object space坐標(biāo)系與高模中的object space坐標(biāo)系是重合的.所以不需要構(gòu)建,所以低模上某點(diǎn)才能直接用高模的法線替換自己的法線.坐標(biāo)系重合這個(gè)概念很重要.新方法中,低模上的這個(gè)tangent space,也必須與高模上的坐標(biāo)系tangent space.因?yàn)榈湍I系囊粋€(gè)面,可能對(duì)應(yīng)了高模上的幾個(gè)面(精度高),按照新方法每個(gè)面都有一個(gè)局部坐標(biāo)系,那對(duì)于低模上的每個(gè)面,高模因?yàn)榇嬖诤脦讉€(gè)面,就會(huì)出現(xiàn)好幾個(gè)局部坐標(biāo)系,這肯定是不行的.所以高模所用的tangent space,就是低模上的.生成法線貼圖,必定會(huì)確認(rèn)高模上哪些面都對(duì)應(yīng)低模上的哪個(gè)面,然后高模上的這幾個(gè)面的法線,都會(huì)轉(zhuǎn)換為低模這個(gè)面上所構(gòu)建的tangent space的坐標(biāo).這樣,當(dāng)?shù)湍W冃螘r(shí),即三角面變化時(shí),它的tangent space也會(huì)跟著變化,保存在貼圖里的法線乘以低模這個(gè)面的tangent space到外部坐標(biāo)系的轉(zhuǎn)換矩陣即可得到外部坐標(biāo).順便再提一點(diǎn),高模保存的這個(gè)法線,是高模上object space里的法線,看到這里你該明白這是自然而然的.你搜索文章時(shí)可能會(huì)看到什么把光轉(zhuǎn)換到tangent space里,確保處于同一個(gè)坐標(biāo)系下的話.確實(shí)是這樣.但初次接觸卻還是模糊.我以為確保tangent sapce重合及做法,才是讓人頓悟tangent space的訣竅點(diǎn).
上圖稍微清楚一些了.曲線表示高模,P點(diǎn)處有TBN坐標(biāo)系.線段表示低模,M點(diǎn)處有T'B'M坐標(biāo)系.高模上P點(diǎn)處的法線轉(zhuǎn)換到TBN坐標(biāo)里,與N的夾角為NPN'.低模處取出這個(gè)法線為N'',與低模的PM(面法線)夾角為PMN''.可以看到這2個(gè)夾角是近似的.所以渲染時(shí)高模上的法線,是基于低模上的這個(gè)坐標(biāo)系運(yùn)算的.你可能會(huì)說(shuō),我這的TBN不就是實(shí)際的高模面上的左邊嗎?別忘了很可能幾個(gè)高模的面擠在一起對(duì)應(yīng)一個(gè)低模的面,高模的這個(gè)TBN必然是經(jīng)過(guò)一種“插值”或“平均”得來(lái)的,實(shí)際上也會(huì)跟低模有些相關(guān)性,以求最匹配的效果。具體如何得來(lái)未深究,有高手可否告知否?
當(dāng)我自己想到上邊這段話時(shí),tangent space的法線貼圖原理就豁然開(kāi)朗了.接下來(lái)我們構(gòu)建這個(gè)tangent space坐標(biāo)系.
面在動(dòng)時(shí),tangent space也得跟著動(dòng).面上的垂直法線是跟著動(dòng)的,因此這個(gè)法線N可以作為tangent space的一個(gè)坐標(biāo)軸.非常非常需要注意的是,這里所說(shuō)的面上垂直法線,不是指插值所得來(lái)的法線,那個(gè)法線正是是我們需要保存的內(nèi)容.N單純就是指垂直于這個(gè)面的方向.
我們考察上圖,對(duì)于一個(gè)三角面,它的邊V2V1,V3V1,V3V2我們總是能夠確定的.邊也定會(huì)在變形時(shí)跟著動(dòng).因此我們可以選擇一條邊作為tangent space的第二個(gè)坐標(biāo)軸T.第三個(gè)坐標(biāo)軸就簡(jiǎn)單了,直接根據(jù)叉積來(lái)B=T * N.這個(gè)坐標(biāo)軸就訂好了.其實(shí),坐標(biāo)軸的選定幾乎可以是任意的,只要你能夠確保每次都能構(gòu)建出來(lái).比如你可以先選擇V1V3,V1V2作為坐標(biāo)軸,N=V1V3 * V1V2.這里N恰好和前面一樣方向.但如此一來(lái)這個(gè)坐標(biāo)系中V1V2,V1V3不是垂直的,不正交的坐標(biāo)基在矩陣運(yùn)算中是不方便的,還得正交化.因此我們選擇第一種最直觀最清晰最方便的方法.
既然三個(gè)坐標(biāo)軸都確定了,那構(gòu)建object space到tangent space的矩陣O-TBN就簡(jiǎn)單了,我們把T,B,N單位化,分別作為tangent space的x,y,z軸.根據(jù)三個(gè)坐標(biāo)基我們構(gòu)造矩陣如下:
O-TBN =
高模上object space內(nèi)的某點(diǎn)法線(不會(huì)是world space的,否則旋轉(zhuǎn)就露相),乘以這個(gè)矩陣,即得到tangent space內(nèi)的法線方向,再把這個(gè)值映射到rgb空間,存為貼圖即可.這個(gè)矩陣為什么是這樣,這是題外話了.我簡(jiǎn)略說(shuō)一下:object space的三個(gè)坐標(biāo)軸(1,0,0),(0,1,0),(0,0,1)乘以這個(gè)矩陣,必須剛好為tangent space中的坐標(biāo)軸,很自然矩陣就是上邊的樣子.而object space其他點(diǎn)的坐標(biāo)都是x,y,z三個(gè)單位坐標(biāo)的線性組合.所以這個(gè)矩陣對(duì)于其他點(diǎn)必定是正確的.
實(shí)際上在vertex shader中,我們只能知道當(dāng)前頂點(diǎn)的信息,三角形的另外兩個(gè)頂點(diǎn)我們是不知道的.但現(xiàn)代的shader能夠?yàn)轫旤c(diǎn)提供一個(gè)tangent信息,表示在頂點(diǎn)處的切線.你可以想象一個(gè)足球上經(jīng)過(guò)某點(diǎn)的切線.因此我們會(huì)把頂點(diǎn)的tangent方向作為上邊的T向量.這也是tangent space叫這個(gè)名稱的由來(lái).你會(huì)看到很多文章中提到紋理的u,v方向.因?yàn)槊嫔夏滁c(diǎn)的u,v是沿各條邊線性插值的,所以u(píng),v方向與邊的方向相同.其實(shí)我們現(xiàn)在已經(jīng)有現(xiàn)成的tangent可以用了.
現(xiàn)在我們可以分析為什么tangent space法線貼圖是偏藍(lán)色了.因?yàn)閷?duì)于高模上的面來(lái)說(shuō),因?yàn)榫忍?面很小,而且周圍的面相對(duì)它的方向很平滑),所以這個(gè)面渲染時(shí)計(jì)算機(jī)認(rèn)為這個(gè)面的"彎曲"程度很小,即面上各個(gè)點(diǎn)插值得來(lái)的法線相互間偏差很小.基本跟整個(gè)面的垂直方向不會(huì)差太多.因此在tangent space里,這些法線都跟z軸偏差較小.而z軸是被保存在貼圖里的b字節(jié)處(藍(lán)色通道)里.所以貼圖顯示出來(lái)的顏色就偏藍(lán)了.
好了,現(xiàn)在高模面上各點(diǎn)的法線值,都轉(zhuǎn)換為低模上的tangent space坐標(biāo)了.現(xiàn)在我們考慮具體的低模上的渲染計(jì)算了.假設(shè)在低模上的某個(gè)面我們計(jì)算出了這個(gè)矩陣,并取出了面上某點(diǎn)的對(duì)應(yīng)在法線貼圖里法線值.現(xiàn)在需要計(jì)算光照.我們可以把光向量轉(zhuǎn)換到tangent space里做計(jì)算.也可以把得到的法向量轉(zhuǎn)換到world space與光向量進(jìn)行計(jì)算.結(jié)果是一樣的.實(shí)際考量,你會(huì)發(fā)現(xiàn)后一種方法不好.因?yàn)閷?duì)于面上的每個(gè)點(diǎn),都要計(jì)算一次normal到world space的準(zhǔn)換.而前一種方法,對(duì)一個(gè)面上的所有點(diǎn),只要計(jì)算一次光向量到tangent space的計(jì)算.然后再考慮到vertex shader與fragment shader的流程,你會(huì)發(fā)現(xiàn)剛好我們可以在vertex shader計(jì)算光線到tangent space的轉(zhuǎn)換,在fragment sader取出法線值與前面得到的tangent space里的光線方向做計(jì)算即可.這里提醒一下,一般verteix shader中我們得到的光線方向是基于world space的,而法線貼圖保存的是高模的object space內(nèi)的方向然后再轉(zhuǎn)換到tangent space,所以在vertex shader中,我們必須先把光線先轉(zhuǎn)換到object space,再轉(zhuǎn)換到tangent space.這樣才能保證最終計(jì)算時(shí),光線與法線是基于同一個(gè)坐標(biāo)系的.這也是你在很多normal map的shader里,看到類似ToOjectSpaceDir(lightDir)之類函數(shù)的原因,正是要把光轉(zhuǎn)換到object space.
實(shí)際做法可能會(huì)有些復(fù)雜.比如有些模型是鏡像對(duì)稱,貼圖也是鏡像對(duì)稱的,計(jì)算時(shí)會(huì)省去另一半等等.這時(shí)如何處理看具體的法線貼圖生成軟件和處理它的引擎(shader)了.基本原理還是上邊所說(shuō)的.
tangent space normal map適應(yīng)變形的這種能力,使它不僅能夠應(yīng)用在原來(lái)的模型上邊,甚至可以應(yīng)用在變形嚴(yán)重的不同模型上.即法線貼圖有一定的脫離原來(lái)模型使用的能力.比如你模擬出了一個(gè)高精度的粗糙花崗巖平板表面,得出的法線貼圖可以應(yīng)用到圓柱模型上邊.類似photoshop的直接根據(jù)花崗巖表面照片生成法線貼圖也是能夠使用的.因?yàn)槟康鼐褪菫榱宋⑿〉臄_動(dòng)法線生成凹凸不平的表面.雖然這個(gè)表面并不是正確的還原一個(gè)真正存在的花崗巖表面.但圖形學(xué)不就是一個(gè)模擬過(guò)程,能足夠真實(shí)的欺騙我們的眼睛就行.其實(shí)這種粗糙表面微小擾動(dòng)只是應(yīng)用之一.你搜到一些處理的好的圖片,不仔細(xì)看你會(huì)發(fā)現(xiàn)低模的怪物會(huì)以假亂真體現(xiàn)出高模才有的平滑彎曲.
以上是法線貼圖的原理.因?yàn)樵撛淼膽?yīng)用范圍很廣,也能夠串起很多知識(shí)點(diǎn),是非常值得搞清楚的.我當(dāng)初在學(xué)習(xí)法線貼圖過(guò)程中,沒(méi)有看到能夠講的讓我清晰明白整個(gè)過(guò)程的.遂作此篇.
這是本篇文章的引用來(lái)源之一:
http://www.gamasutra.com/view/feature/129939/messing_with_tangent_space.php?PRint=1
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注