【Unity Shader入門】Shader編程基礎:ShaderLab語法

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

前言

Unity Shader與Shader

Unity Shader != 真正的Shader

Unity Shader實際上是指的就是一個ShaderLab文件。以.Shader作爲後綴的一種文件。在Unity Shader裏面,我們可以做的事情遠多於一個傳統意義上的Shader。

Unity Shader優點

1.在傳統的Shader中,我們僅可以編寫特定類型的Shader,例如頂點着色器、片元着色器等。而在Unity Shader中,我們可以在同一個文件裏同時包含需要的頂點着色器和片元着色器代碼。
2.在傳統的Shader中,我們無法設置一些渲染設置,例如是否開啓混合、深度測試等,這些是開發者在另外的代碼中自行設置的。而在Unity Shader中,我們通過一行特定的指令就可以完成這些設置。
3.在傳統的Shader中,我們需要編寫冗長的代碼來設置着色器的輸入輸出,要小心地處理這些輸入輸出的位置對應關係等。而在Unity Shader中,我們只需要在特定語句塊中聲明一些屬性,就可以依靠材質來方便地改變這些屬性。而且對於模型自帶的數據(如頂點位置、紋理座標、法線等),Unity Shader也提供了直接訪問的方法,不需要開發者自行編碼來傳給着色器。

Unity Shader缺點

由於Unity Shader的高度封裝性,我們可以編寫的Shader類型和語法都被限制了。例如:Unity對曲面細分着色器、幾何着色器等的支持性就差一些。
可以說,Unity Shader提供了一種讓開發者同時控制渲染流水線中多個階段的方式,不僅僅是提供Shader代碼。作爲開發者而言,我們絕大部分時候只需要和Unity Shader打交道,而不需要關心渲染引擎底層的實現細節。

CG/HLSL與ShaderLab

Unity Shader是使用ShaderLab語言編寫的,但對於表面着色器和頂點/片元着色器,我們可以在ShaderLab內部嵌套CG/HLSL語言來編寫這些着色器代碼。CG/HLSL代碼是區別於ShaderLab的另一個世界。

從本質上講,Unity Shader只有兩種形式:頂點/片元着色器(Unity會把表面着色器轉化爲包含多Pass的頂點/片元着色器)和固定函數着色器(Unity5.2版本以後,固定函數着色器會被轉化成頂點/片元着色器,因此本質上說UnityShader只有頂點/片元着色器一種形式)。

ShaderLab

Unity Shader模板

Unity一共提供了4 種Unity Shader 模板供我們選擇——
Standard Surface Shader:包含了標準光照模型基於物理的渲染方法表面着色器模板 (PBR)
Unlit Shader:一個不包含光照(但包含霧效)的基本的頂點/片元着色器
Image Effect Shader: 實現各種屏幕後處理效果
Compute Shader:特殊Shader,利用GPU 的並行性來進行一些與常規渲染流水線無關的計算

Unity Shader Properties塊

