久久精品人妻一区国产传媒国产精品|51黑料吃瓜网在线观看色噜噜色偷偷30根|久久久久久久久国产在亚洲中文字幕人妻|91av福利china人妻91九色|国语精品视频自产自拍|色婷婷av一区二区三区久久|国产91丝袜在线|亚洲二区中文字幕|91久久精品中文内射|中文 欧美 日韩,3d色噜噜狠狠一区二区三区,国产精品福利99,国产精品传媒网站

我的訂單|我的收藏|我的商城|幫助中心|返回首頁(yè)
搜維爾[SouVR.com]>服務(wù)>案例分享 應(yīng)用研究>案例分享>軟件開(kāi)發(fā)

揭秘Unity的黑盒世界,,“ShaderLab”底層原理淺談

文章來(lái)源: 作者:frank 發(fā)布時(shí)間:2021年09月01日 點(diǎn)擊數(shù): 次 字號(hào):

在閱讀本文之前我們首先需要弄清楚什么是 ShaderLab,?

ShaderLab是由Unity發(fā)明或者說(shuō)是由Unity首創(chuàng)的一種語(yǔ)言體系,用來(lái)幫助大家做跨平臺(tái)Shading開(kāi)發(fā)。它里面除了語(yǔ)言規(guī)則之外,,還有很多其他的東西,。我們一個(gè)個(gè)來(lái)看。

我們先來(lái)看看ShaderLab Text(就是它的文本),。

我們大家知道,,無(wú)論是寫代碼,還是寫shading,,實(shí)際上我們寫的都是一堆文本,。雖然在IDE 里看起來(lái)“花里胡哨”的,,但是對(duì)計(jì)算機(jī)來(lái)講就是文本,。大家能看到,這就是我們非常熟悉的Unity的Shader,,這個(gè)東西叫ShaderLab文本,,是根據(jù)Unity定義的語(yǔ)法規(guī)則來(lái)寫的。

我們可以看到,,在基礎(chǔ)文本里面會(huì)包含一些塊,,比如說(shuō)Shader的名字,在Subshader里面也有它自己的屬性,,比如Tag,、LOD等等。在Subshader下面還有一個(gè)個(gè)Pass,,在Pass里面我們還可以定義不同的pragma,、Vertex、Fragment,,而其中的每個(gè)都對(duì)應(yīng)著不同的代碼塊,。

這是ShaderLab第一個(gè)組成的部分,我們稱之為ShaderLab文本,。

但光有文本是不行的,,就如同你寫C++,如果只是寫了一堆CPP文件,,依然是無(wú)法被計(jì)算機(jī)認(rèn)可并執(zhí)行的,。中間需要有翻譯的過(guò)程,這就是Shader Compiler的過(guò)程,。如果大家在 Windows或者是Mac上有留意過(guò)的話,,就會(huì)發(fā)現(xiàn),打開(kāi)Unity之后再打開(kāi)任務(wù)管理器,,或者在Mac上打開(kāi)active monitor,,你都會(huì)看到一個(gè)叫Unity shader Compiler的東西。如果是早期的Unity版本,,你看到的就可能是cgbatch,。

這個(gè)東西是干什么的呢,?實(shí)際上它類似一種服務(wù),是Unity在后臺(tái)提供的一種服務(wù),,用來(lái)幫助我們?nèi)グ褜懞玫腟haderLab語(yǔ)言翻譯為目標(biāo)機(jī)器能夠認(rèn)可并執(zhí)行的語(yǔ)言(我們會(huì)在下文中講解大概是怎么翻譯的),。

這是第二個(gè)組成模塊。

第三個(gè)是一個(gè)體系,,我們稱之為ShaderLab Asset,。我們寫的ShaderLab大部分是不會(huì)進(jìn)入到最終的運(yùn)行環(huán)境中去的,需要經(jīng)過(guò)二次加工,。ShaderLab里面有很多東西都是不能直接使用的,,需要進(jìn)行翻譯。而加工之后的東西,,我們叫它Asset(資產(chǎn)),,這個(gè)Asset比較常見(jiàn)的是這兩個(gè)地方。

第一個(gè)地方,,是我們打Assetbundle,,這是大家最常見(jiàn)的,我們把shader 打成一個(gè)包,,放到 bundle里,。

