計算機圖形學-貼圖

一個三維場景的畫面的好壞,百分之四十取決于模型,百分之六十取決于貼圖,可見貼圖在畫面中所占的重要性。在這里我將列舉一系列貼圖,并且初步闡述其概念,理解原理的基礎上制作貼圖,也就順手多了。

1. 漫反射貼圖diffuse map?

漫反射貼圖在游戲中表現出物體表面的反射和表面顏色。換句話說,它可以表現出物體被光照射到而顯出的顏色和強度。我們通過顏色和明暗來繪制一幅漫反射貼圖,在這張貼圖中,吸收了比較多的光線的部分比較暗,而表面反射比較強的部分,吸收的光線比較少。

刨去那些雜糅的東西,我們只談明顯的,漫反射貼圖表現了什么? 列舉一下,物體的固有色以及紋理,貼圖上的光影。前面的固有色和紋理我們很容易理解,至于后面的光影,我們再繪制漫反射貼圖的時候需要區別對待,比如我們做一堵墻,每一塊磚都是用模型做出來的,那么我們就沒有必要繪制磚縫,因為這個可以通過打燈光來實現??墒俏覀內绻媚P椭蛔隽艘幻鎵?,上面的磚塊是用貼圖來實現,那么就得繪制出磚縫了。從美術的角度,磚縫出了事一條單獨的材質帶外,還有就是磚縫也是承接投影的,所以在漫反射圖上,繪制出投影也是很有必要的。

沒有什么物體能夠反射出跟照到它身上相同強度的光。因此,讓你的漫反射貼圖暗一些是一個不錯的想法。通常,光滑的面只有很少的光會散射,所以你的漫反射貼圖可以亮一些。

漫反射貼圖應用到材質中去是直接通過DiffuseMap的。再命名規范上它通常是再文件的末尾加上“_d”來標記它是漫反射貼圖。

2. 凹凸貼圖Bump maps

凸凹貼圖可以給貼圖增加立體感。它其實并不能改變模型的形狀,而是通過影響模型表面的影子來達到凸凹效果的。再游戲中有兩種不同類型的凸凹貼圖,法線貼圖(normalmap)和高度貼圖(highmap)。

Normal maps法線貼圖

法線貼圖定義了一個表面的傾斜度或者法線。換一種說法,他們改變了我們所看到的表面的傾斜度。

法線貼圖把空間坐標的參數(X,Y,Z)記錄在像素中(R,G,B)。

有兩種制作法線貼圖的方法:

????1.從三維的模型渲染出一張法線貼圖 (用高模跟低模重疊在一起,把高模上的細節烘焙到低模的UV上,這里需要低模有一個不能重疊的UV)

????2.轉換一張高度貼圖成為一個法線貼圖。(是用NVIDIA的PS插件來轉換一張圖成為法線貼圖)

種類

? ? 1.世界空間下的法線紋理

????2.模型空間下的法線紋理

????3.切線空間下的法線紋理

對比不同的法線貼圖

首先按照不同的坐標系得到了不同類型的法線貼圖。模型頂點的法線根據所處坐標系的不同,在成圖后表現也是不同的。以模型法線貼圖和切線法線貼圖為例:


左邊: 模型空間下的法線紋理 右邊: 切線空間下的法線紋理??

不同的顏色是因為法線作為一個Vector3類型的需要轉換到2D的顏色,而通常來說我們可以把顏色的RGB看成一個坐標系,這樣法線就對應了一個RGB顏色。但是法線的范圍是[-1,1],而顏色是沒有賦值的,因此有以下的轉換過程。

法線紋理存儲的是表面的法線方向。由于法線方向的分量范圍在[-1, 1],而像素的分量范圍為[0, 1],因此我們需要做一個映射,通常使用的映射就是:

pixel=(normal + 1) / 2

這就要求,我們在Shader中對法線紋理進行紋理采樣后,還需要對結果進行一次反映射的過程,以得到原先的法線方向。反映射的過程實際就是使用上面映射函數的逆函數:

normal=pixel × 2 - 1

????1.world space normal map

一旦從貼圖里解壓出來后,就可以直接用了,效率很高.但是有個缺點,這個world space normal 是固定了,如果物體沒有保持原來的方向和位置,那原來生成的normal map就作廢了。

