一.Unity Shader概述
1.在Unity中我們需要配合使用材質(material)和Unity Shader才能達到需要的效果。材質是載體,Unity Shader是文本文件,我們在Unity Shader中寫好渲染的代碼(屬性,頂點着色器,片元着色器等),加載到材質上,在材質上可以調節shader的屬性,然後將材質賦給模型展示渲染效果。
2.Unity Shader不是傳統意義上的的Shader,Unity Shader實際上指的是一個ShaderLab文件--以.shader爲文件後綴的一種文件。但Unity Shader可以做的遠多於一個傳統意義的Shader。
a、傳統Shader中,我們只可以編寫特定類型的Shader,比如頂點着色器,或片元着色器等。Unity Shader中我們可以在一個文件中編寫他們。
b、傳統Shader中,我們不能做一些例如開啓混合、深度測試等渲染測試,這是在另外的代碼中設置的。Unity Shader中我們加幾個指令就可以了。
c、傳統Shader中,需要編寫大量代碼設置着色器的輸入和輸出。Unity Shader中,我們只需要聲明一些屬性,並可以在材質中改變這些屬性。對於模型數據(頂點位置,紋理座標,法線,切線等),Unity Shader中我們可以直接訪問,傳統Shader需要自行編碼傳給shader。
d、Unity Shader的高度封裝,使其失去了更多的編寫自由性,不過同時也使我們只需要和Unity Shader打交道,不用關心渲染引擎底層實現。
3.Unity 5.5版本中,提供了5種Unity Shader模板:Standard Surface Shader,Standard Surface Shader(Instanced),Unlit Shader,Image Effect Shader, Compute Shader。
a、Standard Surface Shader是基於物理渲染(PBS)的包含標準光照模型的表面着色器模板,在5.x版本中,我們新建一個材質,它會默認使用內置的Standard Shader,是使用基於物理渲染(PBS)的技術,區別於傳統光照Shader,它對光照渲染有着更加強大的支持,當然如果想達到強大的效果,除了主紋理和法線紋理,你可能需要加入金屬紋理,粗糙度紋理,遮擋紋理,細節紋理,並配置一堆屬性,再加上光照探針,反射探針啥的,想清楚再用。
b、Standard Surface Shader(Instanced),據說是5.4版本以後加的,使用了Gpu Instancing技術,這個技術在大量使用相同材質和網格的情況下可以大幅度降低Draw Call,而這個模板在生成陰影pass中使用了該技術。
c、Unlit Shader:不包含光照但包含霧效的頂點片元着色器。
d、Image Effect Shader:只是一個簡單的圖片展示效果,爲實現屏幕後處理效果提供了基本模板。
f、Compute Shader:產生特殊的shader文件,旨在利用GPU的並行性來進行一些與常規渲染流水線無關的計算。(原書照搬,不在研究範圍)。
a和b是表面着色器,c和d是頂點片元着色器,請對應選擇模板。(因爲喜歡用頂點片元着色器,我喜歡用d)
二.ShaderLab
上面提到過Unity Shader不是傳統意義的shader,編寫傳統意義的shader需要和很多文件和配置打交道,Unity爲我們提供了一層抽象:Unity Shader,而專門爲Unity Shader服務的語言就是ShaderLab。
三.Unity Shader結構
1.名字
每個Unity Shader第一行都需要定義一個名字,格式例子:Shader "Custom/MyShader","/"是路徑,其對應位置爲Shader->Custom->MyShader。
2.屬性(Properties)
Properties {
Name ("display name", PropertyType) = DefaultValue
Name ("display name", PropertyType) = DefaultValue
....
}
Properties中包含了一系列屬性,會在材質面板中展示,開發者可以方便調試它們,同時shader會訪問它們,類似於untiy的public變量。如上所示,每條屬性由Name(名字,代碼中要用),"display name"(面板顯示名字),PropertyType(屬性類型),DefaultValue(默認值)組成。Unity Shader屬性類型如下:
3.SubShader
一個Shader文件可以包含多個SubShader,但最少要一個。Unity加載該shader時,會掃描並選擇一個能在目標平臺運行的SubShader,如果都不支持,會使用Fallback指定的Unity Shader。
SubShader通常定義如下:
- SubShader {
- //可選
- [Tags]
- //可選
- [RenderSetup]
- Pass {
- }
- //其他Pass
- ...
- }
a、Tags:標籤,由一組鍵值對組成,鍵和值都是字符串,它們告訴Unity渲染引擎,我希望怎樣及何時渲染該SubShader。結構如下:
Tags { "TagName1" = "Value1" "TagName2" = "Value2"}
新手注意,每個標籤間隔不要加逗號或分號,只是空格,最後也沒符號,新手這裏容易寫錯。
SubShader支持的標籤類型如下(書上截圖,原諒我懶):
注意,這裏的標籤是在SubShader裏的,不是Pass裏的,它們不同。
b、RenderSetup
狀態設置,ShaderLab提供了一系列渲染狀態的設置指令,可以設置在SubShader裏,影響其下所有pass,也可以放某個pass裏,隻影響該pass。常見的渲染設置如下(接着截圖):
c、Pass
SubShader中可以有多個pass,每個Pass定義了一次完整的渲染流程,但Pass過多會造成渲染性能下降,所以我們儘量用最少數目的Pass。
Pass包含的語義如下:
- Pass {
- [Name]
- [Tags]
- [RenderSetup]
- //正式代碼
- ....
- }
Name:該pass名字,可選,書寫例子如下:
Name "MyPassName"
通過該名字,我們可以在其他的Unity Shader中用UsePass命令直接使用該Pass,非常方便,例如
UsePass "MyShader/MYPASSNAME"
需要注意的是Unity內部會把所有Pass名稱轉換成大寫字母,所以用UsePass時必須使用大寫形式的名字。
上面SubShader的RenderSetup(狀態設置)同樣適用於Pass。
Pass的標籤不同於SubShader的標籤,下面是Pass中使用的標籤:
還有一些特殊的Pass
UsePass:前面提到了,可以用Pass的名字複用訪問。
GrabPass:該Pass負責抓取屏幕並存到一張紋理中,後面的Pass可以對該紋理繼續處理。
d、FallBack
放在最後,當所有SubShader都不合適,就用FallBack提供的Shader。語義如下:
FallBack "name" 或 FallBack Off
不要以爲它沒用,當你學到陰影那裏就知道它的用處了,FallBack的內置shader往往包含一個通用的陰影投射Pass,所以你不用自己實現。