【Unity Shader入門】Shader編程初級:Shader結構

【Unity Shader入門】Shader基礎概念:渲染流水線
【Unity Shader入門】Shader編程基礎:ShaderLab語法
【Unity Shader入門】Shader數學基礎:向量(矢量)
【Unity Shader入門】Shader數學基礎:矩陣
【Unity Shader入門】Shader數學基礎:矩陣變換
【Unity Shader入門】Shader編程初級:Shader結構

準備工具

Unity 2017.1.1f1:用於執行Shader顯示渲染效果
Visual Studio 2019:用於Unity代碼編輯工具,此處用於編寫Shader腳本
ShaderlabVS:Shader語法高亮代碼補全Visual Studio插件

Shader結構

最簡單的Shader

Unity Shader(ShaderLab)語法有對整個Shader腳本Properties和SubShader等語義塊進行詳細的介紹。

#pragma vertex vert     // 頂點着色器函數名稱
#pragma fragment frag   // 片元着色器函數名稱

它們告訴Unity,哪個函數包含頂點着色器的代碼,哪個函數包含了片元着色器的代碼。

//mul(UNITY_MATRIX_MVP,v);
UnityObjectToClipPos(v);

UnityObjectToClipPos這個是把頂點從模型空間直接轉化到裁剪空間,也就是進行了M-V-P三次轉化,這個函數是回unity重新封裝過一次,其實它最初是mul(UNITY_MATRIX_MVP,v);其中,UNITY_MATRIX_MVP是轉化矩陣。

Shader "Example" 
{ 
	Properties
	{
		_MainTex("Texture",2D) = "White" {}
	}
    SubShader
    {
        Tags
        { 
			"RenderType" = "Opaque"
        }
        LOD 100

		Pass 
		{
			CGPROGRAM
			#pragma vertex vert     // 頂點着色器函數名稱
			#pragma fragment frag   // 片元着色器函數名稱

			float4 vert(float4 v:POSITION):SV_POSITION
			{
				// mul(UNITY_MATRIX_MVP,v);
				return UnityObjectToClipPos(v);
			}
			
			fixed4 frag():SV_TARGET
			{
				return fixed4(1,1,1,1);
			}
			ENDCG
		}
    }
	Fallback Off
}

輸入結構體

聲明瞭一個新的結構體a2v,它包含立頂點着色器需要的模型數據。它包含了頂點着色器需要的模型數據。a表示應用(application),v表示頂點着色器(vertex shadr),a2v的意思就是把數據從應用階段傳遞到頂點着色器中。

Struct a2v
{
	float4 vertex:POSITION;            // 用模型頂點填充vertex變量
	Float3 normal:NORMAL;              // 用模型的法線填充normal變量
	Float4 texcoord:TEXCOORD0;         // 用模型的第一套UV填充texcoord
};	

模型數據從哪裏來:在Unity中,他們是由使用該材質的Mesh Render組件提供的。在每幀調用Draw Call的時候,Mesh Render組件會把他負責渲染的模型數據發送給Unity Shader。我們知道,一個模型通常包含了一組三角面片,每個三角面片由3個頂點構成,而每個頂點又包含了一些數據,例如頂點位置、法線、切線、紋理座標、頂點顏色等。通過上面的方法,我們就可以在頂點着色器中訪問頂點的這些數據模型。

CGPROGRAM
#pragma vertex vert     // 頂點着色器函數名稱
#pragma fragment frag   // 片元着色器函數名稱

Struct a2v
{
	float4 vertex:POSITION;            // 用模型頂點填充vertex變量
	Float3 normal:NORMAL;              // 用模型的法線填充normal變量
	Float4 texcoord:TEXCOORD0;         // 用模型的第一套UV填充texcoord
};			

float4 vert(a2v v):SV_POSITION
{
	return UnityObjectToClipPos(v.vertex);
}
			
fixed4 frag():SV_TARGET
{
	return fixed4(1,1,1,1);
}
ENDCG

在實踐中,我們往往希望從頂點着色器輸出一些數據,例如把模型的法線、紋理座標等傳遞給片元着色器。這就涉及頂點着色器和片元着色器之間的通信。

輸出結構體

頂點着色器和片元着色器之間如何通信:我們聲明瞭一個新的結構體v2f。v2f用於在頂點着色器和片元着色器之間傳遞消息。同樣,v2f中也需要指定每個變量的語義。

Struct v2f
{
	//SV_POSITION語義告訴unity:pos爲裁剪空間中的位置信息
	float4 pos:SV_POSITION;
	// COLOR0語義可以存儲顏色信息
	fixed3 color:COLOR0;
};	