世界坐標下的頂點的法線是現成的,因此好用。不過如果進入模型在U3D里面進行了位置或者方向的轉換,那么在沒有轉換矩陣的情況下,法線信息就是錯誤的,也就無法使用了。進一步思考如果場景中存在大量的靜態模型,可以考慮用這個。

????2.object space normal map

對于模型頂點自帶的法線,它們是定義在模型空間中的,因此一種直接的想法就是將修改后的模型空間中的表面法線存儲在一張紋理中,這種紋理被稱為模型空間的法線紋理(object-space normal map)。

對象空間的法線貼圖,這個貼圖中記錄的法線信息是基于模型空間的,因此數值是相對的,這樣模型在場景中是可以位移和旋轉的,只要在計算的時候乘上對應的矩陣即可。而且從上面的圖里可以看到貼圖是彩色的,因為模型上的頂點法線在這個空間中是朝各個方向的。

對象空間的法線貼圖比起世界空間的在使用了已經有了很大的進步,不過它仍舊有自己的局限性,就是這樣的貼圖還是依賴于模型本身。從其定義也可以看出來,它也是一種“絕對位置”。如果模型發生了形變,則這個貼圖的信息就是錯誤的。從目前來看,我只能想到模型在場景中存在動畫這個問題。

????3.tangent space normal map

對于模型的每一個頂點,它都有一個屬于自己的切線空間,這個切線空間的原點就是該頂點本身,而z軸是頂點的法線方向(n),x軸是頂點的切線方向(t),而y軸可由法線和切線叉積而得,也被稱為副切線(bitangent, b)或副法線。這種紋理被稱為是切線空間的法線紋理(tangent-space normal map)。

定義很好理解,從本質上講切線空間的法線貼圖解決了模型變形的問題。因為在另一個模型上的頂點的切線空間坐標系里面,法線貼圖中的信息是可以使用的,它不依賴于模型本身、也不依賴于模型所處的坐標系。

????4.切線空間下的法線貼圖如何生成

以3DMAX為例,法線貼圖需要高模和低模配合,具體過程不說了,網上大把的視頻。

重點是法線貼圖的生成需要高模和低模,因為沒有高模就不知道法線方向,沒有低模,就不知道高模上某點的法線對應于低模上哪個點。

下面才是重點,因為多個高模的面使用了同一個低模的面,因此在生成法線貼圖時,高模不能使用自己的tangent space,而是使用低模的tangent space。這樣一些高模上的點的法線與低模面上的法線出現了不一致,你可以想象低模上的某個面上的法線指向一個方向,但是對應了幾個高模的點,可能一些點的法線與低模面的法線方向一樣,那么很好,完美融入低模的切線空間,顏色呈現出淡藍色。但是其它那些和低模面法線不一致的點的法線就產生了夾角,就造成了在切線法線貼圖上那些不是[0.5,0.5,1]色值的點。

低模上的這個tangent space,也必須與高模上的坐標系tangent space。因為低模上的一個面,可能對應了高模上的幾個面(精度高),按照新方法每個面都有一個局部坐標系,那對于低模上的每個面,高模因為存在好幾個面,就會出現好幾個局部坐標系,這肯定是不行的。所以高模所用的tangent space,就是低模上的。生成法線貼圖,必定會確認高模上哪些面都對應低模上的哪個面,然后高模上的這幾個面的法線,都會轉換為低模這個面上所構建的tangent space的坐標。這樣,當低模變形時,即三角面變化時,它的tangent space也會跟著變化,保存在貼圖里的法線乘以低模這個面的tangent space到外部坐標系的轉換矩陣即可得到外部坐標。順便再提一點,高模保存的這個法線,是高模上object space里的法線。

對于上述的內容,這張圖做了很好的詮釋。

如何將高模的法線貼圖用在低模上

對于object space normal map,低模的object space坐標系與高模中的object space坐標系是重合的。所以不需要構建,所以低模上某點才能直接用高模的法線替換自己的法線。

Height maps高度貼圖

什么是HeightMap呢?所謂高度圖實際上就是一個2D數組。創建地形為什么需要高度圖呢?可以這樣考慮,地形實際上就是一系列高度不同的網格而已,這樣數組中每個元素的索引值剛好可以用來定位不同的網格(x,y),而所儲存的值就是網格的高度(z)。

