unity shader 变种(多重编译 multi_compile)
一、定義
在unity中我們可以通過(guò)使用#pragma multi_compile或#pragma shader_feature指令來(lái)為shader創(chuàng)建多個(gè)稍微有點(diǎn)區(qū)別的shader變體。這個(gè)Shader被稱為宏著色器(mega shader)或者超著色器(uber shader)。實(shí)現(xiàn)原理:根據(jù)不同的情況,使用不同的預(yù)處理器指令,來(lái)多次編譯Shader代碼。
在運(yùn)行時(shí),Unity從Material宏Material.EnableKeyword和Shader.DisableKeyword或全局著色器宏Shader.EnableKeyword和Shader.DisableKeyword中選擇適當(dāng)?shù)闹髯凅w。如果這兩個(gè)宏都未啟用,則Unity使用第一個(gè)宏。
二、使用
//定義兩個(gè)TEST_1,TEST_2兩個(gè)宏 #pragma multi_compile TEST_1 TEST_2 //在shader中使用 #ifdef TEST_1//Todo #endif #ifdef TEST_2//Todo #endif上面這個(gè)命令會(huì)產(chǎn)生2種著色器變種:TEST_1,TEST_2。
要生成未定義預(yù)處理器宏的著色器變體,請(qǐng)?zhí)砑右粋€(gè)僅為下劃線(__)的名稱。這是避免使用兩個(gè)宏的常用技術(shù),因?yàn)閷?duì)項(xiàng)目中可以使用的宏數(shù)量有限制,例如:
在腳本中控制使用:
//使用TEST_1變種 Shader.EnableKeyword ("TEST_1"); Shader.DisableKeyword ("TEST_2");三、組合
#pragma multi_compile TEST_1 TEST_2 #pragma multi_compile TEST_3 TEST_4 TEST_5它產(chǎn)生總共六個(gè)著色器變體(TEST_1_TEST_3,TEST_1_TEST_4,TEST_1_TEST_5,TEST_2_TEST_3,TEST_2_TEST_4,TEST_2_TEST_5)。
所以如果有10行multi_compile,每行2個(gè)選項(xiàng),那么將一共產(chǎn)生1024個(gè)著色器變體。
請(qǐng)記住,著色器變體數(shù)量將以這種方式瘋狂增長(zhǎng)。
四、pragma shader_feature
shader_feature非常相似multi_compile。唯一的區(qū)別是Unity shader_feature在最終版本中不包含未使用的著色器變體。所以shader_feature適用于在我們?cè)诰庉嬈髦?#xff0c;選中材質(zhì),設(shè)置它使用的shader的宏,如果在程序中動(dòng)態(tài)的去設(shè)置可能無(wú)效(原因下面說(shuō)明)。而對(duì)于multi_compile,會(huì)把所有的變體都編譯進(jìn)程序里,所以適合需要在程序運(yùn)行中動(dòng)態(tài)改變狀態(tài)的宏,適合全局設(shè)置 。
材質(zhì)中設(shè)置位置截圖:
五、宏限制
在unity中限制了全局的宏個(gè)數(shù)為265個(gè),而unity內(nèi)部使用了大約60個(gè),所以在多個(gè)不同的著色器中定義全局宏時(shí)需要注意宏數(shù)量不要超過(guò)限制。
使用本地宏替代一部分全局宏:使用shader_feature_local和multi_compile_local。
shader_feature_local:類似于shader_feature,但枚舉宏是本地的。
multi_compile_local:類似于multi_compile,但枚舉宏是本地的。
在項(xiàng)目中除非是希望通過(guò)全局API啟用的那些特定宏,否則應(yīng)盡量使用本地宏,
使用更多本地宏和更少的全局宏,以減少每個(gè)著色器的宏總計(jì)數(shù)。如果存在具有相同名稱的全局和本地宏,則Unity會(huì)優(yōu)先使用local宏。
注意:
(1)不能將本地宏與進(jìn)行全局宏更改的API一起使用(例如Shader.EnableKeyword或CommandBuffer.EnableShaderKeyword)。
(2)每個(gè)著色器最多有64個(gè)唯一的本地宏。
(3)如果Material啟用了本地宏,并且其著色器更改為不再聲明的宏,則Unity會(huì)創(chuàng)建一個(gè)新的全局宏。
六、內(nèi)置multi_compile快捷方式
unity中提供一些內(nèi)置的宏用于編譯多個(gè)著色器變體。這些主要用于處理Unity中不同的光照,陰影和光照貼圖類型。
multi_compile_fwdbase:編譯PassType.ForwardBase所需的所有變體。變體處理不同的光照貼圖類型,并啟用或禁用主方向光的陰影。
multi_compile_fwdadd:為PassType.ForwardAdd編譯變體。這將編譯變體以處理Directional,Spot或Point Light類型及其變體與Cookie紋理。
multi_compile_fwdadd_fullshadows:同樣multi_compile_fwdadd,但也包括燈具有實(shí)時(shí)陰影的能力。
multi_compile_fog:擴(kuò)展為多個(gè)變體以處理不同的霧類型(off / linear / exp / exp2)。
大多數(shù)內(nèi)置快捷方式都會(huì)產(chǎn)生許多著色器變體。如果您知道項(xiàng)目不需要它們,您可以使用#pragma skip_variants跳過(guò)編譯它們中的一些。例如:
#pragma multi_compile_fwdadd #pragma skip_variants POINT POINT_COOKIE該指令跳過(guò)包含POINT或POINT_COOKIE的所有變體。
七、查看shader變種數(shù)量
#pragma multi_compile TEST_1 TEST_2 TEST_3 #pragma multi_compile TEST_4 TEST_5 #pragma multi_compile TEST_6 TEST_7查看變體數(shù)量.png
?
上面的組合會(huì)產(chǎn)生3x2x2=12種變體,我們可以點(diǎn)擊show查看具體的變體組合名稱。
// Total snippets: 1 // ----------------------------------------- // Snippet #0 platforms ffffffff: Keywords always included into build: TEST_1 TEST_2 TEST_3 TEST_4 TEST_5 TEST_6 TEST_712 keyword variants used in scene:TEST_1 TEST_4 TEST_6 TEST_1 TEST_4 TEST_7 TEST_1 TEST_5 TEST_6 TEST_1 TEST_5 TEST_7 TEST_2 TEST_4 TEST_6 TEST_2 TEST_4 TEST_7 TEST_2 TEST_5 TEST_6 TEST_2 TEST_5 TEST_7 TEST_3 TEST_4 TEST_6 TEST_3 TEST_4 TEST_7 TEST_3 TEST_5 TEST_6 TEST_3 TEST_5 TEST_7這里查看的是所有會(huì)被編譯的變體的數(shù)量,也就是#pragma multi_compile聲明的宏的全部組合。
#pragma multi_compile TEST_1 TEST_2 TEST_3 #pragma multi_compile TEST_4 TEST_5 #pragma shader_feature TEST_6 TEST_7查看變種數(shù)量.png
// Total snippets: 1 // ----------------------------------------- // Snippet #0 platforms ffffffff: Keywords stripped away when not used: TEST_6 TEST_7 Keywords always included into build: TEST_1 TEST_2 TEST_3 TEST_4 TEST_56 keyword variants used in scene:TEST_1 TEST_4 TEST_6 TEST_1 TEST_5 TEST_6 TEST_2 TEST_4 TEST_6 TEST_2 TEST_5 TEST_6 TEST_3 TEST_4 TEST_6 TEST_3 TEST_5 TEST_6上面的組合會(huì)產(chǎn)生3x2x1=6種變體,#pragma shader_feature沒(méi)有特別處理的話只有會(huì)默認(rèn)包括第一個(gè)宏。
八、編譯
(1)material的ShaderKeywords
Material所包含的Shader Keywords表示啟用shader中對(duì)應(yīng)的宏,Unity會(huì)調(diào)用當(dāng)前宏組合所對(duì)應(yīng)的變體來(lái)為Material進(jìn)行渲染。在Editor下,可以通過(guò)將material的inspector調(diào)成Debug模式來(lái)查看當(dāng)前material定義的Keywords,也可在此模式下直接定義Keywords,用空格分隔Keyword。
?
設(shè)置ShaderKeywords.png
?
優(yōu)點(diǎn):根據(jù)material中的ShaderKeywords自動(dòng)生成變體。無(wú)需額外設(shè)置
缺點(diǎn):多個(gè)不同的material包中可能存在相同的shader變體,造成資源冗余。若在程序運(yùn)行時(shí)動(dòng)態(tài)改變material的keyword其變體可能并沒(méi)有被生成
如上圖設(shè)置:如果ShaderKeywords中沒(méi)有設(shè)置TEST_6,這是如果我們想在程序中通過(guò)代碼動(dòng)態(tài)使用TEST_6這個(gè)宏(Shader.EnableKeyword("TEST_6"))。可能不能得到想要的效果,因?yàn)門EST_6這個(gè)變種沒(méi)有生成。
(2)把Shader加入到Always Include Shaders列表里
找到ProjectSetting->Graphics->Always Include Shaders列表,將我們需要的shader添加到里面,這樣unity將會(huì)把這個(gè)shader的所有的變種都生成出來(lái)。
?
AlwaysIncludeShaders.png
優(yōu)點(diǎn):我們不用擔(dān)心項(xiàng)目發(fā)布出去以后有些變種沒(méi)有生成,不能在程序中動(dòng)態(tài)的去控制我們的宏。
缺點(diǎn):生成的變體數(shù)量龐大,導(dǎo)致發(fā)布時(shí)間變長(zhǎng),游戲包體過(guò)大。比如你把standardShader放進(jìn)去,由于它有大量的keyword,全部變種都生成的話大概有幾百兆。
(3)使用ShaderVariantCollection是生成指定變體
ShaderVariantCollection是unity5.x以后用來(lái)記錄shader的哪些變體需要被生成。這樣做的好處就是在shader_feature與multi_compile結(jié)合使用時(shí),能夠設(shè)置生成何種變體,從而避免生成不必要的變體;shader不必和material打在一個(gè)包中,避免了多個(gè)包中存在相同的變體資源;明確直觀的顯示了哪些變體是需要生成的。
生成方式:
(1)通過(guò)Create->Shader-> Shader Variant Collection,就可以新建一個(gè)shader variant collection文件,手動(dòng)添加需要編譯的變種
?
ShaderVariantCollection.png
?
選擇需要生成的變種.png
?
(2)通過(guò)Edit->Project Settings->Graphics中的save to asst...按鈕,生成unity幫我們自動(dòng)收集的,使用到的變種信息。
?
自動(dòng)生成.png
這時(shí)候只需要先Clear一下,然后依次打開我們的所有場(chǎng)景,把需要的物體都顯示一遍,Unity就會(huì)自動(dòng)記錄下來(lái)哪些著色器的哪些著色器變體已經(jīng)被使用到。統(tǒng)計(jì)完后只需點(diǎn)擊下面的保存按鈕就可以生成我們所需要的ShaderVariantCollection資源。當(dāng)然你也可以為你的每一個(gè)場(chǎng)景或者按需生成足夠多的ShaderVariantCollection資源。自動(dòng)收集的功能不一定百分百可靠,最好事后多檢查。
ShaderVariantCollection加載:
啟動(dòng)時(shí)預(yù)加載:
?
最簡(jiǎn)單最粗暴的使用方式就是在游戲啟動(dòng)的瞬間就直接加載ShaderVariantCollection資源并編譯里面的著色器變體,Unity已經(jīng)為我們做好這一步了,依然還是在圖形設(shè)置面板里,只需把需要啟動(dòng)是就編譯的ShaderVariantCollection添加在Preloaded Shaders里面
預(yù)加載.png
代碼加載:
由于ShaderVariantCollection也是一種資源,可以跟紋理、模型等等資源一起打包和加載等,只需在加載之后調(diào)用一句WarmUp。
ShaderVariantCollection shaderVariantCollection = Resources.Load <ShaderVariantCollection>( "MainShaderVariant"); if (shaderVariantCollection )shaderVariantCollection.WarmUp ();也可以把ShaderVariantCollection放在Resources目錄下,好像會(huì)被自動(dòng)加載。
?
總結(jié)
以上是生活随笔為你收集整理的unity shader 变种(多重编译 multi_compile)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 为什么申请不到大额信用卡?申请大额信用卡
- 下一篇: 走进LWRP(Universal RP)