法線貼圖

在三維電腦圖形學中，法線貼圖（Normal mapping）是一種模擬凹凸處光照效果的技術，是凸凹貼圖的一種實現。法線貼圖可以在不添加多邊形的前提下，為模型添加細節。常見的使用場景是為低多邊形模型改善外觀、添加細節，此時的法線貼圖一般根據高多邊形模型或高度貼圖生成。

法線貼圖通常以普通RGB圖像的形式存儲，其中的R、G、B分量分別對應法線的X、Y、Z坐標。

法線貼圖有時也稱為「Dot3（仿立體）凸凹紋理貼圖」。凸凹與紋理貼圖通常是在現有的模型法線添加擾動不同，法線貼圖要完全更新法線。與凸凹貼圖類似的是，它也是用來在不增加多邊形的情況下在濃淡效果中添加細節。但是凸凹貼圖通常根據一個單獨的灰度圖像通道進行計算，而法線貼圖的數據源圖像通常是從更加細緻版本的物體得到的多通道圖像，即紅、綠、藍通道都是作為一個單獨的顏色對待。

法線貼圖通常有兩個變體，即物體空間與tangent-space法線貼圖，它們的不同之處在於法線測量與儲存所用坐標系統。

這項技術的一個有趣的應用是使用高解析度模型的法線貼圖表大幅度地提高low poly低面模型的顯示效果。儘管這種利用該解析度模型細節創建位移貼圖取代非均勻有理B樣條的方法早在1996年由Krishnamurthy與Levoy在Proc. SIGGRAPH 1996的文章中已經提出，但是直到後來才開始用到更加普通的三角形網格。1998年另外兩篇論文提出了從高解析度向低解析度多邊形網格轉換細節作為法線貼圖的方法：Cohen et al.在SIGGRAPH 1998的論文提出了一個特殊的約束簡化演算法，在化簡過程中跟蹤如何將丟失的細節映射到簡化的網格；Cignoni et al.在IEEE Visualization '98上的論文提出了分離高低精度多邊形網格的簡單方法，以及不受低精度模型構建方法影響的丟失細節恢復方法。後一種方法及其變體目前仍然是目前大多數可用工具使用的方法之一。

## 工作原理

計算表面光照的朗伯值（漫反射值）時，只需計算以下兩個單位向量的點積：

- 從濃淡點到光源的單位向量
- 該表面的法線單位向量

得到的結果就是光線在表面上的強度。假設有一個球體，我們只能通過多邊形模型近似表示其曲面形狀。通過在模型上應用三通道的位圖紋理，就可以對更加細緻的法線向量資訊進行編碼。位圖中的每一個通道（通常是紅色、綠色、藍色通道）都對應於一個空間尺度（X、Y、Z），這些空間尺度與物體空間法線圖的固定的坐標系統相關，或者與切空間法線圖場合中根據位置相對於紋理坐標平滑變化的坐標系統相關。這使得模型表面更加細緻，尤其是與先進的光照技術一起使用的時候更是如此。

單位法線向量可以根據對應的 UV 紋理坐標映射到法線貼圖上。因為幾何體上背向觀察者的向量不會被觀察到，所以法線貼圖上只有面向觀察者的向量（如果是左手坐標系，則 z 為 0 到 -1）。映射如下：

```
  X: -1 ~ +1 :  R:   0 ~ 255
  Y: -1 ~ +1 :  G:   0 ~ 255
  Z:  0 ~ -1 :  B: 128 ~ 255
```

- 直接指向觀察者的法線 (0,0,-1) 映射為 (128,128,255)。所以（法線所創造的凹凸）物體上直接面朝觀察者的部分為淺藍色，也是法線貼圖上最常見的顏色。
- 指向紋理右上角的法線 (1,1, 0) 映射為 (255,255,128)。所以物體的右上角一般是淺黃色，也是顏色貼圖上最亮的部分。
- 指向紋理右側的法線 (1,0,0) 映射為 (255,128,128)。所以物體的右邊一般是淺紅色。
- 指向紋理頂部的法線 (0,1,0) 映射為 (128,255,128)。所以物體的頂邊一般是淺綠色。
- 指向紋理左側的法線 (-1,0,0) 映射為 (0,128,128)。所以物體的左邊一般是深藍綠色。
- 指向紋理底部的法線 (0,-1,0) 映射為 (128,0,128)。所以物體的底邊一般是深楊紅色。
- 指向紋理左下角的法線 (-1,-1,0) 映射為 (0,0,128)。所以物體的左下角一般是深藍色，也是顏色貼圖上最暗的部分。

## 具體實現

把高度圖（Height map）轉換成一張法線圖（Normal Map）後，其圖的RGB分別是原高度圖該點的法線指向：Nx、Ny、Nz，這張圖可由Direct3D的專門函數幫助計算。最後在渲染的時候直接將該高度圖的每個像素與光源的向量點乘，即可得到表示每一點的明暗係數的圖：根據高度圖，越突出的地方，法線與光源夾角越小，該點的數值越大。接著將這張圖乘到渲染線中即可，這樣就使模型在背光的凹處有陰影而在面向光源處更亮的效果，這樣的3D模型看起來就像真的凹凸不平一樣。這些都可以直接在渲染流水線中由機器完成。

