天天看點

《Unity着色器和螢幕特效開發秘笈》—— 2.6 在Unity編輯器中建立程式紋理貼圖

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

有時你為了建立更多不一樣的效果,需要動态建立紋理或者在運作時修改它們的像素值,這種情況通常被稱為程式性的紋理效果。不同于你在圖像編輯軟體中手動制作一些新紋理,你需要在一個二維空間中建立一組像素然後将其應用到一個新的紋理上。再将建立的新紋理傳入到着色器中,使它們可以在着色器中進行計算。

這種技術在已有的紋理貼圖上進行繪圖是非常有用的,我們使用動态建立紋理貼圖的方式可以制造一種玩家和遊戲環境之間的互動效果。也可以用它來制作一些貼花的效果,或者建立一些可以在着色器函數中使用的程式化形狀等。在很多情況下比如你可能想建立一個新紋理并且将它比對到某些程式模式,另外你也可以将它應用到你的着色器中。

建立動态紋理的過程其實就是對你的紋理進行處理的過程,它肯定需要依賴于一個專門的腳本。但是你需要了解它是如何實作的,換句話說,你應該知道在你的着色器管線中需要哪些技術。讓我們來看看如何通過建立一個腳本實作将動态建立的紋理賦給表面着色器。

你需要通過執行以下步驟來為本節做些準備:

1.在你的unity項目中建立一個新的c#腳本,并将其命名為proceduraltexture。

2.在場景中建立一個空的遊戲對象,将其position(位置)置零,并将procedural-texture.cs腳本附加到該物體上。

3.接下來,建立一個新的着色器,一個新的材質,以及一個可以附加着色器和材質的對象。确定你的着色器和材料的命名,使你通過名字可以很容易地找到它們。

4.設定好了這一切,我們就可以建立一段代碼實作一個抛物線型的像素值,将其應用至一個紋理并将該紋理賦給着色器。通過本節的學習,你将建立一個如下圖所示的紋理貼圖:

《Unity着色器和螢幕特效開發秘笈》—— 2.6 在Unity編輯器中建立程式紋理貼圖

1.建立一個變量來控制紋理的高度和寬度,以及一個texture2d類型的變量來存儲我們生成的紋理。我們還需要幾個私有變量來存儲腳本運作時涉及的一些變量值。

《Unity着色器和螢幕特效開發秘笈》—— 2.6 在Unity編輯器中建立程式紋理貼圖

2.在腳本的start()函數中,我們首先需要檢查對象,檢視該對象的材質屬性是否已經指派。如果材質不為空,我們将調用自定義函數generateparabola(),并為我們傳回一個texture2d類型的變量值:

《Unity着色器和螢幕特效開發秘笈》—— 2.6 在Unity編輯器中建立程式紋理貼圖

3.然後,我們需要聲明自定義函數generateparabola(),它将實作我們預期的效果:

《Unity着色器和螢幕特效開發秘笈》—— 2.6 在Unity編輯器中建立程式紋理貼圖

4.最後,我們還要填充自定義函數,實作一個抛物線形紋理的算法。現在先不用關心這些内容的具體意義,我們将在本章的下一節詳細地講解每一行代碼。

《Unity着色器和螢幕特效開發秘笈》—— 2.6 在Unity編輯器中建立程式紋理貼圖
《Unity着色器和螢幕特效開發秘笈》—— 2.6 在Unity編輯器中建立程式紋理貼圖

在腳本開始處,我們先簡單地檢查場景中的特定對象,看看是否有材質賦給該對象,這樣我們才能給它指定一個紋理。如果該對象的材質不為空,我們會将自定義的currentmaterial變量值賦給transform.renderer.sharedmaterial的傳回值,該傳回值是一個材質類型變量。

然後,進入下一個if()語句,檢查目前材質值是否為有效值。如果材質值有效,我們就調用generateparabola()函數,該函數将為我們傳回一個texture2d類型的值。

當程式運作到generateparabola()函數時,它會先通過texture2d()構造函數建立一個新的紋理,并且傳入我們的widthheight變量。完成這一步後我們将建立一個空的紋理,這樣我們就可以遞歸widthheight的平方次為每個像素填充相應的顔色值了。

建立了新的紋理以後,我們計算中心像素的位置,并使用centerpixelposition變量來存儲該值。

接下來,對于循環内目前像素值的位置vector2(x,y),我們使用vector2.distance()函數計算它與中心像素的距離,該函數将為我們傳回一個浮點值。舉例來說,如果在循環中的目前像素位置是vector2(32,32)而且我們建立的是一個512×512的紋理,那麼我們得到的距離值等于316.78。也就是說,它與中心點的像素距離為(32,32)。

然後,我們需要将像素距離值重新映射至0到1的範圍内,這樣它才能作為一個顔色值被我們使用(unity使用的顔色值範圍是從0到1的)。為了實作這種映射我們需要做的就是将距離值除以紋理的寬度或高度值的一半。是以,在這種情況下,我們需要把我們的距離值除以256,也就是512的一半。是以,如果我們有一個大小為316.78的距離值,正如我們在前面的例子中看到的一樣,我們會得到一個大小為1.23的顔色值。

現在,我們還需要確定我們得到的任何值都不能高于1.0或低于0.0,是以我們使用mathf.clamp()函數,它可以讓我們将值限定在你傳遞的參數範圍内。我們給該函數傳入0和1兩個值,以確定我們得到的是一個歸一化的值。

最後,我們用1減去目前值對顔色值進行取反,然後将最後的值傳遞給一個新的顔色變量的各個通道。如下圖所示:

《Unity着色器和螢幕特效開發秘笈》—— 2.6 在Unity編輯器中建立程式紋理貼圖

現在你已經看到了如何使用少量的矢量數學生成像素值,你也可以試着生成其他類型的資料并将它們存儲到一個紋理當中。下面的代碼示範了通過使用世界向量和圖像中心到目前像素的向量方向兩者的點積來生成其他類型資料。

1.下面就是使用數學公式建立一個環繞紋理中心的環形:

《Unity着色器和螢幕特效開發秘笈》—— 2.6 在Unity編輯器中建立程式紋理貼圖

2.下面是使用數學公式計算像素方向上的點積,相對世界向量的vector3.up(vector3(0, 1, 0) y軸)和vector3.right(vector3(1, 0, 0) x軸):

《Unity着色器和螢幕特效開發秘笈》—— 2.6 在Unity編輯器中建立程式紋理貼圖

3.下面是使用數學公式計算像素方向相對世界方向的角度:

《Unity着色器和螢幕特效開發秘笈》—— 2.6 在Unity編輯器中建立程式紋理貼圖

生成像素使用不同的向量和角度計算會産生不同的計算結果,我們可以通過下圖看出:

《Unity着色器和螢幕特效開發秘笈》—— 2.6 在Unity編輯器中建立程式紋理貼圖