第一章 創建一個shader

                                        創建一個shader


什麼是Shader

Shader(着色器)是一段能夠針對3D對象進行操作、並被GPU所執行的程序。Shader並不是一個統一的標準,不同的圖形接口的Shader並不相同。OpenGL的着色語言是GLSLNVidia開發了Cg,而微軟的Direct3D使用高級着色器語言(HLSL)。而Unity的Shader 是將傳統的圖形接口的Shader(由 Cg / HLSL編寫)嵌入到獨有的描述性結構中而形成的一種代碼生成框架,最終會自動生成各硬件平臺自己的Shader,從而實現跨平臺。

Unity Shader 其實並不難,初學者往往很迷惑是因爲它有太多固定的命令和結構,而這些命令又需要我們對3D渲染有一定的瞭解才能知道它們是做什麼的。


Shader種類

OpenGL和Direct3D都提供了三類着色器:

  •     頂點着色器:處理每個頂點,將頂點的空間位置投影在屏幕上,即計算頂點的二維座標。同時,它也負責頂點的深度緩衝(Z-Buffer)的計算。頂點着色器可以掌控頂點的位置、顏色和紋理座標等屬性,但無法生成新的頂點。頂點着色器的輸出傳遞到流水線的下一步。如果有之後定義了幾何着色器,則幾何着色器會處理頂點着色器的輸出數據,否則,光柵化器繼續流水線任務。
  •     像素着色器(Direct3D),常常又稱爲片斷着色器(OpenGL):處理來自光柵化器的數據。光柵化器已經將多邊形填滿並通過流水線傳送至像素着色器,後者逐像素計算顏色。像素着色器常用來處理場景光照和與之相關的效果,如凸凹紋理映射和調色。名稱片斷着色器似乎更爲準確,因爲對於着色器的調用和屏幕上像素的顯示並非一一對應。舉個例子,對於一個像素,片斷着色器可能會被調用若干次來決定它最終的顏色,那些被遮擋的物體也會被計算,直到最後的深度緩衝纔將各物體前後排序。
  •     幾何着色器:可以從多邊形網格中增刪頂點。它能夠執行對CPU來說過於繁重的生成幾何結構和增加模型細節的工作。Direct3D版本10增加了支持幾何着色器的API, 成爲Shader Model 4.0的組成部分。OpenGL只可通過它的一個插件來使用幾何着色器。

 

Unity Shader 分爲 表面着色器(Surface Shader)和 頂點片段着色器(Vertex And Fragment Shader)

  •     表面着色器(Surface Shader)是Unity提出的一個概念。編寫着色器與光照的交互是複雜的,光源有很多類型,不同的陰影選項,不同的渲染路徑(正向和延時渲染),表面着色器將這一部分簡化。Unity建議使用表面着色器來編寫和光照有關的Shader。
  •     頂點片段着色器(Vertex And Fragment Shader)和OpenGL,Direct3D中的頂點着色器和片段着色器沒有什麼區別。頂點片段着色器比表面着色器使用更自由也更強大,當然光照需要自行處理。Unity也允許在裏面編寫幾何着色器,一般用得不多。

 

Unity Sahder的模板 類型

 

模板名 功能
Standard Surface Shader 包含標準光照模型的表面着色器模板。
Unlit Shader 產生一個不包含光照(但包含霧效)的基本的頂點/片元着色器。
ImageEffect Shader 實現各種屏幕後處理效果的基本模版。
Compute Shader 特殊的Shader,利用GPU的並行性來進行一些與常規渲染流水線無關的計算。

 

 

Unity Shader 結構

// 着色器名稱
Shader "ShaderName" {
	// 屬性 
	Properties {
		Name ("display name", PrpertyType) = DefaultValue
	}
	// 子着色器
	SubShader {
		// 可選的,標籤(告訴Unity如何、何時渲染對象)
		[Tags]
		
		// 可選的,狀態設置(開關混合、深度測試,剔除模式,設置深度測試使用函數)
		[RenderSetup]
		
		// 完整渲染流程
		Pass {
			[Name]
			[Tags]
			[RanderSetup]
		}
	}
	//SubShader不能運行時執行(同時渲染陰影)
	Fallback "VertexLit"  
}

 

●  Properties

  • 屬性: 不一定要在Properties語義塊中聲明,也可以在Cg中定義變量(可通過腳本向Shader傳遞)。
  • 作用: 只是爲了讓這些屬性顯示在材質面板中。
  • 定義 Name ("display name", PrpertyType) = DefaultValue

   

  • Name:名字。在Shader中訪問該變量時,要聲明這個名字。
  • display name:顯示的名字。即面板顯示的標籤名字。
  • PropertyType:屬性類型。
  • DefaultValue:默認值。
Properties {
	// Numbers and Sliders
	_Int ("Int", Int) = 2
	_Float ("Float", Float) = 1.5
	_Range("Range", Range(0.0, 5.0)) = 3.0
	// Colors and Vectors
	_Color ("Color", Color) = (1,1,1,1)
	_Vector ("Vector", Vector) = (2, 3, 6, 1)
	// Textures
	_2D ("2D", 2D) = "" {}
	_Cube ("Cube", Cube) = "white" {}
	_3D ("3D", 3D) = "black" {}
}

//對於 SubShader 數據類型
************************************************************************************
Range  Color  2D  Rect  Cube  Float  Vector
************************************************************************************

// Color , Vector 對於的數據類型:  float4   half4   fixed4
// Range , Float  對於的數據類型:  float    half    fixed
// 2D             對於的數據類型:  sampler2D
// 3D             對於的數據類型:  sampler3D
// Cube           對於的數據類型:  samplerCube

 

 

●  SubShader

