最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

【深入淺出】法線貼圖與切線空間(上)

2023-03-08 09:28 作者:獨立游戲人-老雷  | 我要投稿

前言

今天給大家分享的是法線貼圖與切線空間深入淺出的介紹

如果大家之前做過一些shader效果,那么很有可能用過法線貼圖,但是今天要講的法線貼圖跟大家平時在學習,在使用過程中接觸的法線貼圖,會有一些不一樣的地方

在過去學習法線貼圖的時候,更多的是立足于如何去使用它。但是對于它背后的一些技術(shù)實現(xiàn)可能是囫圇吞棗的

所以今天給大家分享的就是法線貼圖背后的一些技術(shù)原理

版權(quán)聲明

本文為“優(yōu)夢創(chuàng)客”原創(chuàng)文章,您可以自由轉(zhuǎn)載,但必須加入完整的版權(quán)聲明

更多學習資源請私信獲取(企業(yè)級性能優(yōu)化/熱更新/Shader特效/服務器/商業(yè)項目實戰(zhàn)/每周直播/一對一指導)

點贊、關(guān)注、分享可免費獲得配套學習資源

完整視頻請點擊觀看

議題


  1. 什么是法線?

  2. 如果模型表面本身是沒有定義法線數(shù)據(jù)的,unity如何生成法線?

  3. 當你去寫法線相關(guān)的一些功能的時候,過去會把法線進行一個單位化,在進入片元著色器的時候,法線究竟要不要單位化

  4. 有的時候為了調(diào)試法線的效果,看它是否正確,我們需要把法線進行可視化,那么如何將法線可視化<便于調(diào)試>呢?

  5. 如何利用法線來進行光照計算?大家知道用法線進行光照計算的方式是:用法線跟燈光方向進行點乘得到一個光照強度,那具體該怎么做呢?

  6. 法線在空間變換上,有一定的特殊性,它跟頂點位置、空間變換方式是不一樣的,法線在空間變換上的特殊性在哪里?

  7. 法線貼圖的錯誤用法有哪些?

  8. 法線貼圖的色彩空間,這個也是大家很容易忽視的一點

  9. 法線貼圖的編碼和解碼

  10. 切線空間的構(gòu)成

  11. 法線貼圖在使用的時候,可能遇到一些錯誤,這些錯誤,很多是跟里面進行正確的空間坐標處理有關(guān)系的,所以我們會在切線空間里面做很多的運算,那么如何去生成這個物體表面的切線,如何正確的運用切線空間和運用法線貼圖來進行光照計算?

  12. 如何正確利用法線貼圖計算光照

  13. 法線貼圖shader的性能優(yōu)化

如何不添加小球模型,把小球畫出來?



在左邊這幅圖上面,在一個四邊形的平面上放置了一些小球,我們把這些小球按照小球自身的法線來進行圖形渲染,得到了一個3D的帶小球的面板的圖像

但是很多時候,大家可以想象一下,如果場景里面有很多物件,這些物件有的非常小,那么即使是一些非常小的物件,如果要把這些物件刻畫的非常精細,它的性能開銷也是非常大的

所以我們想一想,有沒有一種既可以節(jié)省性能,又能把物體刻畫的比較精細的方法呢?

大家看右邊這個圖,右邊這個圖是在場景里面沒有放置任何一個小球的模型,只是貼了一張法線貼圖,大家就能看到它渲染出來的效果,看上去就像是場景里面有16個小球一樣,非常逼真

這就是我們的今天的文章要解決的問題:

  • 如何不添加小球模型,把這些小球給畫出來呢?

什么是法線?

要把這些小球在沒有小球模型的情況下渲染出來,首先我們需要用到法線,那么我們來了解一下究竟什么是法線


先從最簡單的2D情況看起,假設在場景里面,有兩個點,我們可以把這兩個點構(gòu)成一條線,這條線構(gòu)成了一個平面,由線去分割了這個屏幕空間當中的兩個平面


這個時候,我給這條線畫一條垂線,這條垂線是跟這個兩個點構(gòu)成的,是互相垂直的

接著我在垂線上面其中一個方向和另外一個方向去計算表示方向的,我們叫做向量,向量的長度值是1,我們把這種長度為1的,代表線段構(gòu)成的平面的方向的線段,我們就叫它向量


