天天看點

渲染篇:法線貼圖

今天接着講渲染基礎:就是下面的法線貼圖了。

渲染篇:法線貼圖

什麼是法線貼圖?

法線貼圖這個東西,隻要搞渲染算法的肯定會遇到。簡單來講,法線就是指模型表面的凹凸感,而凹凸感的産生是因為模型表面像素的光照條件不一樣産生的。比如下面這個圖,邊緣光照壓暗了,是以給人有一種凹凸3D感覺。

渲染篇:法線貼圖

但凹凸感跟法線貼圖有什麼關系?

在逐像素計算光照時,每一個像素都會根據該點的法向量來計算最終該點的光照結果,那麼,我們如果能夠改變這個法線的方向,就可以改變這個點的光照結果,進而影響模型表面凹凸感。比如,高模在計算光照時,每個面的法線方向不同,是以各個面的光照計算結果都不同,就有凹凸的感覺了,而有的低模隻有一個面,整個面的光照條件都是一緻的,就沒有凹凸的感覺了。如果我們把高模的法線資訊儲存下來,類似紋理貼圖那樣,存在一張圖裡,再給低模使用,低模就可以有跟高模一樣的法線,進而在計算光照時達到和高模類似的效果,這也就是常說的烘法線的原理。

知道了概念,再來看看實作。

最早的法線貼圖實作方式是使用凹凸貼圖(Bump Map),簡單來講就是給一張灰階圖,預設為黑色,越凸起的地方顔色越亮,通過采樣點之間斜率決定像素是否位于邊緣,進而影響光照明暗,不過這種方式已經過時了,具體細節不再贅述。

Unity法線貼圖一般都是存儲在切線空間。這跟世界空間、模型空間類似,隻不過這個空間稍有點不直覺。大家隻要知道這是為了解耦就行,比如最直覺是将不同頂點的法線值存儲在世界空間,了解和計算都友善,但是這樣會有弊端,就是當模型發生旋轉等變化時,同一頂點的法線值就會發生變化,也就是需要多份法線貼圖,這顯然是極其浪費的。如何保證同一模型共用一份法線貼圖呢?答案就是将法線值存儲在切線空間。切線空間的z軸就是頂點所在面的法線方向,該點的uv二維坐标系則用來表達該點的切線(tangent)和該點的次法線(binormal)方向,具體計算如下:

T = normalize(dx/du, dy/du, dz/du)

N = T × normalize(dx/dv, dy/dv, dz/dv)

B = N × T

OK,知道法線貼圖存儲的是切線空間法線值,那麼就可以開始了。首先在頂點着色器中,存儲模型的切線空間到世界空間的轉換矩陣。

渲染篇:法線貼圖

片元着色器采樣法線貼圖,映射計算,空間轉換。

渲染篇:法線貼圖

這中間有一步映射計算,大緻就是因為法線貼圖存儲的值是有限範圍(比如8bits是0~255),歸一化就是0到1;而法線值是-1到1,是以需要乘以2減去1,隻不過這裡Unity給我們封裝好了。

看下效果:

渲染篇:法線貼圖

我們增大下法線強度。從法線貼圖中擷取到的是這個采樣點對應的法線方向,光滑的部分法線方向都為垂直于表面豎直向上的方向,也就是(0,0,1)的方向,而有凹凸的地方,法線就會有偏移值,換句話說,我們讓法線貼圖采樣出來的方向越偏離(0,0,1)方向,就會越加強法線的效果。

渲染篇:法線貼圖

結果:

渲染篇:法線貼圖

我們應用到前面文章講過的BlinnPhong模型,增加法線貼圖效果,看下對比:

從左到右分别是:直接貼圖采樣、BlinnPhong模型、增加法線貼圖的BlinnPhong模型。

渲染篇:法線貼圖

本節内容就介紹到這裡,有問題歡迎留言或私聊~~~

歡迎關注我的微信公衆号【unity大話東遊】,更多的unity技術類和渲染類文章等着你哦!