我們在這里敘述高度圖,其實也是為了更好的繪制法線貼圖,很多情況下我們的法線貼圖只能在已有的漫反射貼圖作為素材進行繪制,這樣就是需要由一個HeightMap轉換成法線貼圖的一個過程,明白了這個原理,做起來也就可以更好的駕馭其效果。

高度貼圖是一種黑白的圖像,它通過像素來定義模型表面的高度。越亮的地方它的高度就越高,畫面越白的地方越高,越黑的地方越低,灰色的在中間,從而表現不同的地形。

高度貼圖通常是在圖形處理軟件中繪制的。他們通常沒有必要渲染這些,再DOOM3游戲中高度貼圖是被轉換成法線貼圖來使用的。使用高度貼圖僅僅是為了適應簡單的工作流程。高度貼圖通常通過“Heightmap”函數來調用到3D軟件中去的,我們通常再文件名后面加一個"_h"來標示它。

Normal maps vs. height maps

法線貼圖和高度貼圖

一般來說,Normal Map來自于Height Map。具體生成的方法如下:

把Height Map的每個像素和它上面的一個像素相減,得到一個高度差,作為該點法線的x值;

把Height Map的每個像素和它右邊的一個像素相減,得到一個高度差,作為該點法線的y值;

取1作為該點法線的z值。

另種推導過程如下:

x方向,每個像素和它下面的一個像素相減,得到向量<1, 0, hb - ha>,其中ha是該像素的高度值,hb是下一行的高度值;

y方向,每個像素和它左邊的一個像素相減,得到向量<0, 1, hc - ha>,其中ha是該像素的高度值,hc是左一列的高度值;

兩個向量Cross,得到

簡單來說,就是取兩個方向的切線向量,對它們做Cross得到該點的法線向量。

還有第三種做法,是根據每個象素四邊的點計算,而該點象素本身不參與計算。計算結果大同小異。

而且我覺得這種計算只適合于單塊的HeightMap、NormalMap,像是DOOM3中的NormalMap就無法由HeightMap計算出來了。所以最好還是在美工建模的時候同時生成NormalMap和HeightMap而不是利用HeightMap生成NormalMap。

DOOM3游戲引擎可以把法線貼圖和高度貼圖合成在一張凸凹貼圖上。

通常我們繪制一張具有足夠細節的高度貼圖要比建立一個足夠細節的模型然后渲染成相應的法線貼圖要實際的多。

法線和高度的凸凹貼圖可以通過Addnormals函數來合并到一種材質中。

毫無疑問,高度貼圖大多數游戲引擎中出現的不多。他們只是給電腦一種方法來計算曲面法線當使用動態燈光的時候。

這說明實際上,一張高度貼圖被轉換成一張法線貼圖,以此可以計算出相鄰兩塊不同高度的位置之間的傾斜面。高度貼圖永遠不能像法線貼圖這樣具有足夠的細節,這是被肯定的。

很明顯只有灰度的高度貼圖并不能很好的表現應該有的細節,因為它是黑白的,RGB顏色就會遭到浪費,并且因此你只能只用256層級的強度。

相比較來言法線貼圖的每一個圖像通道都可以利用到,顯而易見,法線貼圖能夠更好的來表現凸凹。

3. Specular maps高光貼圖?

什么是高光貼圖?

高光貼圖是用來表現當光線照射到模型表面時,其表面屬性的.(如金屬和皮膚、布、塑料反射不同量的光)從而區分不同材質.

高光貼圖再引擎中表現鏡面反射和物體表面的高光顏色。

材質的反光程度就越強。(強弱度度是指,如果將這張Specularmap去色成為黑白圖,圖上越偏向RGB0,0,0,的部分高光越弱,越偏向RGB255,255,255的部分高光越強.)