因為跟這條線段垂直的垂線有兩條,我們通常約定,這兩個方向向量并不都是法線向量,只有代表物體表面正方向的那個向量,叫它法線向量


假設這這個線段構(gòu)成的平面是上圖這樣的,假設約定它的正方向是鼠標所在的這個方向,只有這一條垂線長度為1的垂線構(gòu)成的方向向量為法線向量

這就是法線的基本概念,它代表了一個物體(不管是2D還是3D),它的物體表面的方向

法線可以做什么呢?


首先法線可以用來做物理運算,就比如說大家看在我們的圖片上面,可以看到有一個小球,這個小球在物體表面進行彈跳


我們知道一個物體的彈跳,小球的彈可以拆成兩個方向的運動

  • 第一個水平方向:是在物體表面的平面的這個方向進行運動

  • 第二個垂直方向:是在物體表面的法線的反方向以及物體表面的法線方向上進行上下的彈跳

  • 同時在水平方向上面進行水平運動

在游戲當中,定義了物體表面的法線以后,就能夠讓小球在法線的正面進行運動,而不是在這個物體表面的背面

因為我們知道物體表面的垂線有兩個方向,但只有一個法線方向,當我定義了法線就不會讓物體在表面的背面進行運動


當我知道了物體表面的法線以后,同樣我也可以讓游戲的主角瑪麗奧,在物體表面的正面進行運動,而不是在背面來進行滑動


剛才我們說的是在二維空間中的情況,前面我們說了在二維空間當中兩個點構(gòu)成一個線段,它會有一個法線方向


同理在三維空間當中,我們可以通過三個點定義一個三角形,跟三角形所在的平面,大家看這個白色的平面,垂直的方向向量,我們就叫它法線向量

同樣的道理,跟平面垂直的法線方向有兩個,只有其中一個代表了這個物體表面的法線方向,那么在unity引擎當中是如何確定的呢?到底是上圖中朝上的向量還是朝下的呢?

其實在unity當中,能夠根據(jù)一定的圖形學算法來進行計算,那怎么計算呢?這里面牽涉到一些相對復雜的數(shù)學概念,簡單來看是這樣的:(參照上圖)

  • 我們在unity當中可以定義三個點,點a、點b、點c,假設我們的物體是按照這個abc的順序來定義的

  • 在計算物體表面的法線方向的時候,用a跟b的連線構(gòu)成一個向量,再用a跟c的連線構(gòu)成第二個向量,這時候unity內(nèi)部采用了一種叫做左手定則的方式,什么叫左手定則呢?

  • 大家現(xiàn)在可以把左手伸出來,伸出來以后,除了大拇指以外的另外四根手指,從a,b的方向往a,c的方向去繞

  • 當你的四根手指卷起來以后,把你的大拇指豎起來,這個時候大拇指的方向,一定是朝上的

  • 注意是左手不是右手,如果是右手,那么卷出來的方向應該是朝下的,而unity內(nèi)部使用的是左手定則

具體的內(nèi)部實現(xiàn),大家可以參考我們的unity小白的TA之路

大家再想一想另外一個問題:

  • 如果反過來,在我們確定頂點順序的時候,假設我把C點確定為第二個點,把B點確定為第三個點,這個時候就是a跟c構(gòu)成第一個向量,a跟b構(gòu)成第二個向量

  • 在進行叉乘的時候,再把左手伸出來看一下,如果頂點順序是acb,這個時候算出來的法線方向就應該是朝下的

  • 這樣就明白了unity內(nèi)部,究竟是怎么去這個計算從而得到每一個三角形的法線方向,也就是三角形的正面方向的,這樣我們就明白了unity內(nèi)部運算的原理是什么了

  • 所以我們學習的時候千萬不要浮于表面,在網(wǎng)上面找一個現(xiàn)成的shader效果拿過來抄,那是沒有用的

如何求得法線?


剛才我們講了unity內(nèi)部的工作原理,但實際上我們在項目里面需不需要自己寫程序把模型表面的法線方向一個一個手工算出來呢?

是沒有必要的,因為unity在內(nèi)部已經(jīng)提前幫我們,當你去導入這個模型的時候,有一個默認值,它的默認值實際上已經(jīng)提前幫我們把這些東西都算好了

