天天看點

《Unity着色器和螢幕特效開發秘笈》—— 2.4 壓縮和混合紋理貼圖

本節書摘來自華章出版社《unity着色器和螢幕特效開發秘笈》一 書中的第2章,第2.4節,作者:(美)kenny lammers,更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視。

紋理也可用于存儲大量的資料,但不是一般意義上我們所知道的像素的顔色資訊,而是存儲在x和y方向上以及rgba通道上的多組像素資訊。我們可以将多個圖像打包存儲在單一的rgba紋理上,然後通過着色器代碼提取這些元素,我們就可以使用每個圖檔的r、g、b和a通道的資訊作為一個獨立的紋理了。

下圖是将單個灰階圖像壓縮至一個獨立的rgba紋理的效果:

《Unity着色器和螢幕特效開發秘笈》—— 2.4 壓縮和混合紋理貼圖

這麼做對我們有什麼用處呢?首先,從你的應用程式實際記憶體占用方面來看,紋理在整個應用程式中占有很大比例。是以,為了減少應用程式的大小,我們可以檢視使用着色器時涉及的所有圖檔,看看我們是否可以将它們合并成一個獨立的紋理。

任何灰階的圖檔都可以壓縮至另一個rgba通道的紋理貼圖中。一開始這聽起來似乎有點奇怪,但是本節即将揭示壓縮紋理的一個用處,而且在我們的着色器中也會使用這種紋理。

使用這種壓縮紋理的一個典型例子就是當我們需要将一組紋理混合顯示在一個單一的物體表面時。這種情況大多出現在地形着色器當中,因為在這種情況下,你需要使用一種特殊的紋理操作或者紋理壓縮的方式來完美地進行紋理混合。本節将主要講述這種技術,并且教你如何建構一個優秀的四紋理混合地形着色器。

首先在你的着色器檔案夾中建立一個新的着色器檔案,然後為這個着色器建立一個新的材質檔案,命名約定完全取決于你的着色器和材質檔案,是以請盡量保持它們的統一性友善以後的引用。

準備好你的着色器和材質之後,建立一個新的場景,以便測試我們的着色器。

你還需要準備四張你想混合的紋理。這可以是任何東西,但是為了得到一個效果更好的地形着色器,你最好準備一些草地、泥土、岩石泥土或者岩石紋理。

在本節中我們将使用下面四個彩色紋理,這些紋理在本書的幫助頁面都可以找到。

《Unity着色器和螢幕特效開發秘笈》—— 2.4 壓縮和混合紋理貼圖

最後,我們還需要一個填充了灰階圖像的混合紋理。它包含了四個混合紋理,這樣可以根據它來指導我們如何将顔色紋理映射到物體表面上。

我們可以使用高複雜度的混合紋理來建立一個地形網格上的超現實的紋理分布,如下圖所示:

《Unity着色器和螢幕特效開發秘笈》—— 2.4 壓縮和混合紋理貼圖

通過輸入如下代碼來學習如何使用填充紋理:

1.我們需要添加一些屬性到我們的properties塊中。共需要5個sampler2d類型的對象或紋理,以及兩個顔色屬性。

《Unity着色器和螢幕特效開發秘笈》—— 2.4 壓縮和混合紋理貼圖

2.然後,我們需要建立subshader變量,這樣我們就可以通路properties塊中的資料:

《Unity着色器和螢幕特效開發秘笈》—— 2.4 壓縮和混合紋理貼圖

3.現在,我們已經擁有了紋理特性,并且傳遞到我們的subshader函數中。為了讓使用者可以改變機關基礎紋理的裁剪率,我們需要修改input結構。修改之後允許我們對每個紋理使用裁剪和偏移參數:

《Unity着色器和螢幕特效開發秘笈》—— 2.4 壓縮和混合紋理貼圖

4.在surf函數中,得到了紋理資訊并将其存儲在私有變量中,這樣我們就可以以一種整潔且易于了解的方式與資料進行互動作業了:

《Unity着色器和螢幕特效開發秘笈》—— 2.4 壓縮和混合紋理貼圖

5.然後我們使用lerp()函數(線性插值)對紋理進行混合。它需要三個參數,lerp(紋理值:a,紋理值:b,混合參數:c)。lerp()函數接受兩個紋理參數,并且使用最後一個參數賦予的浮點值對它們進行紋理混合運算:

《Unity着色器和螢幕特效開發秘笈》—— 2.4 壓縮和混合紋理貼圖

6.最後,我們将剛才的混合紋理與色調值相乘,并使用紅色通道來确定兩個不同地形将形成怎樣的色調:

《Unity着色器和螢幕特效開發秘笈》—— 2.4 壓縮和混合紋理貼圖

下圖顯示的是四個地形紋理混合以及建立了一個地形着色技術的效果:

《Unity着色器和螢幕特效開發秘笈》—— 2.4 壓縮和混合紋理貼圖

混合紋理似乎需要多行代碼,但其實它的背後原理還是很簡單的。為了了解該技術是如何工作的,我們必須先從cgfx标準庫中的lerp()函數開始。該函數使我們得到參數1和參數2之間的值并使用參數3來計算混合量。

函數 功能描述

lerp(a,b,f) 涉及線性插值(1-f ) a + b f,在這裡,a和b可以比對為一個矢量或标量類型,f可以是一個标量或者與a、b同類型的矢量。

《Unity着色器和螢幕特效開發秘笈》—— 2.4 壓縮和混合紋理貼圖

是以,假如我們想得到1和2之間的中間值,我們可以将lerp()函數的第三個參數指派為0.5,它将傳回值1.5。這個函數非常适合用于我們的混合紋理,因為在一個rgba紋理中單個通道的值就是單精度浮點數值,而且通常值的範圍在0到1之間。

在着色器中,我們隻是簡單地利用混合紋理中的一個顔色通道,并将它作為lerp函數的權值參數(f參數),這樣就可以影響每個像素的顔色值。例如,我們将提供的草地紋理、泥土紋理,以及混合紋理的紅色通道三個值作為lerp()函數的三個參數。這樣我們得到物體表面上的每個像素值均為正确的混色顔色。

如下圖所示,我們可以使用一種更加直覺的方式來展示使用lerp()函數的效果:

《Unity着色器和螢幕特效開發秘笈》—— 2.4 壓縮和混合紋理貼圖

着色器代碼隻是簡單地使用了混合紋理的四個通道以及提供的幾個顔色紋理,建立出了一個最終的混合紋理。這個混合紋理就可以作為我們的顔色紋理,并且用于我們的漫反射光照。