一、概述
在Unity中需要配合使用材質和Unity Shader才能達到需要的效果。常見的流程:(1)創建一個材質;(2)創建一個Unity Shader,並把它賦給創建的材質;(3)把材質賦給要渲染的對象;(4)在材質面板中調整Unity Shader的屬性,以得到滿意的效果。
二、Unity中的材質
Unity中的材質需要結合一個GameObject的Mesh或者Particle Systems組件來工作。它決定了我們的游戲對象看起來是什么樣子的。
三、Unity中的Shader
Unity提供了四種Unity Shader模板:
1、Standard Surface Shader:產生一個包含了標准光照模型的表面着色器。
2、Unlit Shader:產生一個不包含光照(但包含霧效)的基本的頂點/片元着色器。
3、Image Effect Shader:為實現各種屏幕后處理效果提供基本模板。
4、Compute Shader:產生一種特殊的Shader文件,旨在利用GPU的並行性進行一些與常規渲染流水線無關的計算。
Shader文件說明:
、
Default Maps指定該Shader使用的默認紋理,當任何材質第一次使用該Shader時,這些紋理就自動被賦予到相應的屬性上。
Surface shader和Fixed function用於表明該shader是一個表面着色器還是固定函數着色器,如果是某個着色器,在對應的位置就有Show generated code按鈕,單擊該按鈕打開一個新的文件,該文件里將顯示Unity在背后為該表面着色器生成的頂點/片元着色器。這可以方便我們對這些生成的代碼進行修改(需要復制到一個新的Unity Shader中才可保存)和研究。
Cast shadows(是否會投射陰影)、Render queue(渲染隊列)、LOD(LOD值)等,和我們在Shader中的標簽設置有關。
Compile and show code下拉列表用於檢查該Shader針對不同圖像編程接口(例如OpenGL、D3D9等)最終編譯成的Shader代碼。
除此之外,面板還可以查看其是否關閉批處理(Disable batching)、屬性列表(Properties)等信息。
四、Unity Shader的結構
基礎結構:
Shader "ShaderName"{ Properties{ //屬性 } SubShader{ //顯卡A使用的子着色器 } SubShader{ //顯卡B使用的子着色器 } Fallback "VertexLit" }
(1)Shader文件的第一行通過Shader語義指定該Shader的名字,由一個字符串來定義。通過在字符串中添加“/”,可以控制Shader在材質面板中出現的位置。例如:
Shader "Custom/MyShader"{ }
該Shader在材質面板中的位置就是:Shader->Custom->MyShader。
(2)Properties語義塊包含了一系列屬性,這些屬性將會顯示在材質面板中。
Properties { Name ("display name", PropertyType) = DefaultValue Name ("display name", PropertyType) = DefaultValue //更多屬性 }
指定名字(Name)可以讓我們在Shader中訪問它們。
顯示的名字(display name)是出現在材質面板上的名字。
類型(Property Type)是每個值的類型。
默認值(DefaultValue)是為每個屬性指定的默認值,當第一次把該Shader賦給某個材質時,面板上顯示的就是這些值。
下面給出展示所有屬性類型的例子:
Shader "Custom/ShaderLabProperties" { 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" {} } FallBack "Diffuse" }
對於Int、Float、Range這些數字類型的屬性,其默認值就是一個單獨的數字;
對於Color和Vector這類屬性,默認值就是用圓括號包圍的一個四維向量;
對於2D、Cube、3D這類屬性,默認值通過一個字符串后跟一個花括號來指定。其中,字符串要么是空的,要么是內置的紋理名稱,花括號的作用原本是用於指定一些紋理屬性,但在Unity5.0之后便取消了,如果需要類似功能,就需要自己在頂點着色器中編寫計算相應紋理坐標的代碼。
如果想要在材質面板上顯示更多類型的變量,Unity允許重載默認的材質編輯面板,以提供更多自定義的數據類型。
參考: https://docs.unity3d.com/Manual/SL-CustomShaderGUI.html
(3)每一個Unity Shader文件可以包含多個SubShader語義塊,但最少有一個。當Unity需要加載這個Unity Shader時,Unity會掃描所有的SubShader語義塊,然后選擇第一個能夠在目標平台上運行的SubShader。如果都不支持的話,Unity就會使用Fallback語義指定的Unity Shader。Unity提供這種語義的目的在於適應不同能力的顯卡。
SubShader { //可選的 [Tags] //可選的 [RenderSetup] Pass { } //Other Passes }
SubShader中定義了一系列Pass以及可選的狀態([RenderSetup])和標簽([Tags])設置。每個Pass定義了一次完整的渲染流程,但如果Pass的數目過多,往往會造成渲染性能的下降。因此,應盡量使用最小數目的Pass。
狀態和標簽同樣可以在Pass聲明。對於狀態設置來說,SubShader和Pass是相同的,在SubShader進行的狀態設置將會用於所有的Pass。不過對於標簽設置來說,SubShader和Pass是不一樣的。
狀態設置
狀 態 名 稱 | 設 置 指 令 | 解 釋 |
Cull | Cull Back | Front | Off | 設置剔除模式:剔除背面/正面/關閉剔除 |
ZTest | ZTest Less Greater | LEqual | GEqual |Equal | NotEqual | Always | 設置深度測試時使用的函數 |
ZWrite | ZWrite On | Off | 開啟/關閉深度寫入 |
Blend | Blend SrcFactor DstFactor | 開啟並設置混合模式 |
SubShader的標簽
SubShader的標簽(Tags)是一個鍵值對,它的鍵和值都是字符串類型。
標 簽 類 型 | 說 明 | 例 子 |
Queue | 控制渲染順序,指定該物體屬於哪一個渲染隊列,通過這種方式可以保證所有的透明物體可以在所有不透明物體后面被渲染,我們也可以自定義使用的渲染隊列來控制物體的渲染順序 | Tags{"Queue"="Transparent"} |
RenderType | 對着色器進行分類,例如這是一個不透明的着色器,或是一個透明的着色器等。這可以被用於着色器替換(Shader Replacement)功能 | Tags{"RenderType"="Opaque"} |
DisableBatching | 一些SubShader在使用Unity的批處理功能時會出現問題,例如使用了模型空間下的坐標進行頂點動畫。這時可以通過該標簽來直接指明是否對該SubShader使用批處理 | Tags{"DisableBatching"="True"} |
ForceNoShadowCasting | 控制使用該SubShader的物體是否會投射陰影 | Tags{"ForceNoShadowCasting"="True"} |
IgnoreProjector | 如果該標簽值為“True”,那么使用該SubShader的物體將不會受Projector的影響。通常用於半透明物體 | Tags{"IgnoreProjector"="True"} |
CanUseSpriteAtlas | 當該SubShader是用於精靈(sprites)時,將該標簽設為“False” | Tags{"CanUseSpriteAtlas"="False"} |
PreviewType | 指明材質面板將如何預覽該材質。默認情況下,材質將顯示為一個球形,我們可以通過把該標簽的值設為“Plane”“SkyBox”來改變預覽類型 | Tags{"PreviewType"="Plane"} |
Pass語義塊
Pass {
[Name]
[Tags]
[RenderSetup]
//Other code
}
我們可以在Pass中定義該Pass的名稱,例如:
Name "MyPassName"
通過這個名稱,我們可以使用UsePass命令來直接使用其他Shader中的Pass。例如:
UsePass "MyShader/MYPASSNAME"
這樣可以提高代碼的復用性。需要注意的是,Unity內部會把所有Pass的名稱轉換為大寫字母表示。因此,使用UsePass命令時必須使用大寫形式的名字。
Pass中設置的標簽不同於SubShader的標簽。這些標簽也是用於告訴渲染引擎我們希望怎樣來渲染物體。
標 簽 類 型 | 說 明 | 例 子 |
LightMode | 定義該Pass在Unity的渲染流水線中的角色 | Tags{"LightMode"="ForwardBase"} |
RequireOptions | 用於指定當滿足某些條件時才渲染該Pass,它的值是一個由空格分隔的字符串。 | Tags{"RequireOptions"="SoftVegetation"} |
除了上面普通的Pass定義外,Shader還支持一些特殊的Pass。
1.UsePass:可以使用該命令來復用其他Shader中的Pass。
2.GrabPass:該Pass負責抓取屏幕並將結果存儲在一張紋理中,以用於后續的Pass處理。
(4)當所有的SubShader都不能在某張顯卡上運行時,就使用Fallback指定的最低級的Shader,語義如下:
Fallback "name" //或者 Fallback Off
事實上,Fallback還會影響陰影的投射。在渲染陰影紋理時,Unity會在每個Untiy Shader中尋找一個陰影透視的Pass。通常,我們不需要自己專門實現一個Pass,這是因為Fallback使用的內置Shader中包含了這樣一個通用的Pass。因此,為每個Untiy Shader正確設置Fallback是非常重要的。