當你選中unity里面的一個幾何體的模型,這個模型有一個叫做“Normals“的選項,這個選項有三個值:

  • 第三個選項是叫做None,大家知道在英文里面的意思就是空

  • 另外一個,叫做**Import,**也就是說在美術(shù)軟件,在dcc建模軟件里面,我可以讓項目組的美工提前在建模軟件里面把法線生成好,然后在unity里面,只要導入這個法線就可以了,這是第二種情況

  • 第三種情況就是我剛才講的,哪怕你的模型沒有法線,我們也可以讓unity自己去算,怎么算呢?就是用我剛才講的左手定則來進行運算,如果你選的是Calculate,也就是自動計算這一項,它就能夠把法線在導入模型的時候自動算出來

我再舉個例子,比如說像我們在小白的TA之路里面,有一個案例:去繪制原神角色

  • 因為我們知道原神的角色是一個二次元的角色,二次元的角色有個特點,就是角色要進行描邊,為了防止角色在描邊的時候出現(xiàn)描邊斷裂,我們就需要在unity當中用代碼對模型表面的法線進行重組,這里重組具體怎么重組,我們先不細說

  • 當了解了剛才講的左手定則以后,就能把三角面的法線算出來,進一步就能夠?qū)τ诿恳粋€頂點上面的進行描邊的法線平均化工作,這樣就可以讓原神的角色不會出現(xiàn)描邊斷裂的問題

  • 什么是描邊斷裂?給大家簡單講一下:假設這邊有一個立方體,如果我給這個立方體描邊,如果你不做特殊處理計算機里面的描邊是怎么描的呢

如上圖右側(cè)所示,上面描一下,左邊這塊描一下,右邊這塊描一下,下邊這塊描一下,大家看描完以后出現(xiàn)什么問題?

  • 在區(qū)域四個角上面就出現(xiàn)了斷裂,所以當我們把法線做過特殊處理以后,就不會出現(xiàn)斷裂問題了

如何使法線平滑?


在程序當中,我們可以自己去實現(xiàn)物體表面法線的平滑工作,unity其實也為我們準備了相似的選項,這個選項叫做Smoothing angle ,Smoothing就是平滑,angle就是角度

也就是說選項的功能,是按照三角形之間的夾角對法線進行平滑的工作,大家可能看這個選項,會覺得有點陌生,什么叫做按照三角形之間的夾角來進行平滑呢?我們來看下面這個例子


這兒有一個三角形,按照左手定則,我們可以把三角形的法線算出來,但是為了讓三角形的法線更加精細,我們不應該是一個三角形一個法線,而是讓三角形上面的每一個頂點有一個法線

因為一個物體它可能有很多個三角形構(gòu)成,并且這些三角形是緊挨著的,也就是說像第三幅圖中,兩個三角形是共用一條邊的,在圖形學當中,我們把共用一條邊,用紅色表示的兩個點進行合并,合并成一個頂點

這時候有個問題了,假設左邊這個三角形,它的法線朝向是朝左,右邊這個三角形,它的法線朝向是朝右。那么這個頂點中間這個頂點,它的法線朝向應該是朝哪里呢?怎么計算呢?

不管用unity、ue,還是用cocos、laya,在圖形學里面都是這么做的:

  • 首先,找到左邊三角形的法線

  • 然后跟右邊三角形的法線進行連接

  • 從頂點的底部連到兩個向量加出來的頂部的向量,這個向量的方向就代表了最終的兩個三角形共用的頂點上面的法線方向


最后的結(jié)果就是什么呢?一個頂點它的法線可能是朝左的,另一個頂點的法線方向可能是朝右的,那么中間這兩個點算出來的法線,就是在左邊和右邊的方向的中間,并且法線只是代表方向,最終我們在進行運算的時候會有一個步驟叫做單位化

  • 單位化是干什么呢?

  • 就是把非常長的向量縮短到長度為一的向量

這就是使法線進行平滑的技巧,但unity是不是把任何的法線都進行平滑呢?

  • 比如說有一個三角面,它是朝左的,另外一個三角面呢,是朝右的,unity默認夾角在多少度以內(nèi),比如說夾角在60度以內(nèi),才去把這個頂點進行共享,然后計算出來平均化的頂點的法線朝向

  • 如果兩個三角面,一個是朝左,一個是朝右,兩個夾角是180度,那么unity有沒有可能把這樣的三角形進行頂點共用、法線共用呢?答案是不可能的!

