Chapter3 Unity Shader 基礎
概述
在Unity需要材質(Material)與Unity Shader配合使用來達到滿意的效果。
- Unity Shader定義了渲染需要的各種代碼(頂點着色器與片元着色器等),屬性(使用哪些紋理)和指令(渲染和標簽設置),我們通過材質調節這些屬性,再賦給相應的模型。
- 材質:配合GameObject的Mesh或者Particle Systems組件來工作。
- Unity Shader:
- Standard Surface Shader:使用了一個包含了標准光照模型的表面着色器模板
- Unlit Shader: 一個不包含光照但是包含霧效的基本頂點/片元着色器
- Image Effect Shader: 為實現屏幕后處理提供基本模板
- Compute Shader: 借助GPU的並行性來進行一些與渲染流水線無關的計算
ShaderLab
一款專門為Unity Shader服務的語言。
Properties 屬性
- 語句格式:
Name("display name",PropertyType)=DefaultValue
- 支持的屬性類型:
| 屬性類型 | 定義語法 ||
|:--------😐:--------:||
|Int|number||
|Float|number|
|Range(min,max)|number|
|Color|(number,number,number,number)|
|Vector|(number,number,number,number)|
|2D|"defaulttexture"{}|
|Cube|"defaulttexture"{}|
|3D|"defaulttexture"{}|
Unity允許重載默認的材質編輯面板以提供更多的自定義數據類型。 關鍵詞“Custom Shader GUI”
Properties語義塊的作用僅僅是為了讓這些屬性可以出現在材質面板里
SubShader:表面着色器
- 語句格式
SubShader{
//可選的,標簽
[Tags]
//可選的,狀態
[RenderSetup]
//一次完整的渲染流程,如果pass的數目過多,會造成渲染性能的下降。
Pass{
}
...
}
-
RenderSetup 狀態:關於渲染狀態的設置指令
| 狀態名稱 | 設置指令 |解釋|
|:--------😐:--------😐:----😐
| Cull |Cull Back/Front/Off| 剔除模式:剔除背面/正面/關閉剔除|
|ZTest|ZTest Less Greater/LEqual/GEqual/Equal/NotEqual/Always|設置深度剔除時使用的函數|
|ZWrite|ZWrite On/Off|關閉/開啟深度寫入|
|Blend|Blend SrcFactor DstFactor|開啟並設置混合模式| -
Tags 標簽:希望怎樣以及何時渲染這個對象
Tags{"TagName1"="Value1" "TagName2"="Value2"}
| 標簽類型 | 說明 |
|--------|--------|
| Queue | 控制渲染順序,指定該物體屬於哪一個渲染隊列 |
|RenderType|對着色器進行分類,可以用於着色器替換功能|
|DisableBatching|指明是否對該SubShader使用批處理|
|ForceNoShadowCasting|控制使用該SubShader的物體是否會投射陰影|
|IgnoreProjector|控制使用該SubShader的物體是否受projector(投影儀?)的影響|
|CanUseSpriteAtlas|當該SubShader是用於sprite時,將該標簽設為“false”|
|PreviewType|指明材質面板將如何預覽該材質。默認材質下,材質將顯示為一個球形,我們可以通過將該標簽的值設為“Plane”“SkyBox”來改變預覽類型|
上述標簽可以在SubShader中聲明,而不可以在Pass塊中聲明,Pass塊有專屬於自己的標簽。 -
Pass語義塊:
Pass{ [Name] [Tag] [RenderSetup] // Other code }
-
Name “MyPassName”:定義該Pass的名稱,可以使用UsePass命令來直接使用其他unity shader中的Pass,例如:
UsePass "MyShader/MYPASSNAME"
,由於Unity 內部會將所有Pass 名稱轉換為大寫字母的表示,所以在使用UsePass的時候必須使用大寫形式的名字。 -
RenderSetup:我們可以對Pass設置渲染狀態,除上述狀態設置以外,我們還可以使用固定管線的着色器。
-
Tag:
|標簽類型|說明|例子|
|---|----|---|
|LightMode|定義該Pass在Unity渲染流水線中的角色|Tags{"LightMode"="ForwardBase"}|
|RequireOptions|用於制定當滿足某些條件的時候才渲染該Pass,它的值是一個由空格分割的字符串,目前支持的選項:SoftVegetation|Tags{"RequireOptions"="SoftVegetation"}| -
特殊的Pass:
-
UsePass:使用該指令復用其他UnityShader中的Pass。
-
GrabPass:負責抓取屏幕並將結果存儲在一張紋理之中,以用於后續的Pass 處理。
-
-
FallBack
如果上面所有的SubShader在這塊顯卡上都不能運行,那么就用這個最低級的Shader。
FallBack "name"
// 或者
FallBack Off
通過一個字符串通知引擎最低級的Shader是哪個,也可以關閉Fallback功能——如果上述的SubShader無法使用,那就不要管它了。
其他語義
- 拓展編輯界面:CustomEditor
- 對命令進行分組:CateGory
UnityShader的形式
ShaderLab語句塊:
Shader "Myshader"{
Properties{
// 所需的各種屬性
}
SubShader{
// 真正意義上的SubShdaer代碼會出現在這里
// 表面着色器(Surface Shader)
// 頂點/片元着色器(Vertex/Fragment Shader)
// 固定函數着色器(Fixed Function Shader)
}
SubShader{
// 與上一個Shader類似
}
}
表面着色器
當給Unity提供一個表面着色器的時候,它在背后依舊將其轉換為對應的頂點/片元着色器。意義在於Unity為我們處理了很多光照細節,使得我們無需再操心這些事情。
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"
}
表面着色器被定義在SubShader語義塊中的CGPROGRAM與ENDCG之間。之間的代碼使用Cg/HLSL語言編寫,它嵌套在ShaderLab語言中。
頂點/片元着色器
頂點/片元着色器的代碼需要定義在CGPROGRAM與ENDCG之間,而着色器是寫在Pass語義塊內,而非SubShader內,這樣做來定義每個Pass需要的Shader代碼,靈活性更高,同時控制渲染的實現細節。
Shader "Custom/Simple VertexFragment Shader"{
SubShader{
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
float4 vert(float4 v:POSITION):SV_POSITION{
return mul(UNITY_MATRIX_MVP,v);
}
fixed4 frag():SV_Target{
return fixed4(1.0,0.0,0.0,1.0);
}
ENDCG
}
}
}
固定函數着色器
上面兩種UnityShader形式都使用了可編程管線,而對於一些舊的設備不支持可編程管線着色器,此時需要使用固定函數着色器來完成渲染,這些着色器往往只可以完成一些非常簡單的效果。
Shader "Tutorial/Basic"{
Properties{
_Color("Main Color",color)=(1.0,5.0,5.1)
}
SubShader{
Pass{
Material{
Diffuse[_Color]
}
Lighting On
}
}
}
樂樂女神的一些建議:
- 除非有明確的需求必須要使用固定函數着色器,否則請使用可編程管線的着色器。
- 如果想和各種光源打交道,你可能更喜歡表面着色器,但需要小心它在移動平台的性能表現。
- 如果需要使用的光照數目非常少,使用頂點/片元着色器是一個更好的選擇。
- 如果有很多自定義的渲染效果,請選擇頂點/片元着色器。