Shader "Example" 
{ 
	//屬性塊:定義了一些屬性參數,可在Unity編輯器的“Inspector”面板中編輯和調整。
	Properties
	{ 
		//_MainTex是變量名 ("Texture"是在“Inspector”中的名字, 2D是變量類型) = "White" {}是默認值
		_MainTex("Texture",2D) = "White" {}

		// 整數:創建一個讓用戶填入整數的欄位
		_Int("Int",Int) = 2
		// 浮點數:創建一個讓用戶填入浮點數的欄位
		_Float("Float",float) = 1.5
		// 在(min,max)範圍內的浮點數:創建一個滑動條,可以讓用戶選擇在min和max之間的浮點數值
		_Range("Range",range(0.0,2.0)) = 1.0
		// 顏色 RGBA:創建一個調色板選擇器,可以讓用戶選擇顏色
		_Color("Color",color) = (1,1,1,1)
		// 四維向量:創建4個欄位,讓用戶可以填入相應的浮點數,代表一個Vecto4
		_Vector("Vector",Vector) = (1,2,3,4)
		// 創建一個圖片選擇框,可以讓用戶選擇貼圖
		_2D("Texture",2D) = "White" {
		// 矩形紋理:創建一個non-power-of-2貼圖選擇框,功能基本跟2D想同
		_Rect("Rect",Rect) = "White" {}
		// 立方體貼圖紋理:創建一個選擇Cubmap的框
		_Cube("Cube",Cube) = "White" {}
		// 3D紋理
		_3D("3D",3D) = "black" {}
	} 
	SubShader{ }
}

Unity Shader SubShader塊

一個Shader可以有多個子着色器(SubShader),這些子着色器互不干擾,且只有一個會運行,編寫多個子着色器的目的是爲了解決平臺兼容性問題,Unity會自己選擇兼容終端平臺的Shader運行。

Shader "Example" 
{ 
	Properties{ }
	// Unity加載Shader掃描所有SubShader塊,使用第一個能在目標平臺使用的SubShader塊,當所有SubShader都不支持目標平臺時會執行Fallback語義塊
	SubShader{ }
	Fallback Off // 當上面Shader運行不了的時候會使用下面的Fallback Shader渲染
}

Unity Shader Tags

Unity ShaderLab中,經常會看到各種Tag(標籤)。這裏大致分爲兩類Tag,SubShader Tag 和 Pass Tag。

裏面寫了走裏面,外面寫了走外面,如果裏外定義相同key使用外面的

Shader "Example" 
{ 
	Properties{ }
	SubShader
	{ 
		//標籤 可選 key = value
		Tags 
		{
			// 渲染順序:使用 Queue標籤,分別放入不同的渲染隊列中
			"Queue" = "Transparent"
			// 着色器替換功能
			"RenderType" = "Opaque"
			// 是否進行合批
			"DisableBatching" = "True"
			// 是否投射陰影
			"ForceNoShadowCasting" = "True"
			// 是否受Projector的影響,通常用於透明物體
			"IgnoreProjector" = "True"
			// 是否用於圖片的shader,通常用於UI
			"CanUseSpriteAltas" = "False"
			// 用作shader面板預覽的類型
			"PreviewType" = "Plane"
		}

		Pass
		{
			// 在pass通道中特有的Tag設置
			Tags 
			{
				// 定義該Pass通道在Unity渲染流水中的角色
				"LightMode" = "ForwardBase"
				// 當滿足某些條件時才渲染該Pass通道
				"RequireOptions" = "SoftVegetation"
			}
		}
	}
	Fallback Off
}

SubShader Tag

Rendering Order - Queue tag

在3D引擎中,我們經常要對透明和不透明物體進行排序。先渲染不透明再渲染透明物體,Unity使用 Queue標籤,分別放入不同的渲染隊列中。

Background:背景,一般天空盒之類的使用這個標籤,最早被渲染
Geometry(default):適用於大部分不透明的物體
AlphaTest:如果Shader要使用AlphaTest功能,使用這個隊列性能更高
Transparent:這個渲染隊列在AlphaTest之後,Shader中有用到Alpha Blend的,或者深入不寫入的都應該放在這個隊列。
Overlay:最後渲染的隊列,全屏幕後期的,都應該使用這個
this render queue is meant for overlay effects. Anything rendered last should go here (e.g. lens flares).

RenderType tag

RenderType tag可以用自定義的字符串,在使用ShadeReplacement,全局替換渲染的時候有用。

Opaque:用於大多數着色器(法線着色器、自發光着色器、反射着色器以及地形的着色器)。
Transparent:用於半透明着色器(透明着色器、粒子着色器、字體着色器、地形額外通道的着色器)。
TransparentCutout:蒙皮透明着色器(Transparent Cutout,兩個通道的植被着色器)。
Background:Skybox shaders. 天空盒着色器。
Overlay:GUITexture, Halo, Flare shaders. 光暈着色器、閃光着色器。
TreeOpaque:terrain engine tree bark. 地形引擎中的樹皮。
TreeTransparentCutout:terrain engine tree leaves. 地形引擎中的樹葉。
TreeBillboard:terrain engine billboarded trees. 地形引擎中的廣告牌樹。
Grass:terrain engine grass. 地形引擎中的草。
GrassBillboard:terrain engine billboarded grass. 地形引擎何中的廣告牌草。

DisableBatching tag

很多着色器中,如果使用的Batching技術,物體的模型空間中的位置信息都沒了。如果要設計的模型空間座標系的操作的Shader,就得禁用 Batching,保存模型空間的信息。 我們可以使用 "DisableBatching " = “True”,默認都是“False”

ForceNoShadowCasting tag

如果要替換一個半透明的物體的Shader,如果想要這個物體不需要產生陰影,就用這個。半透明物體渲染如果不需要陰影就加上標籤。

IgnoreProjector tag

Unity有種Projector投影效果,如果加上這個Tag,那麼就不會受到投影影響。(貼花,Projector陰影效果)

CanUseSpriteAtlas tag

如果着色器用於精靈,則將CanUseSpriteAtlas標記設置爲“ False”,並且在將它們打包到地圖集中時不起作用(請參見Sprite Packer)。

PreviewType tag

PreviewType 正常我們都是用一個球體預覽材質,設置標籤”Plane“ 或者 “Skybox”

Pass Tag

Pass Tag 一般控制燈光相關的信息,這些跟SubShader Tag一樣,只能在Pass塊裏面起效果。

LightMode tag

渲染路徑標籤, 一般現在渲染分爲了 三類,頂點渲染路徑,向前的渲染,對於的延遲渲染路徑。

Always:始終渲染,沒有照明
ForwardBase:在前向渲染中,應用了環境光、主方向光、頂點/SH光和光照貼圖(只受到環境光,主要(強度最大那個)的方向光,球協光照和lightMap影響)
ForwardAdd:用於正向渲染,應用每個像素的附加光,每個光通過一次。(如果燈光類型是 NO-IMPORT 或者其他類型光源 就會用到這個)
Deferred:延遲渲染的,渲染到Gbuffer
ShadowCaster:渲染物體深度到陰影貼圖或深度紋理。(生成陰影要用深度圖Shader)
MotionVectors: 渲染物體深度到陰影貼圖或深度紋理。用於計算每個物體的運動矢量。(計算物件移動向量)
PrepassBase:用於傳統的延遲照明,渲染正常和高光指數。
PrepassFinal:用於傳統的延遲照明,渲染最終顏色的紋理,照明和發射。
Vertex:當對象沒有光照映射時,在傳統頂點光照渲染中使用;所有頂點光照都被應用。
VertexLMRGBM:當對象被光照映射時,在傳統頂點光照渲染中使用;在lightMap編碼爲RGBM (PC和控制檯)的平臺上。
VertexLM:當對象被光照映射時,在傳統頂點光照渲染中使用;在lightMap是double-LDR編碼的平臺(移動平臺)上。

PassFlags tag

通過Pass可以指示更改渲染管道將數據傳遞給它的方式的標誌。 這是通過使用PassFlags標記完成的,該標記的值是用空格分隔標誌名稱。 當前支持的標誌是:

OnlyDirectional: 在ForwardBase傳遞類型中使用時,使用此標誌可以將僅主要定向光和環境/光照探針數據傳遞到着色器中。 這意味着不重要的光的數據不會傳遞到頂點光或球諧函數着色器變量中。 有關詳細信息,請參見正向渲染。

RequireOptions tag

通過Pass可以表明僅應在滿足某些外部條件時才進行渲染。 這是通過使用RequireOptions標記完成的,該標記的值是一串用空格分隔的選項。 當前,Unity支持的選項包括:

SoftVegetation:僅當Quality Settings中設置SoftVegetation處於啓用狀態時,才渲染此通道。

Unity Shader 渲染設置

Shader "Example" 
{ 
	Properties{ }
	SubShader
	{ 
		Tags { }
		
		// 渲染設置
		// 裁剪
		Cull off
		//深度測試 
		ZTest Always
		//深度寫入
		Zwrite of
		// 混合
		Blend SrcFactor DstFactor
		// 不同情況下使用不同的LOD達到性能提升
		Lod 100

		Pass
		{
			Tags { }
			// 渲染設置
		}
	}
	Fallback Off
}

Cull

Cull Back(默認):把圖片的背面剪裁,相當於背面不進行渲染
Cull Front:把圖片的正面剪裁,相當於正面不進行渲染
Cull Off:關閉剔除,正反面都渲染

ZWrite

ZWrite On(默認): 深度寫入開啓
ZWrite Off:深度寫入關閉
深度寫入開啓後決定片元的深度值是否寫入深度緩衝。不建議關閉深度寫入,除非有特殊需求,關閉深度寫入會有很多意想不到的現象產生。

ZTest

ZTest LEqual(默認):深度小於等於當前緩存則通過
ZTest GEqual:深度大於等於當前緩存則通過
ZTest Equal:深度等於當前緩存則通過
ZTest NotEqual:深度不等於當前緩存則通過
ZTest Less:深度小於當前緩存則通過
ZTest Greater:深度大於當前緩存則通過
ZTest Always:不論如何都通過
ZTest Off:效果跟ZTest Always一樣
這裏的緩存可以理解成,相機視角此時所保存的某一點的深度值,離相機越近,深度值越大。

Blend

ShaderLab提供了相應的Blend混合命令,用於指定後渲染產生的顏色如何與顏色緩存中的顏色進行混合。混合命令由Blend關鍵字,操作和因子組成,操作默認是加操作

Blend Off:關閉混合
Blend SrcFactor DstFactor:基本的配置並啓動混合操作。對產生的顏色乘以SrcFactor。對已存在於屏幕的顏色乘以DstFactor,並且兩者將被疊加在一起。
Blend SrcFactor DstFactor,SrcFactorA DstFactorA:同上,但是使用不同的要素來混合alpha通道,也就是有了4個操作對象

以下所有屬性都可以作爲SrcFactor或DstFactor。其中Source指的是被計算過的顏色,Destination是已經在屏幕上的顏色
One:值爲1,使用此因子來讓幀緩衝區源顏色或是目標顏色完全的通過
Zero:值爲0,使用此因子來刪除幀緩衝區源顏色或目標顏色的值。
SrcColor:使用此因子爲將當前值乘以幀緩衝區源顏色的值
SrcAlpha:使用此因子爲將當前值乘以幀緩衝區源顏色的Alpha的值
DstColor:使用此因子爲將當前值乘以幀緩衝區目標顏色的值。
DstAlpha:使用此因子爲將當前值乘以幀緩衝區目標顏色Alpha分量的值
OneMinusSrcColor:使用此因子爲將當前值乘以(1-幀緩衝區源顏色值)
OneMinusSrcAlpha:使用此因子爲將當前值乘以(1-幀緩衝區源顏色Alpha分量的值)
OneMinusDstColor:使用此因子爲將當前值乘以(1-目標顏色值)
OneMinusDstAlpha:使用此因子爲將當前值乘以(1-目標顏色Alpha分量的值)

Shader "Example" 
{ 
	Properties{ }
	SubShader
	{ 
		Tags { }
		
		//正常(Normal)
		Blend SrcAlpha OneMinusSrcAlpha
		//柔和相加(Soft Addtive)
		Blend OneMinusDstAlpha One
		//正片疊底(Multiply),即相乘
		Blend DstColor Zero
		//兩倍相乘(2x Multiply)
		Blend DstColor SrcColor
		//濾色(Screen)
		Blend OneMinusDstColor One
		//線性減淡(Linear Dodge)
		Blend One One

		Pass { }
	}
	Fallback Off
}

BlendOp
是混合操作,下面是一些常用的混合操作:

BlendOp Add(默認):將源顏色和目的顏色相加
BlendOp Sub:用源顏色減去目的顏色
BlendOp RevSub:用目的顏色減去源顏色
BlendOp Min:取源顏色和目的顏色中的較小值,是逐分量比較
BlendOp Max:取源顏色和目的顏色中的較大值,是逐分量比較
BlendOp LogicalClear:全部賦值爲0,就是透明
BlendOp LogicalSet:全部賦值爲1,就是黑色
BlendOp LogicalCopy:複製原顏色的值,相當於前面的Blend One Zero
BlendOp LogicalCopyInverted:把源顏色的值按位取反後渲染
BlendOp LogicalNoop:渲染目的顏色中的像素,相當於前面的Blend Zero One
BlendOp LogicalInvert:把目的顏色中的值按位取反後渲染
BlendOp LogicalAnd:源顏色 & 目的顏色
BlendOp LogicalNand:! (源顏色 & 目的顏色)
BlendOp LogicalOr:源顏色 | 目的顏色
BlendOp LogicalNor:! (源顏色 | 目的顏色)
BlendOp LogicalXor:源顏色 ^ 目的顏色
BlendOp LogicalEquiv:! ( 源顏色 ^ 目的顏色)
BlendOp LogicalAndReverse:源顏色 & !目的顏色
BlendOp LogicalAndInverted:!源顏色 & 目的顏色
BlendOp LogicalOrReverse:源顏色 | !目的顏色
BlendOp LogicalOrInverted:!源顏色 | 目的顏色

Shader "Example" 
{ 
	Properties{ }
	SubShader
	{ 
		Tags { }
		
		//變暗(Darken)
		BlendOp Min
		Blend One One
		//變亮(Lighten)
		BlendOp Max
		Blend One One

		Pass { }
	}
	Fallback Off
}

LOD

Shader Level of Detail (LOD),翻譯過來是什麼“着色器的細節層次效果”。Shader LOD其實就是根據設備性能的不同編譯不同版本的Shader。這個是另外一種控制細節級別的技術,在一個Shader當中,可以給不同的SubShader指定不同的LOD屬性。

根據這個特性,我們就可以在一個Shader裏寫一出組SubShader,分別設置不同的LOD,LOD越大的對應性能越好,越低的性能越差。然後我們就可以用設置LOD的方法來控制遊戲畫面的渲染質量。

Shader "Example" 
{ 
	Properties{ }
    SubShader
    {
        Tags{ }
        LOD 100
    }
    SubShader
    {
        Tags{ }
        LOD 200
    }
	Fallback Off
}

在Edit->Project Setting->QualitySettings中的Maximum LOD Level可以設置最大LOD等級,Shader的LOD值是小於所設定的LOD值,纔會被編譯使用。Maximum LOD Level的等級可以設置7個級別,例如設置爲1,則表示把最大LOD值設置爲100,等級2,則最大LOD值爲200,以此類推,若設置爲0,則表示不進行LOD判斷,任何LOD值的Shader都會被使用。

SubShader語義塊Pass

一個Pass就是一次繪製,可以看成一個DC(Draw Call),對於表面着色器而言,只有一個Pass,但是頂點片元着色器可以有多個Pass,多個Pass可以實現一些特殊效果。Pass的意義在於多次渲染,如果你有一個Pass,那麼着色器只會被調用一次,如果你有多個Pass的話,那麼就相當於執行多次SubShader了,這就叫雙通道或者多通道。在編寫Shader的時候,Pass要儘量的少,每多一個Pass,那麼DC就會多一次!而且我們可以在一個Shader中使用另一個Shader的某一個Pass塊,Pass塊是可以命名的,使用use "passname"這樣的方式可調用,具體方式

Pass { [Name and Tags] [RenderSetup] [TextureSetup] }
Name and tags:一個Pass 可以定義它的名字和任意數量的標籤-name/value 字符串 將Pass的含義告訴給渲染引擎。
Render Setup 渲染設置: Pass設置了一系列的顯卡狀態,比如說alpha混合是否開啓,是否允許霧化等等。
Texture Setup 紋理設置:當渲染狀態設置以後,你可以用SetTexture命令指定這些紋理和他們的結合方式。


Shader "Example" 
{ 
	Properties{ }
    SubShader
    {
        Tags{ }
        // 渲染設置

		Pass 
		{
			// Pass通道名稱,可以當成一個函數進行使用,使用時需要全名稱大小調用
			Name "name"
			// Pass標籤
		    Tags{ }
	        // Render Setup 渲染設置
	        // Texture Setup 紋理設置
			
			// CG語言所寫的代碼,主要是頂點/片元着色器
			CGPROGRAM// 插入Cg代碼開始

			ENDCG // 插入Cg代碼結束
		}
    }
	Fallback Off
}

SurfaceShader

Fallback

回滾,相當於備胎。

SIKI學院 Unity Shader入門(Unity2018.3)
UnityShader 基礎知識
Unity Shader (一)ShaderLab 語法
Unity Shader 中各種Tag
UnityShader與Shader的區別
UnityShader RenderType

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