還有一個(gè)就是在我們打出來(lái)包的Resources下面,會(huì)有l(wèi)evel或者是 SharedAssets 這樣的包,,其實(shí)和Assetbundle的文件結(jié)構(gòu)是很類似的,,比如說(shuō)場(chǎng)景里面直接引用的一些東西,大家既愛(ài)又恨的Always include Shader也在這里面,。

這是兩個(gè)Asset比較常見(jiàn)的地方,。

但是有一個(gè)地方,大家不經(jīng)常會(huì)用到,。當(dāng)我們?cè)?library 文件夾里打開(kāi)一個(gè)工程,,就會(huì)看到一個(gè)叫 ShaderCache 的文件。我們?cè)谧鲱A(yù)處理之后的中間產(chǎn)物,,都會(huì)放到ShaderCache里面,。

我們都知道Unity特別喜歡使用GUID做索引的,這個(gè)看起來(lái)和我們的library里面的data的東西很相似,,也是一堆以數(shù)字或字母開(kāi)頭的文件夾,,然而我們現(xiàn)在看到的這個(gè)也是ID但不是GUID。如果大家曾經(jīng)拆過(guò)Unity AssetBundle,,你會(huì)看到你寫的代碼,。

你會(huì)經(jīng)常看到整個(gè)從CGPROGRAM到ENDCG,在你的Asset里看不到了,,變成了一個(gè)名字叫 GPU program IDXXX的文件,,用一個(gè)ID索引了這一整段。在里面我們可以很簡(jiǎn)單地認(rèn)為里面存的就是大家寫的CG program中間的東西,,當(dāng)然不是直接存進(jìn)去的,,是經(jīng)過(guò)了一系列的加工。這是我們存儲(chǔ)幾個(gè)shaderAsset的地方,。

最后還有一個(gè)大家會(huì)經(jīng)常遇到但是往往被忽略掉的事情——ShaderLab是有Runtime的,。既然是一種有語(yǔ)法結(jié)構(gòu)的語(yǔ)言,會(huì)包含很多的信息,,Runtime能不能把這些信息利用起來(lái)就變得很重要,。不然的話寫了半天,打上Asset也沒(méi)人用,,就白白浪費(fèi)掉了,。

這個(gè)東西經(jīng)常在哪兒見(jiàn)到呢?答案就是在Memory里面,,如果你去使用一個(gè)Sample,你會(huì)在ShaderLab里面看到它,。

這也是大家問(wèn)題最集中的地方,,為什么我ShaderLab這么大,到底是哪個(gè)Shader大,?其實(shí)不是Shader大,,而最有可能的是ShaderLab 整體很大。

所以整個(gè)Unity的ShaderLab大致分為四塊,,分別是由ShaderLab Text,、shaderLab Compiler、shaderLab Asset以及shaderLab Runtime四個(gè)部分組合而成的,。

我們了解了 ShaderLab 之后,,再簡(jiǎn)單地看一下 ShaderLab 的工作流。

首先,,當(dāng)我們?nèi)プ?Shader 的時(shí)候,,第一步就是去寫ShaderLab的Text,寫完了之后干什么呢,?寫完之后你會(huì)發(fā)現(xiàn),,當(dāng)你回到Unity的時(shí)候,Unity會(huì)開(kāi)始有一個(gè)編譯的過(guò)程,,如果你第一次導(dǎo)入了很多的Shader,,這個(gè)時(shí)候ShaderCompiler就開(kāi)始工作了。

Unity的Shader 不是一次性編譯到一個(gè)平臺(tái)上的。

那么這個(gè)名為ShaderCache的東西,,它是在什么時(shí)候產(chǎn)生的呢,?其實(shí)在 shader被import進(jìn)Unity系統(tǒng)的時(shí)候,Unity 會(huì)把原始的shader文本發(fā)給shaderCompiler去做一次預(yù)處理,,預(yù)處理的結(jié)果并不是針對(duì)某一個(gè)平臺(tái)最終的文本結(jié)構(gòu),,這個(gè)時(shí)候編譯出來(lái)的東西叫shader compilation info,是一個(gè)中間狀態(tài)的一個(gè)信息集,,這個(gè)信息集里面包含了很多重要的東西,。以下是其中比較重要的幾點(diǎn):

第一,你的變體,。我們知道 Unity 引入了 multi compile 和 shader feature 之后,,通過(guò)一次編碼就可以產(chǎn)生大量不同的 Shader。第一次我們?nèi)ヌ幚沓鲎凅w的概念,,是在我們做 Preprocess 的時(shí)候出現(xiàn)的,。經(jīng)過(guò) Preprocess 第一次的處理,在 shader compilation info 里面,,就已經(jīng)把各個(gè)變體分開(kāi)了,。

