作者學(xué)習(xí)shader已經(jīng)有很長一段時(shí)間了,這篇文章是對shader的整理和總結(jié)。shader的世界繽紛多彩,浩瀚無窮,作者的認(rèn)識只是彌勒山下的一粒沙子,如滄海一粟,希望次文章可以對您有所幫助,那便是作者最大的欣慰!
學(xué)習(xí)資料和工具推薦:
古人有云:工欲善其事必先利其器!
? ●書籍:
《Unity Shaders and Effects Cookbooks》作者讀的第一本書
《GPU 編程與CG 語言之陽春白雪下里巴人》可以幫助你了解硬件,此書作者水平很高
《Real-Time Rendering.3rd》經(jīng)典之作,不過不適合入門
《Unity shader入門精要》一個(gè)女孩寫的書,適合大部分想要學(xué)unity shader的初學(xué)者
《untiy3d ShaderLab實(shí)戰(zhàn)詳解》適合入門unity shader
《3D數(shù)學(xué)基礎(chǔ):圖形與游戲開發(fā)》如果真的想學(xué)好shader,學(xué)數(shù)學(xué)是必須的,這是我覺得比較系統(tǒng)全面,并且適合入門的數(shù)學(xué)書籍
《GPU編程精粹》系列 ? 這個(gè)大神可以試試,初學(xué)者不太適合學(xué)習(xí)
《Unity5.X從入門到精通》shader章節(jié) ? ?相信官方的水平
書籍暫且推薦這些,其實(shí)還有很多,如果需要可以互相交流。
●博客和教學(xué)資料:
學(xué)習(xí)資料暫時(shí)這些,如果有更好的歡迎補(bǔ)充
●逆天工具:
Shader Forge

編寫shader的可視化編輯器,使編寫shader難度大大減少,也方便開發(fā)者理解shader,大大增加開發(fā)的效率,適合初學(xué)者(一般大神都鄙視這個(gè)工具,大神都是用手寫)
Shader Forge教學(xué)視頻百度網(wǎng)盤
vs2013自動補(bǔ)全代碼,語法高亮顯示插件

相信大部分開發(fā)者已經(jīng)用慣了VS,但是VS居然不支持shader代碼高亮和自動補(bǔ)全,這個(gè)是無法容忍的事,好在作者混跡github多年,上面奇人異事很多,故而找到這個(gè)插件。
shader基礎(chǔ)
●概念:Shader(著色器)實(shí)際上就是一小段程序,它負(fù)責(zé)將輸入的Mesh(網(wǎng)格)以指定的方式和輸入的貼圖或者顏色等組合作用,然后輸出。繪圖單元可以依據(jù)這個(gè)輸出來將圖像繪制到屏幕上。輸入的貼圖或者顏色等,加上對應(yīng)的Shader,以及對Shader的特定的參數(shù)設(shè)置,將這些內(nèi)容(Shader及輸入?yún)?shù))打包存儲在一起,得到的就是一個(gè)Material(材質(zhì))。之后,我們便可以將材質(zhì)賦予合適的renderer(渲染器)來進(jìn)行渲染(輸出)了。
Shader只是一段規(guī)定好輸入(顏色,貼圖等)和輸出(渲染器能夠讀懂的點(diǎn)和顏色的對應(yīng)關(guān)系)的程序。而Shader開發(fā)者要做的就是根據(jù)輸入,進(jìn)行計(jì)算變換,產(chǎn)生輸出而已。
如圖:

可以總結(jié)成一句話:
1.GameObject里有MeshRenderer,
2.MeshRenderer里有Material列表,
3.每個(gè)Material里有且只有一個(gè)Shader;
4.Material在編輯器暴露該Shader的可調(diào)屬性。
所以,關(guān)鍵是如何編寫shader。
●unity自建shader說明:
? ?Standard surface shader會產(chǎn)生一個(gè)包含了標(biāo)準(zhǔn)關(guān)照模型(使用了unity5中新添加的基于物理的渲染方法)的表面著色器模板(為我們提供了典型的表面著色器的實(shí)現(xiàn)方法)
? ? Unity shader則會產(chǎn)生一個(gè)不包含關(guān)照(但包含霧效)的基本的頂點(diǎn)/片元著色器
? ? Image effect shader則為我們實(shí)現(xiàn)各種屏幕后處理效果提供了一個(gè)基本的模板
? ? Compute shader會產(chǎn)生一種特殊的shader文件,這類shader目的是利用GPU的并行性來進(jìn)行一些與常規(guī)渲染流水線無關(guān)的計(jì)算。
●Unity Shader文件操作說明:
? ? show generated code? 對于表面著色器,我們通過單擊show generated code按鈕來打開一個(gè)新的文件,在該文件里將顯示unity在背后為該表面著色器生成的頂點(diǎn)/片元著色器。
? ? Compile and show code? 下拉列表可以讓開發(fā)者檢查該unity shader針對的不同圖像編程接口(如opebgl ,d3d9,d3d11等)最終編譯成的shader代碼,我們可以利用這些代碼來分析和優(yōu)化著色器。
●Unity內(nèi)置shader文件分析:
? ? CGIncludes文件夾中包含了所有的內(nèi)置包含文件
? ? DefaultResources文件夾中包含了一些內(nèi)置組件或功能所需要的unity shader,例如一些GUI元素使用的shader
? ? DefaultResourcesExtra則包含了所有unity中內(nèi)置的shader
? ? Editor文件夾目前只包含一個(gè)腳本文件,它用于定義unity5引入的standard shader所用的材質(zhì)面板
(可以到官網(wǎng)下載內(nèi)置文件:https://unity3d.com/cn/get-unity/download/archive)
Unity Shader的結(jié)構(gòu)
在unity里面,我們寫shader,用到的是ShaderLab。ShaderLab是unity提供的編寫unity shader的一種說明性語言。
基礎(chǔ)結(jié)構(gòu)如下:

簡單點(diǎn),可以總結(jié)成一下圖片:

●shader的名字:
每個(gè)Unity Shader文件的第一行都需要通過Shader語義來定義該Shader的名字。
●shader的屬性:
在Properties語義塊中包含了一系列的屬性,這些屬性將會顯示在材質(zhì)面板中。
Properties的語義塊的形式通常如下:

其中的_Color就是表示屬性的名字,而"Main Color"則表示在材質(zhì)面板上出現(xiàn)的名字,Color則是為屬性定義的類型,Default Value表示我們?yōu)閷傩栽O(shè)置的默認(rèn)值,在我們第一次把Unity Shader賦給一個(gè)材質(zhì)時(shí),材質(zhì)面板上顯示的就是他的默認(rèn)值。

