3D遊戲常用技巧Normal Mapping (法線貼圖)原理解析——基礎篇

水煮魚丸發表於2016-08-26

1、法線貼圖基本概念

在製作3D遊戲時,常常遇到這樣一個問題:一個平面,這個平面在現實中並不是一 個“平”面,例如磚牆的表面帶有石質浮雕等等。這種情況下如果只是簡單的做一個平面,則讓人感覺嚴重失真,如圖1所示;而如果用很密集的三角形去表示這類略有凹凸的表面,則效能上大大下降。研究人員發現,人眼對物體的凹凸感覺,很大程度上取決於表面的光照明暗變化,如果能通過一張貼圖在一個平面上表現出由凹凸造成的明暗變化,則可以讓人眼感覺這個平面是凹凸不平的(雖然這個平面還是平的)。法線貼圖正是為了這個目的而產生的。

圖1 不同細節程度的蠟燭

準確的說,法線貼圖是Bump Mapping(凹凸貼圖)的其中一種。第一個Bump Mapping由Blinn在1978年提出,目的是以低代價給予計算機幾何體以更豐富的表面資訊。30年來,這項技術不斷延展,尤其是計算機圖形學成熟以後,相繼出現了不少演算法變體,法線貼圖就是其中很重要的一種。研究人員對法線貼圖進一步改進,出現了Parallax Mapping(視差貼圖), Relief Mapping等技術,實現了更逼真的效果。本文僅針對法線貼圖進行介紹。

一條法線是一個三維向量,一個三維向量由x, y, z等3個分量組成,在法線貼圖中,把(x, y, z)當作RGB3個顏色的值儲存(如圖2),並將其每個分量對映到[-1, 1]。例如,對於x, y, z各有8位的紋理,[0, 128, 255]表示法向量(-1, 0, 1)。

圖2 利用彩色通道儲存法線貼圖

2、切線空間

法線貼圖中儲存的法線最初是定義在世界空間中,但在實際中,這種方式很少見,因為只要物體移動,法線貼圖則不再有效。另一種方式就是將法線儲存在物體的區域性空間中,物體可以進行剛體變換(平移,旋轉,縮放),法線貼圖依舊有效,但是這種方法並不能應對任何方式的變換,並且法線貼圖不能在不同物體進行復用,增加了美工的負擔。所以,現在現在普遍採用的解決方案是將法線儲存在切線空間中。

簡單的來說,切線空間可以理解為紋理空間的u,v方向和法向量n,這3個方向構成了切線空間,一般使用T、B和N表示,如圖3所示。具體解釋見http://blog.csdn.net/bonchoix/article/details/8619624,這個部落格解釋的很好,沒見過的童鞋可以看一看,第一次理解可能會有點困難。

圖3 切線空間

3、法線貼圖的使用

法線貼圖的製作過程如圖4所示,通過對比高模和低模的差異,生成法線貼圖,在執行時使用法線貼圖+低模即可表現出接近高模的效果,但是大大降低了顯示卡的負擔。計演算法線貼圖的演算法在3ds Max中已實現,美術人員只需針對同一個模型製作一個高模和一個低模,烘焙出一張法線貼圖,在遊戲中使用低模+法線貼圖即可。

圖4 法線貼圖製作過程

在渲染模型表面的時候,需保證光照方向和法線是處在同一座標空間。光照方向在世界空間中,而法線在切線空間,將他們變換到同一座標空間無非兩種方法:

1、將光照方向變換到切線空間;

2、將法線變換到世界空間。

在大部分情況下,使用第一種方案會比較好,因為只需針對每個頂點進行變換,然後在三角形中對變換後的光照方向進行插值;而使用第二種方案,則需要對每個畫素進行變換。顯然,在光源較少的情況下,使用第一種方案可以減少計算量。當然,在光源數量較多的情況下,到底使用那種方案,需要值得考慮,因為使用第二種方案只需要變換一次法線,而第一種方案需要有多個光照方向需要變換。

值得注意的是,第一種方案中的插值對於點光源來說存在一個近似,光照方向在一個三角形上變化的很慢,所以可以進行插值,不過對於方向光則沒有這個問題。

4、法線貼圖效果

法線貼圖+低模可以表現出接近高模的效果,在圖4中可以看到,加上法線貼圖的低模,效果很接近高模;圖5為unity3d中法線貼圖的示例,左圖(沒有法線貼圖)和右圖(有加入法線貼圖)相比,明顯右圖的立體感更強。

圖5 unity3d中法線貼圖的示例。左圖中的方塊沒有法線貼圖,右圖加入了法線貼圖

5、法線貼圖的壓縮和mipmap

歸一化的法線長度為1,且在切線空間下,法線的z分量不可能為負數,所以只需要儲存x和y值即可。當然,僅僅是這種簡單的壓縮是不夠的,但是傳統的紋理壓縮方法如DXTC等,不能直接對法線貼圖使用,需要進行一定的變化,具體方法將在下一篇部落格《3D遊戲常用技巧Normal Mapping (法線貼圖)原理解析——高階篇》進行詳細描述。

使用傳統mipmap方法生成的法線貼圖對於漫反射表面基本沒問題,但是在鏡面表面會導致嚴重的視覺問題。對於漫反射表面來說,光照的計算公式為l·nl為光線方向的相反方向,n為法線,l·nl·nl·nl·n4 = l·(nnnn4) / 4,而mipmap則是事先計算(nnnn4) / 4,所以對於漫反射表面,對法線貼圖使用傳統方式的mipmap基本沒問題。為什麼是基本沒問題而不是完全沒問題呢?因為這裡存在一個近似,若l·< 0,則光照值為0(光照不能為負),若將這個因素考慮進去,漫反射表面也會有問題,不過在實際當中這種情況表現不明顯,所以可以認為基本沒問題。

對於鏡面表面來說,當視線偏離反射光線方向的時候,光照強度會急劇下降,反映在公式中是因為其含有cosm(h·n)項(具體公式可以Google),而漫反射光照是線性變化,所以對於鏡面表面,不能使用傳統方法生成法線貼圖的mipmap,需要用特殊的技術手段進行處理,具體方法見下一篇部落格“3D遊戲常用技巧Normal Mapping (法線貼圖)原理解析——高階篇”。

參考資料

[1]http://blog.sina.com.cn/s/blog_5497d613010006qu.html

[2]http://www.zwqxin.com/archives/shaderglsl/review-normal-map-bump-map.html

[3]http://blog.csdn.net/bonchoix/article/details/8619624

[4]Akenine-Möller T, Haines E, Hoffman N. Real-time rendering 3 [M].

相關文章