當(dāng)我們?nèi)グ?shader compilation info 編譯出來(lái)之后,會(huì)把相關(guān)的信息序列化,,并且寫到我們 ShaderCache 里面,,這就是大家所看到的 ShaderCache。這個(gè)ShaderCache的信息會(huì)被用于我們后面的一些加速編譯,,不需要每次進(jìn)入Unity都重新走一遍過(guò)程,。當(dāng)你的shader比較大,變體比較多的時(shí)候,,Preprocess的過(guò)程是相對(duì)比較慢的,。Preprocess的過(guò)程,如果我們更細(xì)化地說(shuō),,實(shí)際上做了以下幾件事情,。

第一個(gè)是做語(yǔ)法分析,比如說(shuō)我們解析語(yǔ)法數(shù),,就會(huì)生成詞法解析器和語(yǔ)法解析器,。我們先去做了一次語(yǔ)法解析和詞法解析,當(dāng)然在這個(gè)過(guò)程中Unity就會(huì)去檢查大家的shader寫得有沒(méi)有問(wèn)題,,如果有報(bào)錯(cuò),,這個(gè)階段就完成了。

當(dāng)我們解析完了之后,,Unity會(huì)把每一種不同的語(yǔ)言,,從shader的文本中對(duì)應(yīng)的部分切割出來(lái),。切割出來(lái)之后,再用對(duì)應(yīng)的語(yǔ)言的Preprocess compile去做一遍對(duì)應(yīng)這個(gè)語(yǔ)言的解析檢查,。通過(guò)這幾次檢查之后,,最終我們會(huì)得到完整的compilation info,再把它寫到ShaderCache 里面,。

如果大家在去做一個(gè)Shader的時(shí)候,,發(fā)現(xiàn)寫完的這個(gè)Shader好像不太對(duì),或者有點(diǎn)問(wèn)題,,你感覺(jué)沒(méi)有進(jìn)行重新編譯,,最簡(jiǎn)單的方法就是把ShaderCache刪掉,然后再?gòu)?qiáng)行導(dǎo)入一次,,重新編譯一次,,這時(shí)候問(wèn)題就迎刃而解了。

我們把它編出來(lái),,放到ShaderCache 里之后,,這個(gè)時(shí)候只是Unity editor拿到了Compile 這個(gè)東西,但并不能用于渲染,,也不能打到最終的包里,。它只是Unity所使用的中間狀態(tài),如果是編譯的話,,大概就類似于IR的東西,。

我們?nèi)绾伟阉罱K編譯成可運(yùn)行的版本呢?

我們可以從shader Compilation info,,或者是ShaderCache里面找到相應(yīng)的文件。這取決于你有沒(méi)有,,如果有的話,,就能從shadercache里找到;如果沒(méi)有的話,,就會(huì)走一遍Prepocess的過(guò)程,,再重新產(chǎn)生shader Compilation info。

拿到之后,,我們會(huì)把這個(gè)東西再送到shader Compiler里面,,再做一些其他的事情。這個(gè) shader Compiler里面包含了很多不同的服務(wù),,剛才是Preprocess,,這次我們要做的就是Binary Compile。這個(gè)事情會(huì)在以下幾種情況下發(fā)生,。

第一,,我們現(xiàn)在啟動(dòng)了Unity,。我們把資源都導(dǎo)入了,點(diǎn)擊play,。點(diǎn)的時(shí)候,,Unity 會(huì)做一件叫Unity Editor warmup all shader的事情(當(dāng)然在第一次導(dǎo)入的時(shí)候,Unity 也會(huì)做),。這就是為什么2020年之前的版本,,大家在點(diǎn)開(kāi)始的時(shí)候,會(huì)經(jīng)常感覺(jué)到卡半天,。實(shí)際上,,“卡”的過(guò)程會(huì)把你內(nèi)存里面,或者是資源里面所有shader的變體都warmup,。但是真機(jī)上不會(huì)卡,。

