Unity 渲染系列教程(三):使用多張紋理貼圖
譯者:張乾光(星際迷航)
審校:崔國軍(飛揚971)
對多張紋理貼圖進行採樣。
使用細節紋理貼圖。
在線性空間中處理顏色
使用splat貼圖。
這是關於渲染基礎的系列教程的第三部分。前面兩個部分介紹了著色器和紋理。我們已經看到了如何使用單個紋理來讓平坦表面看起來更複雜。現在我們繼續向前進,試下同時使用多個紋理。
這個系列教程是使用Unity 5.4.0開發的,這個版本目前還是開放測試版本。我使用的是build5.4.0b10版本。
同時使用多個紋理。
細節貼圖
紋理對於渲染的效果是很好的,但是紋理也有自己的局限性。紋理的像素數目是固定數量的,無論它們顯示出來的尺寸是什麼。如果它們被渲染得很小的時候,我們可以使用mipmap來盡量讓紋理看起來還不錯。
但是當紋理被渲染得很大的時候,它們會變得模糊。我們不能無條件地提供額外的細節,所以沒有辦法處理放大的問題。或者是否有其他辦法可以處理紋理被放大的問題?
當然,我們肯定可以使用更大的紋理。而更多的紋理的像素意味著更多的細節。但是紋理的大小有限制。而且存儲大量額外的數據是很浪費的,這些數據只能在用戶很靠近的時候才會注意到。
增加紋理的像素密度的另一種方法是平鋪紋理。
然後你可以得到你所期望的一個很小的紋理,但你會明顯得到一個重複的模式。雖然這可能在很靠近看的時候不是很明顯。畢竟,當你站在你的鼻子就能觸到一堵牆的位置的時候,你只會看到整個牆一個非常小的一部分。
因此,我們應該能夠通過將一個沒有進行平鋪操作的紋理與一個進行了平鋪操作的紋理組合來添加細節。為了嘗試這個組合效果,讓我們使用具有明顯重複模式的紋理。這是一個方格網格。下載得到它,並把它放到你的項目中去,使用默認的導入設置。我稍微了擾亂了下網格線,使它更加的有趣,也能感知到它處於平鋪模式。
網格線稍微扭曲下的紋理貼圖。
複製My First Shader裡面的代碼到新的文件裡面並將它命名為TexturedWith Detail。從現在開始,我們將使用這個新的著色器。
使用這個著色器創建一個新的材質,然後為這個材質分配網格貼圖。
帶有網格的詳細材質。
將材質分配給一個四邊形並看下效果。從遠處看的話,它的效果會看起來很好。但是如果離得太近的話,它會變得模糊和含糊不清。除了缺乏細節以外,由紋理壓縮引起的瑕疵也將變得愈發明顯。
網格的特寫,顯示了紋理像素過低和DXT1這種壓縮方式引起的瑕疵。
多個紋理的採樣
現在我們採用的是單個紋理的採樣,並使用單個紋理的採樣作為我們的片段著色器的結果。因為我們要改變這種方法,所以將採樣的顏色存儲在一個臨時變數中是很方便的。
我們推測我們可以通過引入平鋪紋理來增加紋理像素的密度。讓我們簡單地執行對第二個紋理的採樣,這個紋理採樣的密度是原始紋理採樣的密度的10倍。 第二個紋理實際上替換原來的顏色,只是還有添加它。
這產生了更小的網格。你可以在它開始看起來效果不好之前能夠離得更近進行觀察。當然,因為網格是不規則的,它很顯然在不停的重複。
硬編碼進行的平鋪。
需要的注意是,在現在進行處理的時候,我們執行的是兩個紋理採樣,但最終只使用了其中一個採樣的結果。這似乎是一種浪費。是嗎?看下編譯後的頂點程序。就像在前面的教程所做的中一樣,我將包括OpenGLCore平台和Direct3D 11平台上的相關編譯代碼。
你注意到編譯後代碼中只有一個紋理採樣么?沒錯,編譯器刪除了不必要的代碼!基本上,它的工作方式是從最終結果往回推所需要的東西,並丟棄任何在最終結果中未使用的東西。
當然,我們不想替換原始的紋理採樣。我們想結合這兩個紋理採樣。讓我們試驗下將它們相乘在一起。但是,我們再一次給紋理貼圖添加一點扭曲。對紋理採樣兩次,並使用完全相同的UV坐標。
著色器的編譯器到底做了什麼?
再次,我們最終得到了一個單一的紋理採樣。著色器的編譯器檢測到重複代碼並對其進行了優化。所以紋理貼圖只採樣一次。紋理採樣的結果存儲在寄存器中並重複使用。著色器的編譯器足夠聰明,可以檢測出這樣的代碼重複,即使你使用了中間變數也是如此。著色器的編譯器將一切都追溯到提供給編譯器的原始輸入。然後它儘可能有效地重組所有的一切。
現在把第二個紋理貼圖乘以10以後 UV坐標進行打包。我們終於看到大的和小的網格的結合。
兩個不同的貼圖相乘的結果。
由於紋理貼圖的採樣不再相同,編譯器也必須使用兩個紋理採樣。
單獨的細節紋理貼圖
當兩個紋理貼圖相乘在一起的時候,所得到結果將變得更暗。除非至少有一個紋理是白色的。這是因為紋理像素的每個顏色通道的值介於0和1之間。當向紋理添加細節貼圖的時候,你可能需要進行變暗處理,也可以進行增亮處理。
要使原始紋理變亮,你需要的值必須大於1。假設這個值最多為2,這將使原始的顏色的亮度加倍。這可以通過在將細節貼圖與原始顏色相乘之前將細節貼圖的採樣值加倍來給予支持。
顏色值加倍後的細節貼圖。
這種方法需要我們重新解釋用於細節貼圖的紋理。對細節貼圖的顏色值乘以1不會更改任何內容。但是當我們對細節貼圖的顏色值加倍的時候,現在只有對原來採樣值為1/2的地方不會產生影響。這意味著,一個只有灰色 -不是白色-的紋理將不會產生變化。而所有原來採樣值低於1/2的地方將變得變暗,而任何原來採樣值高於1/2的地方將變得變亮。
所以我們需要一個特殊的細節貼圖,以灰色為中心。下面就是這樣的一個紋理貼圖。
網格的細節紋理貼圖。
細節紋理貼圖必須是灰度圖么?
細節紋理貼圖不是必須是灰度圖,但通常情況下細節紋理貼圖都是灰度圖。用灰度圖作為細節紋理貼圖將通過增亮和變暗來嚴格調整原始的顏色。這是相對直接的工作。因為與非灰度圖進行乘法往往產生比較不直觀的結果。但沒有什麼理由一定阻止你這樣做。用彩色圖作為細節紋理貼圖往往用於產生細微的色彩偏移。
要使用這個單獨的細節紋理貼圖,我們必須向我們的著色器添加第二個紋理屬性。我們使用灰色作為默認值,因為這不會更改主紋理的外觀表現。
將細節紋理貼圖分配給我們的材質,並將細節紋理貼圖的平鋪設置為10。
使用兩張紋理貼圖。
當然,我們必須添加變數來訪問細節紋理貼圖以及它的平鋪和偏移數據。
使用兩對UV坐標
我們不再是直接使用乘以10這種硬編碼方案,而是應該使用細節紋理貼圖的平鋪和偏移數據。我們可以在在頂點程序中像計算主紋理貼圖的UV坐標那樣計算出最終的細節紋理貼圖的UV。這意味著我們需要插入額外的UV坐標對。
新的細節紋理貼圖的UV坐標是通過將原始紋理貼圖的UV坐標與細節紋理貼圖的平鋪和偏移一起轉換而創建出來的。
這意味著兩個UV坐標對被打包到單個輸出寄存器中去。第一個UV坐標對使用的是X和Y通道,第二個UV坐標對使用的是Z和W通道。 這種做法是可能的,因為寄存器總是有四個通道。Direct3D 11編譯器利用了這一點。
你能像這樣手動打包輸出嗎?
是的,你可以輸出任何你想要的內容。因此,在四個通道值的輸出包中分離出一些信息進行打包是很正常的。如果內插值最終成為瓶頸的話,使用較少的輸出寄存器可能會提高著色器的性能。
手動打包輸出的常見原因是因為只有幾個內插值器可以使用。符合Shader Model 2規範的硬體支持8個通用內插器,而符合Shader Model 3規範的硬體支持10個通用內插器。複雜的著色器可以用滿這個限制。
現在我們可以在片段程序中使用額外的UV坐標對。
我們的著色器現在功能齊全。主紋理通過基於細節紋理貼圖的調製,可以變得更亮或者更暗。
通過細節紋理貼圖的調製,實現的亮化和調光。
讓細節紋理貼圖淡出
我們添加細節紋理貼圖的原因是,它們可以在離得很近或者紋理被放大的時候改善材質的外觀表現。在離得很遠或者紋理被縮小的時候它們被認為不應該是可見的,因為這會使得紋理平鋪更加的明顯。所以我們需要一種方法來在紋理的顯示尺寸減小的時候,能夠對細節紋理貼圖進行淡出處理。我們可以通過將細節紋理貼圖逐漸淡化為灰色來實現,因為這不會導致顏色的變化。
這個想法我們以前實現過!我們需要做的是在細節紋理貼圖的導入設置中啟用Fadeout Mip貼圖。需要注意的是,這也自動將過濾器模式切換為三線性濾波,使得細節紋理貼圖逐漸淡化為灰色。
對細節紋理貼圖進行淡出處理。
網格從有細節紋理貼圖的狀態到沒有細節紋理貼圖的狀態的過渡非常的明顯,但是你通常不會注意到這個變化。讓我們舉個簡單的例子來說明,這裡是大理石材質的主紋理貼圖和細節紋理貼圖。得到它們,並使用我們用於網格紋理貼圖的相同紋理導入設置導入到項目中去。
大理石材質的主紋理貼圖和細節紋理貼圖。
一旦我們的材質使用這些紋理貼圖,那麼細節紋理貼圖的淡出效果就不再明顯。
大理石材質。
然而,由於細節紋理貼圖的存在,大理石看起來離得非常近的時候的視覺效果更好。
離得非常近的時候有細節紋理貼圖和沒有細節紋理貼圖的效果對比。
線性顏色空間
當我們在伽馬顏色空間中渲染我們的場景的時候,我們的著色器能夠正常工作,但如果我們把渲染切換到線性顏色空間就會出錯。選擇使用哪個顏色空間屬於項目設置的範圍。它可以在播放器設置的其他設置面板中進行配置,你可以通過Edit / Project Settings / Player訪問到。
選擇對應的顏色空間。
什麼是伽馬空間?
伽馬空間是指伽瑪校正後的顏色空間。伽瑪校正是對光強度的調整。最簡單的方法是將原始值做一些次方,因此是。 Gamma值為1表示沒有變化。 Gamma值為2表示對原始值進行平方處理。
這種轉換最初被引入是為了適應陰極射線顯像管顯示監視器在顯示顏色方面的非線性性質。伽瑪校正的另一個好處是,它大致對應於我們的眼睛對不同光強度的敏感程度。我們注意到深色之間的差異比對明亮的顏色之間的差異更加明顯。因此,將數字的更多位用於比較暗的顏色值比用於比較亮的顏色值更有意義。 通過使用指數可以允許我們在較大範圍上拉伸比較小的值,同時還能壓縮比較大的值。
最廣泛使用的圖像顏色格式是sRGB。它使用比簡單求冪更複雜的公式,但它存儲的顏色的平均伽瑪值為1 / 2.2。這個值在許多情況下是合理的近似。要將sRGB圖像顏色格式中的數據轉換回其原始顏色,請應用2.2的伽瑪校正。
使用gamma 1 / 2.2進行編碼和使用gamma 2.2進行解碼。
Unity假定紋理貼圖和顏色存儲為sRGB這種圖像顏色格式。當在伽馬空間中進行渲染的時候,著色器直接訪問原始的顏色和紋理數據。這是我們到現在為止所假設的條件。
當在線性空間中渲染時,這些假設不再為真。圖形處理器將紋理採樣的結果轉換為線性空間的顏色值。此外,Unity還會將材質顏色屬性轉換為線性空間的顏色值。然後著色器使用這些線性空間的顏色值進行操作。在這之後,片段程序的輸出將被轉換回伽馬空間。
使用線性空間的顏色值的優點之一是它可以實現更加逼真的光照計算。這是因為光的相互作用在現實生活中是在線性空間發生的,而不是在指數上發生的的。不幸的是,它限制了我們的細節材質。切換到線性空間後,細節紋理貼圖變得更暗。為什麼會發生這種情況呢?
同一貼圖在伽馬顏色空間和線性顏色空間中的比較。
因為我們將細節紋理貼圖的採樣值加倍,所以採樣值為1/2的話,將導致主紋理的顏色沒有變化。然而,轉換為線性顏色空間後,這個採樣值被改變為接近。 加倍以後大約是0.44,這比1小得多。所以導致了變暗。
我們可以通過在詳細紋理貼圖的導入設置中啟用「Bypass sRGB Sampling」選項來解決這個問題。啟用這個選項以後會防止從伽馬顏色空間到線性顏色空間的轉換,因此著色器將始終訪問原始的圖像數據。然而,細節紋理貼圖是一個sRGB圖像,所以結果仍然是錯誤的。
最好的解決方案是重新調整細節紋理貼圖的顏色,使這些顏色值再次以1為中心。我們可以通過乘以而不是2來做到這一點。但是,當我們在線性空顏色間中進行渲染的時候,我們必須這樣做
幸運的是,UnityCG定義了一個統一的變數,它將包含要乘以的正確數字。這個統一的變數是一個float4類型,在其rgb組件中的值大概是2或大約4.59,會根據顏色空間選擇適當的值。由於伽瑪校正不會對透明度通道起作用,因此它始終為2。
有了這種變化,無論我們是在哪個顏色空間進行渲染,我們的細節材質都將看起來是相同的。
紋理splatting技術
細節紋理貼圖的限制在於,對於整個表面使用的是完全相同的細節。這對於一個統一的表面,如大理石板來說工作的很正常。然而,如果你的辭職沒有統一的外觀,你不會想在任何的地方都使用相同的細節紋理貼圖。
考慮一個比較大的地形塊。它可以有草、沙、岩石、雪等等。你希望這些地形類型在離得很近觀察的時候能夠有足夠詳細的細節。但是覆蓋整個地形的紋理將不會有足夠的紋理像素來提供這麼多的細節。你可以通過對每個表面類型使用單獨的紋理貼圖來解決這個問題,並且對這些單獨的紋理貼圖進行平鋪。但是你怎麼知道在哪裡該使用哪個紋理貼圖呢?
讓我們假設我們有一個具有兩種不同表面類型的地形。在每一個點上,我們必須決定使用哪個表面紋理貼圖。到底是第一個還是第二個。我們可以用一個布爾值來表示該使用哪個表面紋理貼圖。
如果這個布爾值設置為true的話,我們使用第一個表面紋理貼圖,否則的話我們使用第二個表面紋理貼圖。我們可以使用灰度紋理貼圖來存儲這個選擇。值1表示使用第一個表面紋理貼圖,值0表示使用第二個表面紋理貼圖。事實上,我們可以使用這些值在兩個紋理之間進行線性內插值。那麼0和1之間的值表示兩個紋理之間的混合。這使得平滑過渡成為可能。
這樣的紋理貼圖被稱為splat貼圖。這就像你將多個地形特徵散布到畫布上。 由於插值的存在,這章貼圖甚至不需要高解析度。這裡是地圖的一個小例子。
splat貼圖的二進位表示。
將splat貼圖添加到項目億後,將splat貼圖的導入類型切換到高級類型。 啟用「Bypass sRGB Sampling」設置,並指示應該在線性顏色空間中生成對應的mipmap。這是必需的,因為紋理不能表示sRGB顏色,但可以選擇。因此,在線性顏色空間中進行渲染時不應該進行轉換。此外,將這個貼圖的圍繞模式設置為clamp,因為我們不會平鋪這個貼圖。
紋理貼圖的導入設置。
通過複製My First Shader文件的內容到新文件,並修改新文件的名字來創建新的TextureSplatting著色器。因為地形通常不是均勻著色,讓我們擺脫均勻著色的功能。
創建使用這個著色器的新材質,並將splat貼圖指定為新材質的主要紋理。 因為我們還沒有對這個著色器添加什麼內容,所以這個著色器只會顯示紋理貼圖。
顯示的是splat貼圖。
增加一張紋理貼圖
為了能夠在兩個紋理貼圖之間進行選擇,我們必須將兩個紋理貼圖作為屬性添加到我們的著色器中去。讓我們把這兩個紋理貼圖命名為Texture1和Texture2。
你可以使用任何你想要的紋理貼圖。我只是選擇了我們已經有的網格貼圖和大理石紋理貼圖。
兩張額外的紋理貼圖。
當然,我們可以為添加到著色器中的每個紋理鐵蹄進行平鋪和偏移控制。我們確實為每個紋理貼圖進行單獨的平鋪和偏移控制的支持。但是,這將需要我們將更多的數據從頂點著色器程序傳遞到片段著色器程序,或者計算像素著色器中的UV調整。這當然很好,但是通常地形中的所有紋理都是平鋪的。而splat貼圖不是平鋪的。因此,我們只需要一個平鋪和偏移控制項的實例。
你可以向著色器的屬性中添加屬性,就像在C#代碼中所做的那樣。NoScaleOffset屬性將做為它的名字建議。是的,它指的是將平鋪和偏移作為縮放和偏移。這並不是非常一致的命名方式。
讓我們將這個屬性添加到我們的額外紋理貼圖的屬性中去,並保持主紋理的平鋪和偏移方面的輸入。
現在,平鋪和偏移控制項出現在我們的著色器檢查器的頂部。雖然他們挨著splat貼圖的設置,我們實際上將平鋪和偏移控制項應用到其他紋理。
沒有額外的平鋪和偏移控制項。
現在我們必須將採樣器變數添加到我們的著色器代碼中。但是我們不必添加採樣器變數相應的_ST變數。
要檢查我們是否可以以這種方式對兩個紋理貼圖進行採樣,請更改片段著色器,以便將這兩個紋理貼圖添加到一起。
添加以後,現在有兩張紋理貼圖了。
使用Splat貼圖
為了對splat貼圖進行採樣,我們還必須將未修改的UV坐標從頂點程序傳遞到片段程序。
然後我們可以在採樣其他紋理之前對splat貼圖進行採樣。
我們決定值為1的話代表第一個紋理貼圖。由於我們的splat貼圖是單色的,我們可以使用任何RGB通道來檢索這個值。讓我們使用R通道並將其乘以紋理貼圖。
調整第一個紋理貼圖。
第一個紋理貼圖現在由splat貼圖進行調製。為了完成插值,我們必須將另一個紋理貼圖乘以1-R。
對兩個紋理貼圖都進行調整。
使用RGB通道的Splat貼圖
我們現在有了一個能起作用的splat材質,但是它只支持兩個紋理貼圖。我們可以支持更多的紋理貼圖嗎?我們目前只使用了R通道,那麼我們如果添加R和G通道會怎麼樣呢?然後用(1,0,0)表示第一張紋理貼圖,用(0,1,0)表示第二張紋理貼圖,用(0,0,1)表示第三張紋理貼圖。為了在這三者之間獲得正確的插值,我們只需要確保RGB通道的值總是加起來等於1就行了。
但是等一下,當我們只使用一個通道的時候,我們可以支持兩個紋理貼圖。這是因為第二個紋理貼圖的權重是通過1-R導出的。這個技巧適用於任何數量的通道。因此,可以通過1-R-G-B支持另一個紋理貼圖。
這導致splat貼圖具有三種顏色和黑色。只要三個通道的值加在一起不超過1的話,它就是一個有效的貼圖。這裡是一張有效的貼圖,獲取它,並使用與以前相同的導入設置導入到項目中去。
使用RGB通道的splat貼圖。
當R+ G + B的值超過1的時候會發生什麼?
那麼前三個紋理的組合將會變得太強。與此同時,第四個紋理貼圖的值將被減去而不是被添加進去。如果誤差很小的話,那麼你不會注意到,結果也是足夠好的。示例中的RGB地圖實際上不是完美的,但是你不會注意到。紋理壓縮會引入更多的錯誤,但是它再也不是很明顯能讓人注意到。
我們可以使用透明度通道嗎?
事實上你可以使用透明度通道!這意味著單個使用RGBA通道的splat貼圖可以支持多達五種不同的地形類型。但對於這個教程而言,支持四種不同的地形類型就足夠了。
如果你想使用超過五個紋理貼圖,你必須使用多個splat貼圖。雖然這是可能的,但是這會導致你有很多的紋理採樣。對於這個問題有更好的技術可以支持,比如說紋理數組。
為了支持使用RGB通道的splat貼圖,我們必須為我們的著色器添加兩個額外的紋理貼圖。我給我們的著色器分配了大理石細節紋理貼圖和測試紋理貼圖。
四張紋理貼圖。
將所需的變數添加到著色器代碼之中。再次重申,我們不需要額外的_ST變數。
在片段程序中,添加額外的紋理貼圖採樣。第二個紋理貼圖採樣現在使用G通道,第三個紋理貼圖採樣現在使用B通道。而最終的紋理貼圖採樣使用(1-R-G-B)作為係數進行調製。
支持四張紋理的splat貼圖。
為什麼混合區域的表現會在線性顏色空間之中看起來不同?
我們的splat貼圖繞過了sRGB採樣,所以混合不應該依賴於我們使用的顏色空間,對吧? Splat貼圖確實是不受到影響。但是混合發生的顏色空間會受到影響。
如果是在伽馬空間中進行渲染,採樣後的結果是在伽馬空間中混合,這就沒什麼問題。但是當在線性空間中進行渲染的時候,採樣後的結果需要首先轉換為線性空間中的值,然後再進行混合,然後再轉換回伽馬空間。結果會略有不同。在線性空間中,混合也是線性的。但是在伽馬空間中,混合會傾向於更暗的顏色。
現在你知道如何使用細節紋理以及如何使用splat貼圖來混合多個紋理了。你還可以對這些方法進行組合。
你可以向splat著色器添加四個細節紋理,並使用貼圖在它們之間進行混合。 當然,這需要四個額外的紋理採樣,所以這麼做是要付出一定代價的。
你還可以使用貼圖來控制細節紋理會應用到哪裡,以及在哪裡會省略細節紋理。在這種情況下,你需要一個單色貼圖,它用作掩碼。當單個紋理包含表示不同材質的區域,但又不像地形有那樣大的尺度的時候,這是非常有用的。舉個簡單的例子來說,如果我們的大理石紋理裡面也包含金屬塊,你不會想要應用那裡面的大理石紋理細節。
這個系列的下一篇教程是《第一個光源》。
【版權聲明】
原文作者未做權利聲明,視為共享知識產權進入公共領域,自動獲得授權。
※利用TexturingXYZ貼圖製作皮膚細節的課程
※Photoshop解析合成教程中紋理貼圖運用
※Army 都下載了嗎?LINE、Kakao 為防彈少年團《Love Myself》共襄盛舉 專屬貼圖大舉出爐
※World Emoji Day 這一天,Tinder 開始支持 Bitmoji 貼圖表情
※3DsMax——平鋪貼圖的常用使用設置
※Instagram 坦承測試限時動態分享他人貼文的功能,可加評論或貼圖
※設置3dmax筒燈模型的自發光貼圖的方法與步驟教程
※貼圖功能背後!WhatsApp 副總裁確認準備將廣告置於狀態列
※PS學習教程 製作超真實水波貼圖
※全能Mari以假亂真成就一代阿凡達 電影材質貼圖繪製之巔《Mari全能》教程全國首發
※Switch版《收穫日2》貼圖質量差 可視距離沒問題
※圖集| 衛衣、連衣裙、襯衫的效果圖+款式圖+UV貼圖
※簡單強大的免費Mac截圖工具,還有貼圖功能
※衛衣、連衣裙、襯衫的效果圖+款式圖+UV貼圖
※《上古捲軸5:天際》新MOD 加入4K高清岩石貼圖
※學界 | 用GAN自動生成法線貼圖,讓圖形設計更輕鬆
※用GAN自動生成法線貼圖,讓圖形設計更輕鬆
※除了貼圖和玩偶 Line的下一個目標是虛擬貨幣市場
※16款連衣裙的效果圖+款式圖+UV貼圖
※8款女士夏裝的效果圖+款式圖+UV貼圖