那么究竟在什么角度把頂點進行共用,unity給我們開放的選擇權(quán)怎么選擇呢?我們回到上面這個圖


當你點中一個模型的時候,就能看到這個屬性面板,如果完全不需要三角面的頂點共用,就把拉桿拉到最左邊,讓它的值為零,就是沒有任何一個三角形進行法線平均化

通常來講,我們會把這個值調(diào)大,默認值是60,60度角以內(nèi)的兩個三角形,它們會進行法線的平均化

最終做出來效果,就是大家在圖片上看到的,左邊這個是完全沒有法線平均化的,這個球就看上去比較的平面化,右邊這個球是利用法線平均化的,它看上去就是一個比較圓滑的小球


這些都是我們平時在開發(fā)shader的時候,在使用模型的時候,根本不會注意到的一些點

在這兒再說一個小知識,明明只是調(diào)整了物體表面的法線,為什么讓物體的顏色看上去變成連續(xù)的呢?

實際上我們是利用了光照計算的一些原理,這個原理是什么樣的呢?

  • 假設物體表面的法線是比較平滑的,這個時候它算出來的光照強度值也是比較平滑的,當我用比較平滑的光照強度值進行物體表面的著色的時候,畫出來的顏色看上去就比較連續(xù),實際上是利用了人眼的視覺欺騙

  • 并不是這個物體本身的模型變平滑了,只是讓這個法線的方向變得比較平滑,這樣就使物體計算出來的光照看上去是平滑的,就會認為這個模型是平滑的,但本身這個模型是不平滑的

實際上就是我們把物體表面的法線用顏色的方式畫出來,法線是一個數(shù)值,如下圖圓上的紅色箭頭是法線方向


物體都有X坐標,Y坐標,Z坐標,所以在這兒的法線數(shù)值可能X值偏左,偏左就是從原點往X的負方向,它可能是負的0.1

因為它是朝上的,所以它的Y方向可能是0.7,它如果朝向小球的背面,那么Z方向在unity里面就是指向屏幕里面的方向,就是z軸的正方向,就是一個正數(shù),比如說0.2

當然這個數(shù)可能并不一定準確,大概的意思是這個樣子

那么我們能不能把這些數(shù)畫在屏幕上面呢?

是可以的,所有法線的方向數(shù)值,它的每一個分量,它的數(shù)值通通都是介于-1~+1之間的,所以我們要做的,就是個-1~+1的值換算成顏色值

如何可視化模型法線?

但是在計算機里面,顏色值的范圍是0~1之間的,要把法線的顏色值畫出來,這是TA要干的活兒,我們應該怎么做?

  • 問題很簡單,就是如何把在-1~+1間的值變成介于零到一之間的值,我們只要去運用一個小小的計算公式就可以,我們只需要寫幾行代碼就可以了

  • 首先,物體表面有很多的頂點,但我們要畫的不是每一個頂點上面的顏色,而是頂點中間的每一個小像素點的顏色,怎么做呢?

  • TA同學在工作的時候,要處理的程序有兩個方面:一個是頂點處理程序,另一個是把頂點換算成頂點之間的像素

  • 第一步:頂點上面的法線,在英文里面叫normal,法線傳到每一個像素點上面,就像我剛才畫的一樣,頂點和頂點之間構(gòu)成像素點

  • 第二步:在像素點上面進行運算,normal的值是-1~+1之間的數(shù)值,只要把數(shù)值加一,變成0~2

  • 第三步:再乘以0.5,0~2之間的值乘以0.5,就變成了0~1


  • 通過加1乘以0.5,把法線值變成了color,變成了顏色值

  • 上面是基于每個頂點的法線數(shù)據(jù),傳到像素著色器里面,然后對法線進行加1乘以0.5的操作就得到了最終的顏色值

法線插值

一般來說,unity傳到程序當中的法線數(shù)據(jù)本身就是一個單位化的數(shù)據(jù),英文叫做normalized就是單位化的數(shù)據(jù),那么我為什么還要在進入每一個像素進行處理的時候,重新對它進行一遍normalize,也就是重新單位化一次呢?

  • 因為在頂點處理階段,這個頂點的長度也是一,但是我要計算的是每一個像素點的顏色值,這個時候要用法線加一乘以0.5把它轉(zhuǎn)成像素顏色

  • 計算機內(nèi)部有一個操作叫做光柵化,光柵化操作是干什么呢?

  • 就是這邊有個頂點上面的法線,它就把法線構(gòu)成了一條線,但是問題是如果左邊這個法線長度是一個單位,長度是一,右邊這個法線,它的長度也是單位一,那么中間在光柵化的時候,通過插值運算出來的結(jié)果,就不是一個單位長度了,向量就不能代表法線方向

  • 因為數(shù)值不一樣,算出來的顏色的結(jié)果值是不一樣,所以在這里需要進行一個操作,叫做單位化

