2007-12-11
2007-04-25
Normal map[結語]
這次仔細研究normal map的製作,算是把整個normal map完全了解了。把整理的心得放在這邊除了是做紀錄外,也是想說透過這個方式把心得分享出來,可以對其他人有幫助。希望這不是野人獻曝 :)
2007-04-21
Normal map[參考資料]
技術文件
相關工具
- Zbrush官方網站
有免費試用版本可下載,可是功能有限,可以拿來先熟悉了解一下雕塑功能。 - Mudbox
有完整功能15天試用版本供下載。 - Nvidia Photoshop plugin ( Normal map filter & DDS importer/expoter)
- ATI the Compressornator (DDS& 3Dc generator)
normal map製作
Normal map[壓縮]
現在的3D遊戲幾乎都使用DDS的壓縮材質,主要原因是壓縮效率品質都不錯。可是normal map直接壓縮為DXT1~5這些格式, 效果都很不好。於是研究了一下目前一般常用的技術。
大致上目前使用的技術都是只儲存X/Y值,而Z值都在pixel shader裡面計算..
Z = sqrt( 1 – x*x – y*y)
這樣的方式有些限制:
- 必須是tangent space normal map。因為在world/object space下,Z有可能是正值或是負值,這個做法只能取正值(或是只取負值)。
- normal必須是normalize 的。一般我們會希望normal 都是normalize,所以不算很大的限制。
- pixel shader版本必須是1.4以上。
這個方式下有幾個常用的normal map格式:
- 使用V8U8/CxV8U8格式:效果和R8G8B8的normal map一樣好。但壓縮率還不夠好,只能壓縮到2/3。
- 使用Swizzled DXT5格式:基本上還是DXT5格式,但是把X值放到A,把Y值放到G,R/B channel可忽略,理由是DXT5壓縮特性使得A/G channel壓縮品質比較高。品質會比直接把DXT5存XYZ的方式好很多。
- 使用3Dc:這目前只有AMD(ATI)的GPU支援。效果應該比Swizzled DXT5好。(由於手邊沒有ATI的卡,所以無從比較)
下圖是測試比較圖,可以看出Swizzled DXT5效果還不錯說
簡單說明一下如何使用NVIDIA Photoshop plugin製作這些壓縮格式的方式:
- V8U8/CxV8U8格式:選擇V8U8/CxV8U8格式輸出。
- Swizzled DXT5:選擇DXT5_NM格式輸出。
- 3Dc:無法輸出。目前只有ATI支援,所以只能透過AMD(ATI)的工具The Compressornator輸出。
Normal map[製作]
一般製作normal map的方式大概有以下幾種:
- 製作 bump map轉normal map
- 製作高面數物件以及低面數物件來產生 normal map。
- 拍照法
製作bump map轉normal map
製作bump灰階高低圖透過轉換工具產生normal map。這個方法只適合產生tangent space的normal map。
- 製作bump圖。圖必須是RGB channel, 長寬必須是2的冪次方。
- 使用normal map轉換工具產生Y-up的normal map
NVIDIA Photoshop Normal map filter plug-in
紅色框的Invert-Y一要勾選, Wrap建議勾選
以下是試做bump map轉normal map的試做結果
製作高面數物件以及低面數物件來產生 normal map:
這個做法就是製作高面數的物件, 把高面數的normal 儲存成normal map。目前美術人員常使用的 3ds max, Maya, XSI等軟體都有內建高面轉低面數的工具,所以都可以使用這些工具製作高面數模型來轉換輸出。不過現在 Zbrush/Mudbox 這類 3D建模軟體的出現,使得 normal map 的製作更有效率。以下說明的是使用Zbrush/Mudbox軟體轉normal map的製作方式.。製作的流程如下:
- 先用3DS max、Maya、XSI等等製作遊戲使用的低面模型,並把UV拆好。ZBrush會使用同樣的UV資料來產生normal map。
- 輸出OBJ格式。
- 在ZBrush 使用Tool->import 載入OBJ檔案。
- 使用ZBrush 製作物件細節。
- 使用ZMapper工具產生normal map:
產生Y-up的normal map設定方式如下圖所示:注意圖中紅色框框:
- Tangent space N.Map 必須勾選,才能產生tangent space的normal map。
- Flip Image Vertically 必須勾選。
- Interpolate/RayTrace : 計算normal map的方式, Interpolate 比較快,Ray Trace會比較慢。理論上ray trace品質應該會比較好才是。
- 其他參數使用預設值。
- 在Texture介面export normal map輸出檔案。
以下是使用ZBrush製作normal map試做的結果:
製作方式與Zbrush差不多,也是製作低面模型輸出OBJ檔案到mudbox製作細節。不過目前測試的結果發現mudbox產生normal map的 Texture Baking工具 效果不是很理想,所以看到網路上一些美術好手的做法是將高面數的物件匯出OBJ檔案,再使用3DS MAX/Maya/XSI透過高低面產生normal map的工具來產生normal map。3DS MAX/Maya/XSI 產生Y-up 的normal map設定可參考http://sd-art.wikispaces.com/normalMapping
Normal map[規格制定]
- 可以共用normal map貼圖(不同物件間的共用或是mirror物件共用)。
- 目前一些normal map壓縮技術也只能使用tangent space的normal map (這部分在normal map壓縮會詳細說明) 。
缺點:
- 需要 vertex normal/tangent的資料, 在計算lighting時候, 需要多處理一些座標轉換.處理。
World space/object space的優缺點和tangent space正好相反,所以某些狀況下或許使用world/object space的normal map 會比較好。
不過我目前只打算使用 tangent space的normal map. 對object space下的normal map有興趣的可看http://www.3dkingdoms.com/tutorial.htm