我們建立高光貼圖的時候,我們使用solid value來表現普通表面的反射,而暗的地方則會給人一種侵蝕風化的反射效果。(你頭腦中要有很清晰的物件不同材質之間高光強弱的關系:高光最強的是那個部分,最弱的是那個部分,處在中間級別的是哪些部分.一般來說:金屬的高光>塑料>木頭>皮膚>不料,但是這個只是一個大致的分類,不要把它作為高光的指導.有時,你處理的物件絕大部分都是同一類型材質的,比如布料,這時你也要小心的去分辨不同材料之間的高光強度的區別.切記,在這個階段一定要保持清晰的頭腦,不要急著去添加那些細節.在大的強弱關系還沒有決定之前,就去添加那些細節會影響你的判斷,而最后得到一張層次不清晰很“花”的高光.很多時候,我們容易犯這樣的毛病,就是將物件的高光處理的太過單一.)

拿一面墻的貼圖舉例,磚的表面與磚縫相比將會有比較少的反光,但是磚縫的位置其實應該幾乎是沒有反光的。(確定好整體高光的強弱之后,就開始在高光上疊加細節:比如金屬劃痕,金屬倒角高光,銹漬周圍的裸金屬亮點,油漬,灰塵等.這時,你會發現,如果你在Diffusemap的繪制過程中,保留了紋理,劃痕或以上提到過的細節的圖層,你只需要將Diffusemap中的相應圖層拖曳到Specularmap中,然后根據這些細節應該反映出來的高光強度調節就可以了.So,良好的圖層管理習慣是非常必要的.)

顏色再高光貼圖中將會用來定義高光的顏色,組成磚的材料應該是一些沙子,他們將會反射出一些微笑的具有質感的光,這些在上面的例子中已經展示了出來。(為了豐富高光貼圖,我們有很多方法:做局部高光的細微變化,添加紋理(這個紋理要和材質本身的紋理區分開),疊加彩色圖層(謹慎用))

高光貼圖是通過Specularmap函數調用到引擎中的,通常我們再貼圖的后面加一個"_s"來區別它。

凸凹貼圖可以通過高光貼圖來改進成相當漂亮的貼圖。(要記住的是,單單憑借高光貼圖是無法充分的表現材質特性的,只有Didffuse,Normal,和Specular三張配合才能充分的表現材質特性.)

﹫﹫在UNITY中,高光貼圖通常放在漫反射貼圖的透明通道里,我們是用相關的SHANDER就可以達到高光的效果。

4. AO貼圖

Ambient Occlusiont簡稱AO貼圖,中文一般叫做環境阻塞貼圖。是一種目前次時代游戲中常用的貼圖技術,很多朋友將其與全局光烘焙貼圖混淆,其實二者本質是完全不同的。

首先,我們從簡單的AO貼圖的算法來講:

AO貼圖的計算是不受任何光線影響的,僅僅計算物體間的距離,并根據距離產生一個8位的通道。計算物體的AO貼圖的時候,程序使每個像素,根據物體的法線,發射出一條光,這個光碰觸到物體的時候,就會產生反饋,標記這里附近有物體,就呈現黑色。而球上方的像素所發射的光,沒有碰觸到任何物體,因此標記為白色。

簡單了解算法后,大家就明白,全局光的烘焙師模擬GI(全局光)所呈現的陰影效果,而AO貼圖時模擬模型的各個面之間的距離。二者性質是完全不一樣的。

我舉例簡單對比AO貼圖和GI陰影貼圖的區別。

根據這個低模,右邊計算出的AO貼圖的黑白關系,是根據物體模型距離產生的,不存在任何光源效果的影響,邊緣部分等比較密集的結構,正確的產生了深色,強化了模型結構,在游戲引擎中,與其他通道貼圖混合,可以提升游戲的效果。

右邊的是全局光烘焙貼圖的效果,是用MAX的天光計算結果進行烘焙,其陰影效果是模擬自然光線下的模型光影關系,在有結構接近的區域(比如褲袋、袖口)由于GI得光線跟蹤計算會使其弱化,符合自然界光線效果,但是不是游戲所需要的效果。

在unity中,我們有兩個地方可以調整AO,一個是在光照貼圖渲染器中,有一個調整AO的參數,這個是確實渲染了一層AO。還有一個就是通過攝影機特效,有一個屏幕空間環境阻塞的特效screen speace ambient occlusion(SSAO).這兩個都可以實現部分的AO效果,有空可以自己嘗試一下。

5. 環境貼圖CUBEMAP

