本篇文章使用Unity 2019 LTS版本,畫面及API可能會有所不同。
首先先新增一個Shader出來。
Create -> Shader -> Unlit Shader
新增一個材質(Material)
Create -> Material
將剛的Shader附加上去在這個新的Material上去。
在場景中,創建一個新朋友,來當我們實驗對象,這邊我選了Sphere。(作者很黑,會把朋友拿去做實驗)
把剛剛材質(Material)附加到我們新朋友上,準確來說是Mesh Renderer的Materials。
用你最喜歡的編輯器把Shader打開後,把預設的程式碼都刪掉,貼上以下的程式碼。這樣我就完成了一個最簡單「不受光源影響,可以變更顏色」的Shader。
以下的程式碼已經在註解中給出了該片段的意思,下面我會解釋各個區塊。
// Shader的名稱
Shader "Learning/MySimpleShader"
{
// 屬性
Properties
{
_Color ("Color", Color) = (1.0, 1.0, 1.0, 1.0)
}
SubShader
{
Pass
{
// 設定名稱、繪製狀態和標籤,可選項目
// 在這個例子中,我們不需要進行更多設置
// 開始撰寫Shader
CGPROGRAM
// 宣告vertex / fragment shader的名稱
#pragma vertex vert
#pragma fragment frag
// 使用定義在Properties區塊的屬性
// 注意:變數必須和區塊中的屬性以及變數名稱一致
fixed4 _Color;
// 頂點 Shader
float4 vert(float4 v : POSITION) : SV_POSITION {
return UnityObjectToClipPos(v);
}
// 片段 Shader
fixed4 frag() : SV_TARGET {
return _Color;
}
ENDCG
// 結束撰寫
}
}
// 若以上兩種Shader皆無法運行,則使用這個最低階的Shader
// 若「不留後路」,也可直接關閉該選項
// `Fallback Off`
Fallback "VertexLit"
}
會發現這些內容很像C語言的語法,這是Unity提供給自家Shader的說明性語言,ShaderLab。
我們往後寫的Shader都是包在這層大括號裡面,第二行的字串代表這個Shader叫做甚麼名字,以及在利用下拉選單選擇Shader時,會放在哪一層資料夾裡面。
該區塊定義變數會顯示在被附加的材質(Material)上,我們的Shader若要使用這個屬性,還要再CGPROGRAM/ENDCG中,宣告與其屬性相同的變數。
Unity有提供以下的屬性供開發者使用。
Properties
{
_Int ("Integer", Int) = 10
_Float ("Float", Float) = 3.14
_Range ("Range", Range(-1.0, 1.0)) = 0.0
_Color ("Color", Color) = (1.0, 1.0, 1.0, 1.0)
_Vector ("Vector", Vector) = (1.0, 0.6, 7.5, 1.0)
_2D ("Texture2D", 2D) = ""{}
_Cube ("Texture Cube", Cube) = "white"{}
_3D ("Texture 3D", 3D) = "black"{}
}
讀者可能發現在Shader裡使用的變數是fixed4
型別。
Unity Shader對於浮點數的精度有3種,float為最高,依序下去為half跟fixed。對於何時去選用哪一種,官方文件有給出建議,並不是一定的。
一款遊戲通常不會只發售一個平台,所以在Shader的撰寫上,會因應多個平台有不同的SubShader。
注意一個Unity Shader至少需要一個SubShader。
一個Pass就是一次完整的繪製流程
Pass和SubShader一樣,可以在一個SubShader中,定義多個Pass,遊戲中許多絢麗的效果是需要多Pass處理的,同時使用過多的Pass會造成效能降低。
我們主要功能的程式碼是寫在這個區塊裡面的,會發現這些函式與C語言非常相近,設置看的出來有些式macro。
先來看看第21行和第22行
#pragma vertex vert
#pragma fragment frag
表示我們要將我們的vertex shader和fragment shader稱做甚麼,不知道甚麼是vertex shader或是fragment shader沒關係,我們很快就會提到他,在這裡,我們只需要知道:
上面的範例,vertex shader只有一句:
return UnityObjectToClipPos(v);
意思是將物件的頂點從模型空間經過線性轉換至裁剪空間,這個函式是Unity提供的內建函式,更多的資訊可以參見官方文件
在fragment shader中,直接讓我們要輸出的像素塗上我們所選的顏色:
return _Color
發現到fragment shader的函式後面還有一個SV_TARGET
,SV
表示system,是所謂的「語意」,原本來自於HLSL,用途在於告訴編譯器,這個變數是拿來做甚麼用的,往後我們會看到像是POSITION
表示頂點的座標;TEXCOORD0
表示第一組紋理(Texture)座標等等...
現在我們可以利用這編輯器裡的Color屬性,自由的幫「朋友」變換顏色了。