下圖是兩個系統下normal map的比較.
可以發現左手系統XYZ(0, 1, 0) 或是RGB(128, 255, 128)是指向下方,右手系統是指向上方。在網路上搜尋了一下,似乎沒有人以左手右手系統來區分這樣的差別,只有提到Y向上或是Y向下。所以以下內容就是以Y向上系統(Y-up)或是Y向下系統稱呼(Y-down)。
Normal map[前言]
normal map是目前3D遊戲最常使用的技術之一。之前參與過的專案有嘗試使用normal map,但是由於程式人員對normal map技術沒有完全了解,以及美術人員無法負擔因為製作normal map所帶來的的製作量,最後也就放棄了這個技術。
2007-03-30
Shadow map 初版
這次實作的shadow map的方式應該算是比較正規的做法. 只要支援shader model2.0以上的卡應該都支援. 概念還是一樣. 首先還是要先產生depth shadow map, shader model 2.0支援16-bit/32 bit的render target了. 這部分實作的細節可以參考DX 9.0c SDK的shadow map範例.
產生shadow map這部分挺好處理的. 最麻煩的是 shadow 計算. 這部分有幾個問題了
- shadow 是要整合到lighting計算, 或是用overlay的方式處理(有點像後製)
* 整合到lighting : 每個shader 都要寫個shadow 處理..很浪費時間.
* overlay : lighting效果會不正確. - 如何有效控制shadow bias 值, 特別是要處理self-shadowing時候.
- 如何快速產生soft shadow
這次修改的render queue打算支援多個光源多個shadow map, 以下是兩個平行光測試結果.

目前只是測試shadow map在render queue內的運作. 一些PVS 的機制尚未加入. 比如說view內需要處理哪些光, 需要把哪些物件放到產生shadow map的sub-queue內等等...這個版本的shadow map 是採用1024x1024 RG16F格式, 在產生shadow時候, 是整合到lighting計算, 使用3x3 PCF(從FxComposer的範例抄來的). lighting計算是 per-pixel light. 使用multi-pass處理2個光.
看起來想要支援多個shadow map效能上要再加強.....
2007-03-28
Try to Inline shader text into C/C++ code
方式很簡單, 就是在resource editor使用import shader .fx檔案的方式產生新的 resource, resource type定為RCDATA即可.這樣在使用D3DXCreateEffectFromResource時候, 就可以載入成功.
不過一開始測試的時候卻載入失敗. 原因是我把Graphics相關的部分寫成一個graphices.lib. 而resource的定義也是放在graphics.lib的project內. 但是在編譯主程式的時候, 雖然有link到graphics.lib..但是定義的resource卻不會自動link. 所以執行的時候就找不到相關的resource. 後來在高人指點之後, 才知道原來要手動link...於是把該編譯好的.res檔案加到主程式的專案內..這樣就可以執行了.
目前這個是暫時的解決方案, 因為我覺得這樣設定很突兀, 本來只需要透過設定project間的dependency就可以自動link lib的, 卻因為resource檔案必須手動加到主程式的專案. 之後如果把lib給他人使用, 編譯後的resource檔案也是要一起提供. 這樣不是很方便, 所以之後會想辦法改成DLL版本. 這個問題就可解決了.