我舉一個現(xiàn)實當中的例子,比如說技術(shù)美術(shù)同學在工作的時候,如果不能夠正確的理解單位化或者忘記單位化,那么這個時候,它渲染出來的圖形學效果感覺好像差不多,但是總感覺差了點意思,原因是什么呢?

  • 其實在工作當中,我們往往就是因為忽略了某一些細節(jié),比如說要在光柵化以后進行重新的法線單位化

再告訴大家一個技巧,實際上在很多專業(yè)的技術(shù)美術(shù)同學工作的時候,對于這些法線向量,是不執(zhí)行單位化這個步驟的

有同學會說,剛才的又要單位化,現(xiàn)在又說不要單位化,到底說的哪一句話是對的呢?


  • 從圖形學的嚴謹性的角度來說,在這里是需要進行normalize單位化這個步驟的,但是任何的數(shù)學運算都是有開銷的,比如說我要進行單位化,單位化的操作在內(nèi)部是干什么呢?

  • 一個法線,它有X坐標,有Y坐標,有Z坐標,它要把這個XYZ坐標進行平方,然后加起來,再進行開根號

  • 開根號以后就能計算出來法線的lens,我們記為L

  • 再用X坐標,除以lens,作為單位化以后的X坐標,用Y坐標除以L作為單位化的Y坐標,再用Z坐標除以L作為單位化以后的Z坐標


  • 是不是覺得這個操作需要很多的步驟,先平方再加法,然后開根號最后再除法,一聽就覺得很復雜,所以計算機內(nèi)部算起來也需要很多的運算指令來完成,就會產(chǎn)生開銷

  • 是否單位化,從視覺角度來說,很多時候差別并不明顯,所以很多的專業(yè)TA,技術(shù)美術(shù)同學,在開發(fā)出新學效果的時候,可以不用考慮單位化的科學性,而是從實際效果,從性能的角度來說,可以把normalize這個步驟去掉

如果一個效果做出來,在肉眼上有太明顯的差別,那這時候就可以對一些運算步驟做一些省略和優(yōu)化,在這兒我們就又學到一個新的概念叫法線插值

剛才講的單位化,包括還有其他的圖形學算法,這些公式技巧其實并不難,我都會在圖形學的課程里面帶大家去手寫一遍這些圖形學算法,而不是告訴你有這個公式,我會用程序的方式帶大家把這些normalize內(nèi)部怎么實現(xiàn)的手寫一遍,讓你真正明白圖形學內(nèi)部是如何工作的,感興趣的小伙伴可以進群交流

回到課程開始的問題:

  • 為了表現(xiàn)模型表面細節(jié),我們需要創(chuàng)建高精度的模型,這個模型可能使用了幾萬個頂點甚至更多,而頂點越多,渲染的開銷越大

  • 那么如何使模型表面保留豐富的法線信息來計算光照、產(chǎn)生豐富細節(jié),同時避免使用過多的頂點呢?

  • 這就需要用到法線貼圖和切線空間的知識了,需要了解的小伙伴可以私信我獲取進階視頻內(nèi)容


【深入淺出】法線貼圖與切線空間(上)的評論 (共 條)

分享到微博請遵守國家法律
南康市| 泽库县| 德安县| 三明市| 澄江县| 民丰县| 临武县| 河津市| 嘉义市| 黄山市| 乌兰县| 德清县| 巴南区| 游戏| 太和县| 灵台县| 松桃| 兴仁县| 鹤岗市| 南汇区| 佛教| 皋兰县| 淄博市| 静海县| 鲁甸县| 菏泽市| 湛江市| 桑植县| 嘉禾县| 营口市| 蒙阴县| 夏津县| 轮台县| 奎屯市| 定陶县| 绍兴市| 邹城市| 肥城市| 德钦县| 那曲县| 安新县|