Esfog_UnityShader教程_前言
很多人在學(xué)習(xí)Unity的時候?qū)hader都是一知半解,作為剛?cè)肼毎肽甑男氯私佑|Shader的時間也并不長,正因為是新人才能體會到學(xué)習(xí)Shader時候所遇到的困難和迷茫,無奈于資料不好找,網(wǎng)上難得的幾篇教程講的又不夠完善或者太淺太短,所以我一直以來就想寫一系列UnityShader的學(xué)習(xí)教程,現(xiàn)在終于快過年公司放假了, 抽空準(zhǔn)備開始著手寫這個系列的教程了,在Unity這個圈子里我還是一只很菜很菜的菜鳥,感謝這半年來一路上幫助過我的人,書,以及在網(wǎng)上無私奉獻寶貴知識的前輩們,僅以此系列向他們致敬.
這個系列的教程會不定期的更新,由于筆者工作繁忙,有時可能會一段時間不更新,還望各位諒解,本人才疏學(xué)淺,可能在大神們面前班門弄斧了,寫這系列教程一來是想幫助那些準(zhǔn)備接觸Shader卻不知如何入門的同學(xué)們分享自己的經(jīng)驗,二來是借由自己寫教程來鍛煉自己寫技術(shù)文章的文筆和鞏固自己學(xué)習(xí)的知識,查缺補漏,只有你能把你學(xué)到的知識透徹的講給別人聽的時候,你才完全掌握了它.由于我接觸Unity時間并不長,接觸Shader時間更短,難免會有所紕漏和錯誤,還望各位看官不吝賜教,批評指正.
前言
前言部分主要是講述一下個人對學(xué)習(xí)UnityShader的一些建議,以及描述一下圖形渲染的大概模型和UnityShader的工作方式.
首先要說明一點,要想學(xué)好Shader而不只是停留在會用幾個簡單語法的層面,那你就一定不可避免的需要接觸數(shù)學(xué),主要是線性代數(shù),深入研究可能會用到微積分和空間幾何,要做好心理準(zhǔn)備,總之要學(xué)習(xí)Shader不難,但要想學(xué)好,你真的要花一番功夫.再有一點就是編寫Shader來說目前只有一些有限功能的帶代碼提示的編輯器,還沒有可以調(diào)試的工具,一旦Shader出錯Unity給出的提示經(jīng)常是非常不明確的,這時候你只能耐心的一行行分析了.
先說明的一下什么是Shader,Shader一般被翻譯為"著色器",他并不是指某一種具體語言,他是一種技術(shù),可以讓程序員去通過編寫代碼去參與到GPU渲染圖形的具體流程中去,去制作一些精美的特效和動畫甚至是讓模型發(fā)生奇怪的形變,簡單點就是可以把它理解成一種對呈現(xiàn)到屏幕上畫面的一種美化工具,想一想是不是很酷,你竟然可以去參與顯卡的工作.以前寫一輩子Hello world一直和CPU打交道.
而編寫Shader目前比較知名的是基于DirectX的HLSL和基于OpenGL的GLSL,而我們Unity用的ShaderLab是基于Nvida和Microsoft一同開發(fā)的CG(C?for Graphic)語言,從名字上我們就能知道,只是一門類C的語言,如果你接觸過C語言或者C++,甚至是JAVA,C#那對他的基本語法一定不會陌生,CG語言他是跨平臺的,他可以基于OpenGL也可以DirectX來運行,也就是說他是工作在DX和OpenGL上層的抽象語言,這三種語言在某些具體方面可能有性能和擴展性上的區(qū)別,但是對于背后的實質(zhì)技術(shù)并無過大區(qū)別,我對GLSL和HLSL接觸的不多,HLSL由于是基于DX的可能現(xiàn)在很多高端引擎都是用HLSL,GLSL的話優(yōu)勢可能在于跨平臺吧.
好吧我們只要關(guān)注我們的CG就可以了,有興趣的同學(xué)可以自己去了解一下另外兩種語言,說明一下由于CG是Nvida和微軟共同開發(fā)的,所以CG上的很多標(biāo)準(zhǔn)和HLSL是兼容的,學(xué)起來有很多互通的地方.Unity 使用的并不是完完全全的CG語言,如果你看官方的API你會發(fā)現(xiàn)他的Shader分為三大類:
(1)Fixed function shader???固定渲染管線?Shader, 現(xiàn)在的使用已經(jīng)很少了,一般用來做默認處理,以一種固定的模式去處理渲染流程,但是他完全使用ShaderLab語法讓你很簡單的去修改一些參數(shù),功能有限,很多Unity內(nèi)置的默認效果用的是這個Shader. (2)Surface Shader 不知道該怎么翻譯,姑且叫表面Shader,這個Shader是Unity官方文檔里用的最多的了,而且在國外很多的UnityShader學(xué)習(xí)教材里也很多用它來舉例子,怎么說呢,這個Shader其實和第三種已經(jīng)很像了,只不過你并不用全部把片段著色器代碼自己來寫,unity給你自帶了很多封裝好的,如果你想要自己寫也可以,我個人感覺他和第三種最大的區(qū)別在于它的光照模型我們不能確定到底是外面哪個光源,我沒試驗過是否可以通過傳外部參數(shù)來讓解決.另外在Surface Shader中的同一個SubShader中不可以使用多個Pass. (3)Vertex and Fragment Shader ?這類是我主要要講的Shader,很好很強大,定點著色器和片段著色器完全由我們自己來控制,這樣子我們就能最大化使用我們掌握的東西,當(dāng)然這類Shader也是最需要時間學(xué)習(xí)的. 我們來看一下GPU把3D物體渲染到2D屏幕上的一個簡略的步驟(只是簡單地有個印象),以后具體的地方會具體分析: 1,由于我們導(dǎo)入Unity的模型或者我們再Unity創(chuàng)建的模型,它們自身都有一個屬于自己的坐標(biāo)系,就像人一樣,無論你站在什么方位,你總是知道自己的前后左右是什么方向,而這個前后左右就建立在你自身的坐標(biāo)系,所以Unity里每一個模型并不知道其他模型的坐標(biāo)系,那么為了方便計算和操作我們就要把他們轉(zhuǎn)換到一個統(tǒng)一的空間坐標(biāo)系里,前者是物體的模型空間,后者是世界空間,這是第一個空間變換:"模型空間"->"世界空間",然后我們要確定我們在攝像機里具體能看到哪些東西,同樣為了方便計算和處理,我們要再一次把物體從世界空間轉(zhuǎn)換到攝像機空間,其實就是以攝像機為坐標(biāo)系原點建立一個三維空間,經(jīng)過這一步操作就能知道每一個物體從攝像機的位置來看他在什么方位,這是第二個空間變換:"世界空間"->"攝像機空間".現(xiàn)在雖然知道了物體在相機空間的位置,但是還不能立刻進行渲染,為了方便后面要進行的空間裁剪和,屏幕坐標(biāo)映射當(dāng)然也是為了方便計算,我們要把攝像機空間內(nèi)所有物體的坐標(biāo)再一次轉(zhuǎn)換到一個坐標(biāo)范圍是(-1,-1,-1)到(1,1,1)的正方體空間區(qū)域中,也就是整個空間變換中最難理解的"投影變換",這是第三個空間變換:"攝像機空間"->"投影空間".接下來就是把投影空間里的物體映射到屏幕坐標(biāo)上去.第四個空間變換(嚴(yán)格來說這不應(yīng)該叫空間變換):"投影空間"->"窗口空間".以上大概屬于空間變換部分的內(nèi)容,很多書本上的地方叫法和說法都不盡相同,理解大概意思即可. 2,顯卡來處理圖形的過程中一般有三個最基本的要素:點,線,面(一般指三角面),而在上一步中我們只是針對模型中單個頂點來一一處理,接下來我們就把經(jīng)過空間變換剩下來的頂點(為什么說剩下來呢,因為上一步有一點沒有提,就是在投影變換的過程中, 會進行一步剔除處理,把一些不在顯示區(qū)域內(nèi)的頂點根據(jù)一定規(guī)則過濾點,這樣可以減少接下來的運算量)進行組裝,組裝成點,線,面.也就是所謂的圖元裝配,圖元裝配進行完之后,我們需要進行柵格化:大家都知道我們面前的屏幕是由像素矩陣構(gòu)成的,而我們處理的模型只是由有限的頂點構(gòu)成的,經(jīng)過圖元裝配后形成的基本圖元(點線面),我們要把它和屏幕上的像素區(qū)域?qū)?yīng)起來,也就是進行像素填充,一般模型的每個頂點都會帶有一些基本信息(例如,法線,位置,紋理坐標(biāo),顏色等),即一個三角面其實只有三個頂點是有基本屬性的,而其他填充進來的像素區(qū)域是并不直接擁有這些基本屬性的,他們的屬性都是通過在頂點間差值計算得來的(其實上面提到的像素應(yīng)該稱為片元fragment).有些書籍中把圖元裝配也歸到柵格化中,請注意.經(jīng)過這些處理模型基本在GPU中已經(jīng)形成了他所要繪制到屏幕上的樣子了.不過這并沒有結(jié)束. 3,經(jīng)過上面的處理我們就仿佛得到了一個預(yù)備要繪制到屏幕上的臨時數(shù)據(jù)區(qū)域,不過到底是將這些像素是否最終繪制到屏幕上,怎么繪制到屏幕上,還需要經(jīng)過一些判斷.制作游戲中最常見的現(xiàn)象,離攝像機近的物體要繪制在前面,會把離攝像機較遠的物體擋住(不考慮半透明物體),如果沒有某些判斷的話,那如果GPU先渲染了離屏幕較近的物體,而后處理了離屏幕較遠的物體,那么近的先畫到屏幕上,遠的后畫就會把之前的覆蓋掉了,這顯然不是我們需要的效果(并不是所有引擎都可以自由的去控制物體的渲染順序,即使可以控制,很多時候也十分麻煩,并不十分常用).所以說我們就需要在繪制的時候進行檢測,上面這個問題使用的是ZTest(還有很多檢測這里只提這一個,其他的以后遇到了再具體說),對于GPU來說擁有兩個最基本的緩沖區(qū):幀緩沖區(qū)和Z緩沖區(qū)(也叫深度緩沖區(qū)),這兩個緩沖區(qū)都與屏幕上的每個像素一一對應(yīng),其中幀緩沖區(qū)對應(yīng)著屏幕上的像素點的最終顏色,GPU最終都是通過把顏色寫入這個區(qū)域來呈現(xiàn)在屏幕上的,而另一個深度緩沖區(qū)則存儲著屏幕上每個像素的深度值,所謂的深度值就是離攝像機的遠近(一般都被規(guī)范化為一個0~1的數(shù)值),數(shù)值越大說明離攝像機越遠,剛才我們提到的ZTest就是通過將光柵化后的像素的深度值和當(dāng)前屏幕上像素對應(yīng)的深度值進行相應(yīng)的比較,來絕定是不是把新的像素點覆蓋掉原來的像素點(當(dāng)然這并不是最終是否寫入幀緩沖區(qū)的判斷條件,還有一些其他判斷),至于以什么模式來判斷并無硬性要求,根據(jù)你具體的要求來選擇判斷方式.經(jīng)過這一系列的判斷和處理之后GPU會把最終結(jié)果寫入幀緩沖區(qū),我們會在下一幀看到剛剛處理過的最新畫面了在上面我簡略的說了一下GPU渲染3D物體的大概流程,那我們的Shader是怎么參與進來的呢,開篇已經(jīng)說過了,這個系列的文章只以Vertex and Fragment Shader來進行距離,這是Unity中最復(fù)雜和最強大的Shader,另外兩種大家自己跟著官方文檔了解一下吧. 在一個shader中我們主要通過兩個部分來參與渲染,頂點著色器(vertex)和片段著色器(fragment),他們兩個參與的時機不同,VertexShader是在頂點變換的時候,而FragmentShader是在光柵化到將最終計算完成的像素值寫入幀緩沖區(qū)。在VertexShader中我們可以對模型頂點實施一些坐標(biāo)轉(zhuǎn)換甚至形變,也可以通過計算和賦值把一些片元默認并不含有的屬性帶入FragmentShader來進行一些需要的操作.而在FragmentShader中我們可以做的就很多了,很多光照處理都是在這里進行的(當(dāng)然在VertexShader中也可以進行光照計算,不過效果不是十分好),而且也可以做一些比較復(fù)雜的色彩變換和處理.好了前言就說到這里,我第一次寫關(guān)于Shader的東西,語言組織的不是很好,大家即使理解的不太清楚也沒有關(guān)系,有個大概的了解 本篇只是接下來系列教程的一個前言,做一些基本交代,接下來為了大家更好的理解接下來的教程,也為了減少浪費一些不必要的時間在一些過于基礎(chǔ)的語法上,提議大家自己先去網(wǎng)上找一些資料或者跟著官方的文檔寫一寫簡單的Shader,熟悉一下基本語法,記得要寫Vertex and Fragment Shader,另外兩種也可以看看.相信我提前預(yù)習(xí)才不會看的一頭霧水,本人會不定期更新,希望大家能有所收獲. 再給大家推薦一些參考資料,我學(xué)習(xí)的很多知識也來自與它們(去網(wǎng)上搜搜吧): ??1.《gpu編程與cg語言之陽春白雪下里巴人》,挺通俗易懂的,是一位前輩個人總結(jié)的,不妨一看
2.《Cg Programming in Unity》,維基教科書的整理的一些關(guān)于Unity圖形渲染的知識,我還沒怎么看,同事介紹的 3.《Cg教程_可編程實時圖形權(quán)威指南》,一本比較早的書,書上的編排有些晦澀,并不十分適合UnityShader來入門,語法上是純CG的與Unity略有不同. 好了,在下才疏學(xué)淺難免有所紕漏,希望各位能及時指正,大家一起進步,若鄙人這些粗淺的見識能夠幫助到大家,我將深感欣慰.也歡迎大家繼續(xù)關(guān)注《Esfog_UnityShader教程》系列文章. 尊重他人智慧成果,歡迎轉(zhuǎn)載,請注明作者esfog,原文地址http://www.cnblogs.com/Esfog/p/3534435.html?
轉(zhuǎn)載于:https://www.cnblogs.com/Esfog/p/3534435.html
總結(jié)
以上是生活随笔為你收集整理的Esfog_UnityShader教程_前言的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Abiword对话框资源
- 下一篇: 三态工作流