以上的類型可以規(guī)為以下幾類:
數(shù)字類型:他們的默認(rèn)值即為數(shù)據(jù),如Int.Float.Range
四維向量:他們的默認(rèn)值是用圓括號包圍的一個(gè)四維向量,如Color.Vector
紋理類型:他們的默認(rèn)值是一個(gè)字符串后面跟一個(gè)花括號來指定的,其中的字符串要么是空的要么是內(nèi)置的紋理的名稱,如"black", "white"等,花括號的用處原本是用于指定一些紋理屬性的,但是在Unity5.0后的版本中這些選項(xiàng)被移除了。
具體代碼如下:

Properties語義塊的作用僅是為了讓這些屬性可以出現(xiàn)在材質(zhì)面板中:

●SubShader
1.設(shè)置渲染狀態(tài):
ShaderLab提供了一系列渲染狀態(tài)的設(shè)置指令,這些指令可以設(shè)置顯卡的各種狀態(tài),如開啟混合/深度測試,具體選項(xiàng)如下。

2.標(biāo)簽:
SubShader的標(biāo)簽是一個(gè)鍵值對,它的鍵和值都是字符串類型,這些鍵值對是SubShader與渲染引擎之間的溝通橋梁。標(biāo)簽的結(jié)構(gòu)如下:
Tags { " TagName1 " = " Value1 " " TagName2 " = " Value2 "}
標(biāo)簽聲明僅可以在SubShader中場景,而不可以在Pass塊中聲明。Pass中雖然也可以定義標(biāo)簽,但這些標(biāo)簽是不同于SubShader中的標(biāo)簽的。具體內(nèi)容可以參考官方文檔:https://docs.unity3d.com/Manual/SL-SubShaderTags.html
3.Pass語義塊:
[Name]:首先我們可以在Pass中定義Pass的名稱。
[Tags]:Pass語義塊的標(biāo)簽不同于SubShader的標(biāo)簽,下面是Pass語義塊中的標(biāo)簽類型:

4.Fallback:
這一指令用于在其它的SubShader不能運(yùn)作的時(shí)候,使用Fallback值中的Shader。
Unity Shader的形態(tài):
●固定管線
固定管線是為了兼容老式顯卡。都是頂點(diǎn)光照。之后固定管線可能是被Unity拋棄的功能,所以最好不學(xué)它、當(dāng)它不存在。
●頂點(diǎn)/片元著色器

以上圖是可編程shader的編程格式,它具有復(fù)雜,靈活性高的特點(diǎn),一直都是大神最喜愛的編寫shader的方式。具體用法和參數(shù)可以參考官方文檔:https://docs.unity3d.com/Manual/SL-SubShaderTags.html
●表面著色器

表面著色器是在頂點(diǎn)/片元著色器的上面做了一層抽象的封裝,目的是為了模擬人類的思維方式,使開發(fā)人員開發(fā)的難度大大降低,并且寫出來的程序易于理解和交流,也大大減少了代碼量。但是弊端就是程序的靈活性低,擴(kuò)展性小,并且消耗的性能比較高。
具體內(nèi)容可以參考官方文檔:https://docs.unity3d.com/Manual/SL-SubShaderTags.html
●選擇Unity Shader的建議
1.除非設(shè)備是不支持可編程管線的著色器的,才考慮使用固定函數(shù)著色器,否則都使用可編程管線的著色器。
2.想和各種光源打資產(chǎn),則可以使用表面著色器,但要注意他在移動端的表現(xiàn)。
3.如果需要使用的光照數(shù)目特別少,那么頂點(diǎn)/片元著色器是一個(gè)更好的選擇。
4.如果有很多自定義的渲染效果,那么選擇頂點(diǎn)/片元著色器。
總結(jié)
shader是一門博大精深的學(xué)科,因?yàn)槔锩嫔婕暗酱罅康暮陀?jì)算機(jī)圖形學(xué)有關(guān)的內(nèi)容,不是單單靠一兩篇博客就可以說清楚,弄明白的。如果讀者們有意想精深學(xué)習(xí)shader編程,必須要花大量的時(shí)間打好基礎(chǔ)功,學(xué)習(xí)并非一朝一夕。而且,在學(xué)的過程中不僅要知道“怎么用”,更重要的是要知道“為什么要這樣用”,多多透過問題的表象思考其本質(zhì)問題,這樣才能朝大牛的方向不斷的前進(jìn)!
本人才疏學(xué)淺,如果有錯(cuò)誤的地方歡迎指正!