大家在去做一些性能檢查,包括去研究原理的時(shí)候你會(huì)驚訝地發(fā)現(xiàn),,Unity 實(shí)際上是兩個(gè)版本,,運(yùn)行時(shí)和編輯期是兩套完全不同的東西。所以我們?cè)谧鲂阅芊治?,或者是?nèi)存,、CPU、GPU 分析的時(shí)候,,不要在編輯器里面做,。編輯器的設(shè)計(jì)目的是為了幫助大家以最流暢的速度去編輯,所以有很多的東西,,不會(huì)去考慮運(yùn)行時(shí)資源環(huán)境的占用,,比如CPU或是內(nèi)存的占用。Unity會(huì)默認(rèn)認(rèn)為你的電腦非常棒,,內(nèi)存不會(huì)爆,,CPU不會(huì)卡,所以它可以盡情地?fù)]霍這些資源,,盡量保證大家整體的編輯體驗(yàn)是好的,。但是在運(yùn)行時(shí),Unity會(huì)考慮實(shí)際的運(yùn)行環(huán)境,。比如手機(jī)和PC上的策略會(huì)有一些差異,。

在這個(gè)地方我們進(jìn)行 Binary Compile。

第二種情況,,是真正開(kāi)始打包了,,比如說(shuō)我們要給安卓打一個(gè)AssetBundle,或者發(fā)一個(gè)安卓的APK,,這時(shí)候也會(huì)觸發(fā)這個(gè)過(guò)程,??傊|發(fā)這個(gè)過(guò)程的必要前提是我的目標(biāo)平臺(tái)是明確的,我知道要把中間的東西最終要翻譯成什么,。BinaryCompile 的過(guò)程其實(shí)是一個(gè)非常神奇的過(guò)程,,Unity 實(shí)際上也不是直接把大家寫的,比如說(shuō)CG就直接翻譯到目標(biāo)平臺(tái)上,,這個(gè)工作量其實(shí)是很大的,。

關(guān)于Unity的目標(biāo)平臺(tái)就非常多了,比如說(shuō)大家常見(jiàn)的手機(jī)平臺(tái)上有很多的API,,加上主機(jī)平臺(tái),,他們都有自己整套的語(yǔ)言規(guī)范。

大家可以腦補(bǔ)一下如果我們要是強(qiáng)行翻會(huì)怎樣,。這是一個(gè)乘的關(guān)系,,左邊4個(gè),假如說(shuō)右邊是10個(gè)不同的平臺(tái),,那就是40個(gè),,要寫40套不同的代碼,代碼的路徑就非常的繚亂,。其一代碼維護(hù)難度很大,,其二是也很難寫。

Unity使用了第三方技術(shù),,名為HLSLCC,,CC的意思是交叉編譯器,大家可以搜到,。這個(gè)最終幫助Unity做出了一些優(yōu)化和改變,,和Unity使用的版本不是完全一樣的(大家不要把網(wǎng)上的內(nèi)容改一下直接替進(jìn)來(lái),這樣行不通),。

Unity 實(shí)際上做了這樣的工作:Unity會(huì)先把前端的一些語(yǔ)言,,盡量地翻譯到DX那個(gè)級(jí)別上去,通過(guò)DX的編輯器進(jìn)行編輯,,編輯完了之后,后端再走到HLSLCC,,再向目標(biāo)平臺(tái)去輸出,,相當(dāng)于是一個(gè)兩步編譯的過(guò)程。所以整體的難度降低了很多,,大部分的工作是由HLSLCC來(lái)做的,。

這個(gè)編譯過(guò)程也會(huì)導(dǎo)致一個(gè)問(wèn)題,比如DX里面沒(méi)有,,翻譯不過(guò)去,,中間要經(jīng)過(guò)一步,,其實(shí)就相當(dāng)于過(guò)路費(fèi)要交,但是過(guò)路的時(shí)候沒(méi)有這個(gè)東西,。因此Unity在2020以后的版本,,最早的時(shí)候是用的DXBC,而現(xiàn)在用的則是DXRL,,Unity也是基礎(chǔ)于DX的編譯器進(jìn)行了自己的擴(kuò)展,,以便盡可能地去支持一些新特性。

電話:010-50951355 傳真:010-50951352  郵箱:[email protected] ,;點(diǎn)擊查看區(qū)域負(fù)責(zé)人電話
手機(jī):13811546370 / 13720091697 / 13720096040 / 13811548270 / 13811981522 / 18600440988 /13810279720 /13581546145

  • 暫無(wú)資料
  • 暫無(wú)資料
  • 暫無(wú)資料
  • 暫無(wú)資料
  • 暫無(wú)資料