具體可以使用以下幾步簡單的語句來實現：

```cpp
DWORD Vector2ARGB(D3DXVECTOR3 *v,float height)
{
DWORD r=(DWORD)(127.0f*v->x+128.0f);
DWORD g=(DWORD)(127.0f*v->y+128.0f);
DWORD b=(DWORD)(127.0f*v->z+128.0f);
DWORD a=(DWORD)(255.0f*height);
return((a<<24L)+(r<<16L)+(g<<8L)+b);
}
```

```cpp
D3DXComputeNormalMap(pNormalMap,pHeightMap,NULL,0,D3D_CHANNEL_RED,1.0f);//pHeightMap为原高度图的指针，pNormalMap为一张空纹理，用于存放法线图
```

```cpp
DWORD F=Vector2ARGB(&light,0.0f);//light是单位化的光源向量
pD->SetRenderState(D3DRS_TEXTUREFACTOR,F);//pD是D3D的设备指针，这句将光源法线参数输入
pD->SetTexture(1,pTEXTURE);//设置原纹理，如上面的球，如有需要可以贴上纹理样式
pD->SetTexture(0,pNormalMap);//使用上面生成好的法线图
pD->SetTextureStageState(0,D3DTSS_COLORARG1,D3DTA_TEXTURE);//设置“来源1”为法线图
pD->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_DOTPRODUCT3);//将“来源1”（法线图）与“来源2”（光源法线）进行点乘
pD->SetTextureStageState(0,D3DTSS_COLORARG2,D3DTA_TFACTOR);//设置“来源2”为光线的光源法线参数
pD->SetTextureStageState(1,D3DTSS_COLORARG1,D3DTA_TEXTURE);//这步和下面几步将图片的原纹理加上
pD->SetTextureStageState(1,D3DTSS_COLOROP,D3DTOP_MODULATE);
pD->SetTextureStageState(1,D3DTSS_COLORARG2,D3DTA_CURRENT);
```

## 在電腦娛樂中的應用

交互式法線貼圖最初只能在北卡萊羅納大學Chapel Hill建造的並行圖形機器上進行渲染，後來逐漸可以在高端的SGI工作站上用多次渲染以或者幀緩衝操作進行法線映射，以及在低端個人電腦硬體上用調色板紋理這樣的技巧實現。但是，隨著家用電腦以及遊戲終端的處理計算能力的不斷增強以及功能越來越複雜，法線貼圖逐漸通過一些鮮活的電腦遊戲步入大眾的視野，這些遊戲包括：Far Cry（Crytek）, Deus Ex: Invisible War（Eidos Interactive）, Thief: Deadly Shadows（Eidos Interactive）, The Chronicles of Riddick: Escape from Butcher Bay（Vivendi Universal）, Halo 2（Microsoft）, Doom 3（id Software）, Half-Life 2（Valve Software）, Call of Duty 2（Activision），以及Tom Clancy's Splinter Cell: Chaos Theory（Ubisoft）。虛幻引擎（Epic Games）中也大量地使用了這項技術。法線貼圖在影片遊戲設計中的流行源自於同時具有的出色圖形質量以及與生成類似效果的其它方法相比所需的較少資源。較少的處理資源要求就可以轉變成性能的提升，並且使得按照距離索引細節縮放這種降低紋理法線圖細節的技術成為可能，基本上這就意味著距離越遠所需的光照模擬複雜性越低，這樣就可以減少處理工作，而且能夠保持與近距紋理同樣的細節層次。

目前，法線貼圖已經在個人電腦以及遊戲終端上得到成功而廣泛的應用。最初，微軟的Xbox是唯一完全支持這種效果的家庭遊戲終端，其它一些終端由於硬體上不能直接支持這種功能所以只能通過軟體實現。如Xbox360這樣的下一代終端的開發人員嚴重依賴於法線貼圖的技術，並且已經開始著手實現視差映射技術。

## 延伸閱讀

- （PDF） Realistic, Hardware-accelerated Shading and Lighting, Heidrich and Seidel, SIGGRAPH 1999

## 外部連結

- Blender法線貼圖
- GIMP法線圖插件
- Photoshop法線圖插件
- 藝術家使用法線貼圖指南 , Ben Cloward
- Free xNormal法線貼圖工具 , Santiago Orgaz
- Maya法線貼圖插件, Olivier Renouard
- 調色板紋理法線貼圖使用舊的OpenGL擴展
- 沒有硬體輔助的法線貼圖 , Lux aeterna luceat eis Amiga demo from Ephidrena
- ZMapper, Pixologic
- 法線貼圖照片通過數字照片分層手工創建法線圖