子着色器 : 每一個Unity Shader文件可以包含多個SubShader語義塊,但最少要有一個。Unity會掃描所有SubShader語義塊,然後選擇第一個能夠在目標平臺上運行的,如果都不支持,則會使用Fallback指定的Shader。
定義:

  • Tags:標籤,可選。
  • RenderSetup:狀態,可選。
  • Pass:一次完整的渲染流程。可以在裏面聲明標籤和狀態。

 

●  RenderSetup  

設置顯卡的各種狀態。如果需要應用到所有Pass塊中,則在SubShader中設置。否則如雙面渲染,第一個Pass剔除正面(Cull Front)來渲染背面,第二個Pass剔除背面(Cull Back)來渲染正面。

狀態名稱 參數 含義
Cull Cull   Back | Front | Off 剔除模式: 剔除背面 |  剔除正面 | 關閉剔除
ZTest ZTest  Less Greater | LEqual | GEqual | Equal | NotEqual | Always 設置深度測試 使用的函數
ZWrite ZWrite On | Off 開啓 關閉 深度寫入
Blend Blend SrcFactor  DstFactor 混合模式

 

 ●   Tags

是鍵值對,都爲字符串類型。用於告訴Unity:SubShader要怎麼樣以及合適渲染這個對象。
結構:Tags { "TagName1" = "Value1" "TagName2" = "Value2" }

注意:下面這些標籤都只可以在SubShafer中聲明,不可以在Pass塊中聲明。

 

標籤類型 說明 例子
Queue 控制渲染順序, 指定該物體屬於哪一個渲染列隊; 通過這種方式 可以保證所有的透明物體 可以在所有不透明 物體後面被渲染。 我們也可以自定義 使用渲染列隊來 控制 物體的渲染順序 Tags { "Queue" ="Transparent"}
RenderType 對着色器 進行分類, 例如 這是一個 不透明的 着色器, 或者是一個 透明的着色器; 這可以被用於 着色器替換的功能 Tags { "RenderType"="Opaque" }
DisableBatching 一些 SubShader 使用 Unity 的 批處理功能是 會出問題; 有時候可以 手動關閉 Tags {"DisableBatching" = "True" }
ForceNoShadowCasting 是否投射陰影 Tags { "ForceNoShadowCasting"="True" }
IgnoreProjecter 如果爲 True, 那麼將不會受到 Projecter 的影響,通過用於半透明 Tags { "IgnoreProjecter"="True" }
CanUseSpriteAtlas 該 Shader 是否用於精靈 圖集 Tags { "CanUserSpriteAtlas"="True" }
PreviewType 指定 材質球的 預覽形狀 Tags { "PreviewType"="Plane"  }

 

 

 ●  Pass語義塊

Pass {
	[Name]			// 如 Name "MyPassName"
	[Tags]
	[RenderSetup]
	// Other code
}
  • Name:名稱。
  • RenderSetup:同SubShader,還可以使用固定管線的着色器命令。
  • Tags:不同與Subshader的標籤。

其他標籤:

  • UsePass:直接使用別的Shader的Pass塊。在使用時必須使用大寫形式如:UsePass "MyShader/MYPASSNAME"
  • GrabPass:抓取屏幕,並將結果存儲到一張紋理中,用於後序的Pass處理。

 


 

 

 

 

Unity Sahder的形式:

 

 ● 表面着色器(Surface Shader)

這是 Unity自己創造的一種着色器代碼類型,在背後會轉換成對應的頂點/片元着色器相當於再對頂點/片元着色器的抽象。定義在 CGPROGRAM ENDCG 之間,而不是在Pass中。

 

#pragma surface surf Lambert	//  使用surf函數作爲表面着色器,用Lambert光照模型
struct Input {
	float4 color : COLOR;
};
void surf (Input IN, inout SurfaceOutput o){
	o.Albedo = 1;
}

 

表面着色器:

Surface Shader示例:
Shader "Custom/Simple Surface Shader"
{
	SubShader {
		Tags{"RenderType"="Opaque"}
 
		CGPROGRAM
		#pragma surface surf Lambert
		struct Input
		{
			float4 color:COLOR;
		};
		void surf (Input IN,inout SurfaceOutput o)
		{
			o.Albedo=1;
		}
		ENDCG
	}
	FallBack "Diffuse"
}

 

●  頂點/片元着色器(Vertex/Fragment Shader)

相比表面着色器更復雜,但更靈活。可以控制渲染的實現細節。同樣定義在 CGPROGRAM ENDCG之間。

 

#pragma vertex vert			// 使用vert函數作爲頂點着色器
#pragma fragment frag			// 使用frag函數作爲片元着色器

 

 定點片元着色器:

SubShader{
	Pass
	{
		CGPROGRAM
		#pragma vertex vert
		#pragma fragment frag
		
		float4 vert(float4 v : POSITION):SV_POSITION
		{
			return mul (UNITY_MATRIX_MVE,V);
		}
 
		fixed4 frag():SV_Target
		{
			return fixed4 (1.0,0.0,0.0,1.0);
		}
		ENDCG
	}
}

●  固定函數着色器(Fixed Function Shader)

以上兩種都是可編程管線,而對於一些舊設備,就不支持了,這時就要用固定函數着色器完成渲染,也只能完成一些簡單的效果。定義在Pass塊中。

Pass {
	Material {
		Diffuse [_Color]
	}
	Lighting On
}

 

固定管線色器:

Shader "Tutorial/Basic"
{
	Properties
	{
		_Color("Main Color",Color)=(1,0.5,0.5,1)
	}
	SubShader
	{
		Pass
		{
			Material
			{
				Diffuse[_Color]
			}
			Lighting On
		}
	}
}

 

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