Cube map技術說到底就是用一個虛擬的立方體(cube)包圍住物體,眼睛到物體某處的向量eyevec經過反射(以該處的法線為對稱軸),反射向量reflectvec射到立方體上,就在該立方體上獲得一個紋素了(見下圖)。明顯,我們需要一個類似天空盒般的6張紋理貼在這個虛擬的立方體上。按CUBE MAPPING原意,就是一種enviroment map,因此把周圍場景渲染到這6張紋理里是“正統”的。也就是每次渲染時,都作一次離線渲染,分別在每個矩形中心放置相機“拍下”場景,用FBO渲染到紋理,然后把這張紋理作為一個cube map對象的六紋理之一。這樣即使是動態之物也能被映射到物體表面了(雖然缺點是不能映射物體自身的任何部分)。

CUBEMAP的制作方法:

http://www.cgtextures.com/content.php?action=tutorial&name=cubemaps

unity3d的官網上有一段代碼,叫做Camera.RenderToCubemap

講的是怎樣把我們的場景烘焙成cubemap,里面附有代碼,有興趣的可以在SCRIPT幫助文件中搜索我上一行提到的關鍵詞。

6. 光照紋理LIGHTMAP

什么是烘焙? 簡單地說, 就是把物體光照的明暗信息保存到紋理上, 實時繪制時不再進行光照計算, 而是采用預先生成的光照紋理(lightmap)來表示明暗效果. 那么, 這樣有什么意義呢?

好處:由于省去了光照計算, 可以提高繪制速度?

對于一些過度復雜的光照(如光線追蹤, 輻射度, AO等算法), 實時計算不太現實. 如果預先計算好保存到紋理上, 這樣無疑可以大大提高模型的光影效果,保存下來的lightmap還可以進行二次處理, 如做一下模糊, 讓陰影邊緣更加柔和?

當然, 缺點也是有的:

模型額外多了一層紋理, 這樣相當于增加了資源的管理成本(異步裝載, 版本控制, 文件體積等). 當然, 也可以選擇把明暗信息寫回原紋理, 但這樣限制比較多, 如紋理坐標范圍, 物體實例個數...?

模型需要隔外一層可以展開到一張紋理平面的UV(范圍只能是[0,1], 不能重合). 如果原模型本身就是這樣, 可以結省掉. 但對于大多數模型來說, 可能會采用WRAP/MIRROR尋址, 這只能再做一層, 再說不能強制每個模型只用一張紋理吧? 所以, lightmap的UV需要美術多做一層, 程序展開算法這里不提及....?

靜態的光影效果與對動態的光影沒法很好的結合. 如果光照方向改變了的話, 靜態光影效果是無法進行變換的. 而且對于靜態的陰影, 沒法直接影響到動態的模型. 這一點, 反而影響了真實度。

那么怎么生成lightmap呢?

最直接的辦法: 光線追蹤....(原理想想很簡單, 按照物體定律來就可以了)速度較慢。

下面說的這個是利用GPU進行計算的, 跟實時光照沒什么兩樣:

原理:

想想實時渲染的頂點變換流程: pos * WVP之后, 頂點坐標就變換到屏幕空間了[-1, 1]

如果VertexShader里直接把紋理坐標做為變換結果輸出(注意從[0,1]變換到[-1,1]), 那么相當于直接變換到了紋理坐標系, 這時在PixelShader里還是像原來那樣計算光照, 輸出的結果就可以拿來做lightmap了

靜態模型的Lightmap(光照貼圖)與Vertex-Lighting(頂點光照)之比較

通常有個誤解就是,Vertex-Lighting是一種不費的靜態模型打光手段,因此應該被作為提升地圖運行效率和減少文件尺寸的手段。這種觀點,在這兩方面其實都有問題Lightmap使用平展開的一套UV,如同普通皮膚貼圖所需的。Lightmap的貼圖大小可以靈活設置,比如64x64。這種方式提供了每像素的光照數據Vertex-Lighting使用的數據結構,包含每個頂點所受光照的亮度和色彩信息。

