3D遊戲常用技巧Normal Mapping (法線貼圖)原理解析——高階篇
1、概述
上一篇部落格,3D遊戲常用技巧Normal Mapping (法線貼圖)原理解析——基礎篇,講了法線貼圖的基本概念和使用方法。而法線貼圖和一般的紋理貼圖一樣,都需要進行壓縮,也需要生成mipmap。但是由於法線貼圖儲存的是法線資訊,壓縮和生成mipmap的方法自然會有所變化。
現在已經許多用於法線貼圖壓縮和生成mipmap的工具,大部分商業遊戲引擎也整合了相關方法,只需要點幾下滑鼠就可以完成。本文僅針對法線貼圖的紋理壓縮和mipmap的方法進行原理性的說明,至於在具體的工具中如何操作,可以參看相關工具的說明文件。
法線貼圖壓縮的中文資料還是比較多的,也不太複雜;但是生成mipmap的方法中文資料不多,《Real-Time Rendering 3rd》講解的比較詳細,本文的這部分內容主要來源於這本書,如果想詳細瞭解的,可以看原書,網上有電子版。
2、法線貼圖的壓縮
傳統的jpg等壓縮方式解壓時間太長,且壓縮比不固定,所以在實時渲染中一般採用DXTC及其改進方法,簡單來說,就是把4*4的畫素當做一個Block,對其進行簡化表示,詳情參見百度百科http://baike.baidu.com/view/736449.htm。由於法線貼圖儲存的資料並不是RGB資訊而是法線方向,所以需要在一般紋理壓縮的方法的基礎上進行一定的改變。
壓縮的第一步很簡單,由於歸一化的法線長度為1,且在切線空間下,法線的z分量不可能為負數,所以只需要儲存x和y值即可。本文的壓縮方法在這一步壓縮的基礎上,利用現有的紋理壓縮方法,進行進一步壓縮。
在支援DirectX10的顯示卡上,可以使用BC5格式進行壓縮。BC5的壓縮方法記憶體情況如圖1所示,該格式有兩個顏色通道(R和G),每個通道使用兩個1Byte的值來表示,每個畫素使用3Bit在這兩個顏色值之間進行插值。將法線貼圖中每個法線的x和y值利用BC5格式進行壓縮,如圖2所示。對每個Block(16個畫素)儲存x的最大、小值和y的最大、小值,然後每個畫素利用3Bit進行插值,相當於在圖2右圖所示的8*8區域內取樣(為了簡化表示,圖2只畫了4*4點)。
圖1 BC5壓縮方法
圖2 法線貼圖壓縮示意圖,右圖框內應該是8*8個點,為了畫圖方便簡單表示為4*4
對於不支援DirectX10的顯示卡,可以使用DXT5格式進行壓縮(DXT5為DirectX9.0的紋理壓縮格式,如果連DirectX9.0都不支援,建議直接送博物館),將法線的x和y值儲存到紋理的alpha和Green通道即可。之所以是儲存到這兩個通道,而非其他通道,是因為每個DXT5中每個Block選擇的兩個參考畫素alpha通道有8Bit,RGB通道分別為5、6、5Bit,所以使用alpha和Green通道可以獲得較高精度。
3、法線貼圖的mipmap
使用一般紋理mipmap方法生成的法線貼圖對於漫反射表面基本沒問題,但是在鏡面表面會導致嚴重的視覺問題。對於漫反射表面來說,光照的計算公式為l·n,l為光線方向的相反方向,n為法線,l·n1 + l·n2 + l·n3 + l·n4 = l·(n1 + n2 + n3 + n4) / 4,而mipmap則是事先計算(n1 + n2 + n3 + n4) / 4,所以對於漫反射表面,對法線貼圖使用傳統方式的mipmap基本沒問題。為什麼是基本沒問題而不是完全沒問題呢?因為這裡存在一個近似,若l·n < 0,則光照值為0(光照不能為負),若將這個因素考慮進去,漫反射表面也會有問題,不過在實際當中這種情況表現不明顯,所以可以認為基本沒問題。
對於鏡面表面來說,當視線偏離反射光線方向的時候,光照強度會急劇下降,反映在公式中是因為其含有cosm(h·n)項(具體公式可以Google),而漫反射光照是線性變化,所以對於鏡面表面,不能使用傳統方法生成法線貼圖的mipmap。法線貼圖對於鏡面反射的mipmap如圖3所示,第一幅圖中有4個畫素,每個畫素有法線和鏡面反射波瓣(紅色的是法線,周圍一圈是鏡面反射波瓣,鏡面反射波瓣用於表示不同方向的反射強度)。圖2中間部分,表示正確的mipmap情況,分別從4個畫素合併為2個畫素,從兩個畫素合併為1個畫素。而現有的方法中,沒有方法可以做到這樣的mipmap,所以只能用其他方法進行近似。
圖3 法線貼圖的mipmap示意圖
圖2的底部左圖,是使用一般紋理的mipmap方法對法線進行平均,可以看到這種方法產生出的鏡面反射波瓣和正確的鏡面反射波瓣差距很大,其根本原因是使用線性方法對非線性的引數進行計算。圖2底部圖右圖,每次在平均法線的同時,改變表面的光澤度(即改變鏡面光公式中的m),雖然最終結果與正確的mipmap有一些差距,但是比一般紋理的mipmap的方法要好很多。
所以,對法線貼圖的mipmap方法之一,就是在使用一般紋理的mipmap方法對法線進行平均的同時,每張mipmap都必須附帶一張光澤貼圖(gloss map),記錄每個畫素點的光澤度(即m),m的計算原則就是讓最後的鏡面反射波瓣與正確的鏡面反射波瓣最接近。當然,還有其他很多方法能得到不錯的結果,具體可以參看《Real-Time Rendering 3rd》,或去搜尋相關論文。
參考資料
[1]Akenine-Möller T, Haines E, Hoffman N. Real-time rendering 3 [M].
相關文章
- 3D遊戲常用技巧Normal Mapping (法線貼圖)原理解析——基礎篇3D遊戲ORMAPP
- 翻譯:非常詳細易懂的法線貼圖(Normal Mapping)ORMAPP
- 常用JavaScript的高階技巧JavaScript
- JavaScript常用的簡潔高階技巧JavaScript
- jQuery高階技巧——效能優化篇jQuery優化
- 掌握次世代3D遊戲場景貼圖繪製技巧,半年拿下網易offer3D遊戲
- Android 3D遊戲開發(高階篇)——Opengl ES遊戲引擎實現Android3D遊戲開發遊戲引擎
- Java後端高階開發面試技巧解析Java後端面試
- 「進階篇」Vue Router 核心原理解析Vue
- Google高階搜尋技巧之高階語法查詢指令Go
- CSS高階技巧CSS
- JS高階技巧JS
- JavaScript 高階技巧JavaScript
- 15 個常用的 SQL Server 高階語法SQLServer
- 「 MySQL高階篇 」MySQL索引原理,設計原則MySql索引
- 從原理到實戰,徹底搞懂Nginx(高階篇)Nginx
- 高階圖形繪製軟體的原理猜想
- 手把手教你架構3D引擎高階篇系列一架構3D
- 雲原生技術學習路線圖 初階+中階+高階
- Python模組高階技巧Python
- Github高階搜尋技巧Github
- CSS 高階佈局技巧CSS
- 《前端之路》之 JavaScript 高階技巧、高階函式(一)前端JavaScript函式
- nginx高階篇rewriteNginx
- Typescript 高階語法進階TypeScript
- Origin圖表技巧之繪製帶輔助面的3D折線圖3D
- 《iOS核心動畫高階技巧》筆記(四) - 專用圖層iOS動畫筆記
- 【轉貼】55種網頁常用小技巧(JavaScript)網頁JavaScript
- 高解析度3D渲染3D
- MarkDown 的常用高階教程
- iOS 核心動畫高階技巧 - 1iOS動畫
- JS高階技巧(簡潔版)JS
- ZeroMQ 教程 002 : 高階技巧MQ
- Kotlin——高階篇(五):集合之常用操作符彙總Kotlin
- 『高階篇』docker之Mesos叢集架構圖(23)Docker架構
- 技術進階·K線篇(八)——下降三法
- 高階QML 3D元件開發3D元件
- MySQL 高階特性篇教程MySql