Unity3D shader簡介


Unity3D shader簡介

可以肯定的說Unity3D使得很多開發者開發游戲更容易。毫無疑問,shader(着色器)編碼,仍有很長的路要走。shader是一個專門運行在GPU的程序,經常被神秘包圍,它最終繪制3D模型的三角形。如果你想給游戲一個特殊的顯示,學習如何編寫shader是必要的。Unity3D使用shader做后期處理,對2D游戲也是必不可少的。這個系列的文章將逐步介紹shader編程,並面向幾乎沒有任何shader知識的開發者。

簡介

下圖大致表示了在Unity3D渲染流程中發揮作用的3個不同實體:

clip_image001

3D模型本質上是,被稱為頂點的3D坐標集合。他們連接在一起構成一些三角形。每個頂點包含一些其它的信息,如顏色、點指的方向(法線)、紋理映射坐標(UV數據)。

沒有材質模型是不能被渲染的。材質包含一個shader和其屬性值的封裝。因此,不同材質可以共享相同的shader,賦予不同的數據。

shader剖析

Unity3D支持兩種不同的shader:表面shader、片段和頂點shader。還有第三種類型:固定管線shader,但是如今已經過時了,將不包含在本系列文章。無論你需要的是哪種類型,shader的結構都一樣:

Shader "MyShader"

{

  Properties

  {

    // The properties of your shaders

    // - textures

    // - colours

    // - parameters

    // ...

  }

 

  SubShader

  {

    // The code of your shaders

    // - surface shader

    //    OR

    // - vertex and fragment shader

    //    OR

    // - fixed function shader

  } 

}

可以包含多個SubShader,一個接一個。他們包含GPU的實際指令。Unity3D將找到與你顯卡兼容的SubShader,並順序執行他們。這對多平台編碼是非常有用,因為你可以在一個文件中編寫同一shader的不同版本。

屬性

shader的屬性在某種程度上相當於C#腳本中的public字段,他們將出現在材質的inspector面板,給你機會來調整。但不像腳本,材質是資源:編輯中游戲運行時修改材質的屬性值是永久的。甚至游戲停止后,修改的屬性值也是有效的。

下面的代碼片段涵蓋了你可以在shader中使用的所有基本類型的定義:

clip_image003

3~4行中的2D,表示參數是紋理。他們可以初始化為whiteblackgray。你也可以使用bump表示使用法線貼圖,這種情況下,它將自動初始為顏色#808080,這用來表示沒有任何凸凹。VectorColor總是有4個元素(分別為xyzwrgba)。

下圖展示了一個shader附着到一個材質上之后,在inspector面板中是如何顯示的。

clip_image004

不幸的是,這對我們使用屬性還不夠。事實上,Properties塊被Unity3D用來從inspector訪問shader隱藏變量。這些變量仍需定義在shader中,它們包含在SubShader塊中。

clip_image006

紋理的類型為sampler2D。向量是float4、顏色一般是half4,分別使用3216位表示。用來編寫shader的語言為Cg/HLSL,很迂腐:參數的名稱必須與先前定義的匹配。然而類型不需要,例如把_MyRange聲明為half而不是float不會報任何錯誤。一些令人困惑的是,如果你定一個向量類型的屬性,關聯到一個float2變量,額外的2個值將被Unity3D忽略。

渲染順序

正如已提到的,SubShader塊包含實際代碼,使用Cg/HLSL(非常像C)編寫。不嚴格地說,一個shader為圖像的每個像素執行,它的性能非常關鍵。由於GPU的體系結構,一個shader中能夠執行的指令數量有限制。可以通過分割幾個部分執行,但本教程不包含這塊。

一個SubShader通常看起來像這樣:

clip_image008

8~11行包含實際的Cg代碼,通過CGPROGRAMENDCG指令示意。

3行,在實際代碼之前,介紹tags的概念。tags用來告訴Unity3D我們寫的shader的某些屬性。例如,shader渲染的順序(Queue)和應該如何渲染(RenderType)。

當渲染三角形時,GPU通常根據它們離攝像機的距離,遠的先繪制。這在渲染不透明的幾何形狀時夠用了,但是透明物體將失敗。這也是為什么Unity3D運行指定Queue標簽,可以控制每個材質的渲染順序。Queue接受正整數(越小越先繪制),預定義(mnemonic)的標簽也可以使用:

l  Background1000):用於背景和天空盒

l  Geometry2000):默認標簽,用於大部分不透明物體

l  Transparent3000):用於包含透明屬性的材質,例如玻璃、火、粒子、水

l  Overlay4000):用於鏡頭耀斑,GUI元素和文本

Unity3D還允許指定相關順序,例如Background+2,表示1002隊列值。搞亂了Queue值會導致惡劣的情況,一個對象總是被繪制,即使它應該被其他模型遮擋住了。

Ztest

記住,一個包含透明屬性(Transparent)的對象並不總是顯示在不透明(Geometry)對象上面。默認情況下,GPU執行ZTest避免隱藏的對象被繪制。原理是,它使用了一個額外的緩沖區,其大小與屏幕渲染的相同。每個像素包含繪制對象在該像素的深度(離相機的距離)。如果我們要繪制一個像素比當前深度更大,像素就被丟棄。ZTest剪裁被其它對象遮擋住的像素,無論他們繪制到屏幕上的順序。

表面 VS 頂點和片段

shader代碼的最后一部分。在渲染之前,需要決定使用那種類型的shader。本節將給出shader效果驚鴻一瞥的樣子,但不會深入解釋。表面、頂點和片段shader將在本教材的下一部分覆蓋。

表面shader

當材質需要根據光照模擬實際效果時,那么你就需要一個表面shader。表面shader在函數surf中隱藏光線如何被反射的計算,並允許指定直觀的屬性,如反照率、法線、反射率等。然后將這些值插入到光照模型,將輸出每個像素的最終RGB值。或者,當需要非常高級的效果是,你也可以編寫自己的光照模型。

一個典型的表面shaderCg代碼如下所示:

clip_image010

clip_image011

5行指定輸入的紋理,然后在第12行將指定Albedo屬性。第3行指定使用Lambertian光照模型,這個是非常典型光照如何影響對象的模型。shader僅使用反照率屬性通常稱為漫反射(diffuse)。

頂點和片段shader

頂點和片段shader的工作貼近GPU渲染三角形的方式,並沒有光照如何表現的概念。模型的幾何形狀首先通過一個調用函數vert,改變他的頂點。然后各個三角形通過另一個調用函數frag,這決定了最終每個像素的RGB顏色。這對2D效果非常有用,后期處理和特殊的3D效果非常付出需要使用表面shader

下面的頂點和片段shader簡單只是使用紅色,沒有光照:

clip_image013

clip_image014

15~17行,將原始的3D空間頂點轉換到最終的2D屏幕位置。Unity3D使用UNITY_MATRIX_MVP實現,隱藏了底層的實現數學運算。在此之后,第22行,給定每個像素為紅色。只需要記住,頂點和片段shaderCg部分需要封裝到Pass塊中。它跟簡單的表面shader不一樣。

結論

本篇文章逐漸引入了兩種類型的Unity3D shader,並說明何時需要使用。接下來四篇文章,將介紹實現它們的細節。還有一個附加篇,將介紹屏幕shader,用於2D圖像的后期處理。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM