Unity Shader 入門 之二 簡單的純色着色器

本篇介紹創建一個最簡單的純色着色器,麻雀雖小五臟俱全。

在unity裏創建一個BaseColor.shader文件,使用編輯器填入下列代碼。所有代碼說明見註釋


Shader "ShaderTutorial/BaseColor" // Shader在面板上顯示的名稱
{
	/*
	    材質面板屬性
	*/
	Properties
	{
	     /* 
		 材質面板屬性定義,格式:變量名("<顯示變量名>",變量類型)=<缺省變量值>
		 */
		 _BaseColor("BaseColor",Color) = (1,1,1,1) 
		 
	}

	/*
	    子着色器
	*/
	SubShader
	{
		Tags { "RenderType" = "Opaque" } // 標籤,這裏"RenderType"標明渲染物體類型爲"Opaque",非透明物體
		LOD 100 // shader LOD(level of detail ) ,可以通過這個對畫質進行分檔

		Pass
		{
			
			CGPROGRAM // CG 代碼段的開始標誌
			#pragma vertex vert // 預編譯指令,指示頂點着色器(vertex)使用名稱爲vert的函數
			#pragma fragment frag // 預編譯指令,告訴編譯器,片元着色器(frament)使用名稱爲frag的函數

			#include "UnityCG.cginc" // 預編譯指令,引用文件"UnityCG.cginc",這裏包含一些預定義的一些變量和函數


            /* 
			變量聲明,前面Properties中定義的,暴露給編輯器材質面板的變量,
			必須在這裏再次聲明,因爲這裏纔是真正的變量聲明位置
			*/
			half4 _BaseColor; 
			

			/* 
				結構體,這個結構體是頂點着色器的輸入數據,
                是從應用階段(cpu)傳輸給頂點處理階段(gpu)的頂點屬性,
                因此這裏命名爲appdata,其他任意名稱也ok
			*/
            struct appdata
            {
                /*
                這裏變量聲明後加的":POSITION",是語義說明,
                用來告訴GPU,頂點的座標放在positionOS這個變量裏。
                */
                float4 positionOS : POSITION;
            };

			/* 
				結構體,這個結構體是頂點着色器的輸出以及片元着色器的輸入,因此命名爲v2f(vector to fragment ),其他任意名稱也ok
			*/
            struct v2f
            {
                float4 positionCS : SV_POSITION;  // 這裏的語義說明":SV_POSITION",是告訴GPU,把光柵化階段之後的裁剪空間頂點座標放在positionCS這個變量裏。
            };

			/*
				頂點着色器函數,每個模型頂點需要調用一次該頂點着色器, 以appdata作爲輸入,v2f作爲輸出
			*/
            v2f vert (appdata v)
            {
                v2f o;

				/* 
				使用UnityCG.cginc中定義的函數,UnityObjectToClipPos(),
				把模型空間的頂點座標轉換到裁剪空間
				*/
                o.positionCS = UnityObjectToClipPos(v.positionOS); 
				/*
				上述函數的實現如下,
				實際上就是把頂點座標先從模型空間轉換到世界空間(乘以模型空間到世界空間的變換矩陣-unity_ObjectToWorld),
				然後從世界空間轉換到齊次裁剪空間(世界空間座標,乘以觀察投影矩陣-UNITY_MATRIX_VP)。
				
				這裏需要注意的是,
				很多教程中會告訴你使用UNITY_MATRIX_MVP矩陣直接乘以模型空間座標,
				這種方式雖然結果上是正確的,
				但是因爲UNITY_MATRIX_MPV矩陣實際上是UNITY_MATIRX_VP和unity_ObjectToWrold相乘的預編譯指令,
				因此直接使用MVP矩陣會導致運算爲4x4矩陣與4x4矩陣的相乘結果再乘以四維向量,
				運算次數遠多於4x4矩陣乘以兩次四維向量。

				因此建議使用unity內置的UnityObjectToClipPos方法或者下面的實現,進行空間變換,可以得到更好的性能
				
				o.positionCS = mul(UNITY_MATRIX_VP, mul(unity_ObjectToWorld, float4(v.positionOS.xyz, 1.0)));

				*/
                return o;
            }
			/* 
				片元着色器函數,以v2f作爲輸入,這裏v2f,是經過光柵化之後的插值過的v2f。
				每一個片元(類似於屏幕像素,只是此時還沒有輸送給屏幕顏色緩衝)都需要執行一次片元着色器
			*/
            half4 frag (v2f i) : SV_Target 
            {
				/* 
                "SV_Target"同樣是語義說明,用來標記返回類型half4,
                說明這裏返回結果保存到SV_Target0(這裏0省掉了),
                指向的顏色緩衝區的對應位置
                */

				/* 
                這裏的返回值使用了half4,而不是常見的fixed4格式,
                因爲目前的幾乎所有顯卡都不再支持fixed4類型格式,
                而編譯器會內部把fixed 類型 轉爲 half 類型。
                
                但是除非你非常瞭解unity shader編譯器在目標平臺的編譯結果,
                建議使用half4代替fixed4類型。
                */

				half4 col = _BaseColor.rgba; 
                /* 
                把我們定義的變量類型_BaseColor賦值給col,並返回。
                這裏".rgba"的寫法或者".xyzw"是CG或者HLSL語言對向量的特有操作,
                表示把向量的指定分量(例如 .r .xy .xx .a 等 賦值給對應變量)
                */
                return col;
            }
            ENDCG // CG代碼段的結束標誌
        }
    }
}

這個着色器在Unity內的預覽如下:

在這裏插入圖片描述

可以看到

  • 顏色來源於我們定義的變量_BaseColor(顯示名稱爲BaseColor)。
  • 渲染隊列Render Queue 默認來自於我們定義的Tags “RenderType” =“Opaque”,事實上這裏可以直接定義Tag “RenderQueue”,這會在之後的文章說明
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章