在本例中,我們使用了SV_POSITION和COLOR0語義。頂點着色器的輸出結構中必須包含一個變量,他的語義是SV_POSITION。否則,渲染器將無法得到裁剪空間中的頂點座標,也就無法把頂點渲染到屏幕上。COLOR0語義中的數據在可以由用戶自定義,但一般都是存儲顏色,例如逐頂點的漫反射顏色或逐頂點的高光反射顏色。類似的語義還有COLOR1等。

#pragma vertex vert     //頂點着色器函數名稱
#pragma fragment frag   //片元着色器函數名稱

Struct a2v
{
	// 用模型頂點填充vertex變量
	float4 vertex:POSITION;         
	// 用模型的法線填充normal變量   
	float3 normal:NORMAL;    
	//用模型的第一套UV填充texcoord          
	float4 texcoord:TEXCOORD0;    
};			

Struct v2f
{
	//SV_POSITION語義告訴unity:pos爲裁剪空間中的位置信息
	float4 pos:SV_POSITION;
	// COLOR0語義可以存儲顏色信息
	fixed3 color:COLOR0;
};

v2f vert(a2v v)
{
	v2f o;
	o.pos = UnityObjectToClipPos(v.vertex);
	// 將[-1,1]轉變爲[0,1]常用寫法
	o.color = v.normal * 0.5 + fixed3(0.5,0.5,0.5);
	return o;
}
			
fixed4 frag(v2f i):SV_TARGET
{
	return fixed4(i.color,1);
}
ENDCG

至此,我們就完成了頂點着色器和片元着色器之間的通信。需要注意的是,頂點着色器是逐頂調用的,而片元着色器是逐片元調用的。片元着色器中的輸入實際上是把頂點着色器的輸出進行差值後得到的結果。

屬性控制

聲明瞭一個屬性_Color,它的類型是Color,初始值是(1.0,1.0,1.0,1.0),對應白色。

Properties
{
	_Color("Color",Color) = (1,1,1,1)
}

爲了在CG代碼中可以訪問他,我們還需要在CG代碼片段中提前定義一個新的變量,這個變量的名稱和類型必須與Properties語義塊中的屬性定義相匹配。

Shader "Example" 
{ 
	Properties
	{
		_MainTex("Texture",2D) = "White" {}
		_Color("Color",Color) = (1,1,1,1)
	}
    SubShader
    {
        Tags
        { 
			"RenderType" = "Opaque"
        }
        LOD 100

		Pass 
		{
			CGPROGRAM
			#pragma vertex vert     // 頂點着色器函數名稱
			#pragma fragment frag   // 片元着色器函數名稱
			
			//只有在CGPROGRAM內再次定義一個與屬性塊內名字類型相同的變量,屬性塊對應的變量才能起作用
			fixed4 _Color;

			V2f vert(a2v v)
			{
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				// 將[-1,1]轉變爲[0,1]常用寫法
				o.color = v.normal * 0.5 + fixed3(0.5,0.5,0.5);
				return o;
			}
			
			fixed4 frag(v2f i):SV_TARGET
			{
				fixed3 c = i.color;
				// fixed4 .xyzw .rgba   //fixed .x .y fixed2 .xw 
				c *= _Color.rgb;
				return fixed4(c,1);
			}
			ENDCG
		}
    }
	Fallback Off
}

Unity提供的內置文件和變量

Unity提供的CG/HLSL語義

頂點着色器輸入結構體中常用語義

POSITION:模型空間中的頂點位置,通常是float4類型
NORMAL:頂點法線,通常是float3類型
TANGENT:頂點切線,通常是float4類型
TEXCOORDn:該頂點的紋理座標,TEXCOORD0表示第一組座標紋理,依次類推,通常是float2,float4類型
COLOR:頂點顏色,通常是fixed4或float4類型

Shader Model版本不同,TEXCOORDn中N的支持個數也不盡相同

Shader Model2:8
Shader Model3:8
Shader Model4:16
Shader Model5:16

頂點着色器輸出結構體中常用語義

SV_POSITION:裁剪空間中的頂點座標,結構體中必須包含一個用該語義修飾的變量。等同於DX9中的POSITION。
COLOR0:通常用於輸出第一組頂點顏色,不是必須
COLOR1:通常用於輸出第二組頂點顏色,不是必須
TEXCOORD0-TEXCOORD7:通常用於輸出紋理座標,不是必須

片元着色器輸出時常用語義

SV_Target:輸出值將會儲存到渲染目標(render target)中。等同於DX9中COLOR語義。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章