該數據結構消耗特定量的內存,這個量是由模型的頂點數量決定的,不能隨意改變在多數情況下,靜態模型應該設成使用Lightmap,因為這可以產生最好的視覺效果,最好的運行效率,而且比Vertex-Lighting消耗更少的內存Lightmap和Vertex-Lighting相比較,具有如下優點:- Lightmap可以減少CPU和GPU的占用- Lightmap讓CPU需要計算的光照和物體間的互動更少- Lightmap不需要在GPU的多重pass中被渲染- Lightmap pass被整合進Emissive(自發光)pass中,因此可以縮短渲染時間- Lightmap可以表現交錯覆蓋于靜態模型三角面上的復雜的每像素光照,然而Vertex-Lighting只能表現頂點到頂點之間線形的漸變- 使用Lightmap的靜態模型,可以通過優化使用更少的三角形,獲得額外的效率提升。

為使用Vertex-Lighting而制作的模型,通常需要較高的細分度,獲得更多的頂點來改善頂點之間的光照過渡,然而這種做法的副作用是提升了模型的三角形數量并影響運行效率- 靜態模型上的Lightmap可以設置為使用很小的分辨率,比如16x16或32x32,來減少內存開支。這對于遠離游戲中心區域的靜態模型來說,非常有用,這同樣也適合受光很均勻的模型。

Vertex-Lighting就不具有這種優化的便利,它總是消耗同樣數量的內存來存放模型全部頂點的數據結構- Lightmap可以通過調整UV的布局,來進行優化以提供盡可能好的光照質量。比如,有一個球形巖石,可以將它的底部的三角形的UV尺寸做得很小,從而讓這部分在整個Lightmap的UV上面只占據很小一塊,這樣,對于頂部和側面來說,就獲得了更大的貼圖面積于是有更精細的光照效果。Vertex-Lighting的精度總是對應于頂點數,而效果又受模型實際大小的影響(就是說縮小了看還可以的模型,放大比如一百倍,由于頂點不能改變,所以效果也變糙一百倍,而Lightmap因為可以靈活設置精度不存在這個問題),并且不能被優化如果靜態模型的三角形和頂點數量很少的話,那使用Vertex-Lighting可能會比使用Lightmap占用更少的內存,然而,使用Lightmap絕對是看起來更好的,效率也更高的。

使用Lightmap讓LD可以優化光照的質量和內存的占用所以Lightmap顯然是比Vertex-Lighting更好的選擇舉個例子:比如使用UT3這游戲的靜態模型HU_Deco_Pipes.SM.Mesh.S_HU_Deco_Pipes_SM_Pipe01該模型有2555個三角形和2393個頂點如果在場景中放置此模型的420個實例,并且都使用Vertex-Lighting,那么總共消耗11MB內存如果在場景中放置此模型的420個實例,并且都使用32x32的Lightmap,那么總共消耗850kb內存如果在場景中放置此模型的420個實例,并且都使用64x64的Lightmap,那么總共消耗3.3MB內存占用內存的量,也會在地圖文件的尺寸上有所表現這個例子中的一部分實例,其所用的Lightmap的精度,可以設到128x128或者更高以便獲得最佳的光照效果,而仍然使用相比Vertex-Lighting來說更少的內存。并且使用Lightmap的版本,要比Vertex-Lighting版本在渲染上快8-10個百分點。

7. Mipmap和detailmap

首先從MIPMAP的原理說起,它是把一張貼圖按照2的倍數進行縮小。直到1X1。把縮小的圖都存儲起來。在渲染時,根據一個像素離眼睛為之的距離,來判斷從一個合適的圖層中取出texel顏色賦值給像素。在D3D和OGL都有相對應的API控制接口。

透過它的工作原理我們可以發現,硬件總是根據眼睛到目標的距離,來玄奇最適合當前屏幕像素分辨率的圖層。假設一張32768x32768的mipmap貼圖,當前屏幕分辨率為1024*1024。眼睛距離物體比較近時,mipmap最大也只可能從1024*1024的Mipmap圖層選取texel。再次,當使用三線性過濾(trilinear)時,最大也只能訪問2048*2048的圖層選取texel,來和1024*1024圖層中的像素進行線性插值。

DetailMAP

顧名思義,就是細節的貼圖,原理上不用贅述,其實就是圖層的疊加與混合。在這里有幾個關鍵詞,一個是Detail的Tiling值,一個是這個Detailmap需要在導入的時候設置為Mipmap,里面的參數大家可以試著調一下,至于Mipmap的原理,已經在上面介紹了。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容