0. 例行的啰嗦
上篇關(guān)于技術(shù)的文章已經(jīng)是10月底的事情了卵惦,上個月寫了半篇關(guān)于創(chuàng)業(yè)的文章涛浙,寫到后來覺得無趣,就停下了——誰會愿意看一個無名小卒的無聊感慨呢樱溉?又是臨近月底了,其實可寫的內(nèi)容不少纬凤,只是時間不多福贞,就選最近花了大約半個星期時間搞的這個優(yōu)化來聊聊Fast Shadow Receiver這個插件的使用吧。
1. 起因
關(guān)于Unity中的動態(tài)陰影停士,已經(jīng)有挺多帖子聊過這個話題了挖帘,比如這篇《Unity移動端動態(tài)陰影總結(jié)》,還有錢康來博客里的這篇《利用Projector實現(xiàn)動態(tài)陰影》和《Planar Shadow》等等恋技。
無論是最簡單的基于Planar投影的方案還是稍微“老式”一些的Projector的方案拇舀,乃至目前比較主流的ShadowMap的方案其實都各有優(yōu)劣和對應(yīng)的應(yīng)用場景,它們之間的原理和差異不是本文的重點蜻底,有興趣的同學(xué)也可以很容易地找到相關(guān)的論文或者博客來看骄崩。
我們項目本著不要重復(fù)造輪子的想法,一直堅持使用Unity原生的ShadowMap的方案來做動態(tài)陰影薄辅。而且UWA也做過一些動態(tài)陰影方案效率的對比要拂,自己的輪子能做得比有源碼的官方好的并不多,更何況我們這種地表有起伏站楚,高配需要支持多角色動態(tài)陰影的“大型”MMORPG游戲脱惰,ShadowMap已經(jīng)是最適合的方案了。
然而窿春!人生總會有然而枪芒,否則就太平淡無味了不是?……
大約1個多月前谁尸,我發(fā)現(xiàn)了這個問題——《Unity中靜態(tài)合批與Shadowmap的宏設(shè)置沖突問題》舅踪,簡單來說,靜態(tài)合批首先對場景物體進(jìn)行了排序良蛮,保證結(jié)果正確抽碌,但是當(dāng)引入了動態(tài)陰影之后,會去修改物體接受陰影的宏(這也是一種優(yōu)化决瞳,因為有采樣和陰影計算的消耗货徙,所以關(guān)閉掉宏著色器的效率更高),導(dǎo)致原本排序好的物體無法正常進(jìn)行合批皮胡,因為著色器的宏不一樣了痴颊,從而導(dǎo)致之前靜態(tài)合批之后理論上可以做到很低的Batch數(shù)值增加了很多,使得場景渲染的效率大幅下降屡贺。
這個問題在想清楚原因之后蠢棱,在依然想要使用Unity的ShadowMap的前提下感覺是沒有什么特別簡單的優(yōu)化方案的锌杀,于是就暫時擱置下來,直到上周的時候?qū)τ螒蚋鱾€效果對于幀率的影響在真機(jī)上做了一個定量的測試之后泻仙,才發(fā)現(xiàn)問題遠(yuǎn)比想象中的嚴(yán)重……
![各個效果對于幀率影響的定量測試結(jié)果](http://o9hm1ti4o.bkt.clouddn.com/FastReceiver1.png)
上面的測試是在中配機(jī)型小米Max2上進(jìn)行的糕再,可以看出陰影的開關(guān)與否導(dǎo)致一幀的時間消耗有9.5ms左右的差異,是所有效果中影響最大的玉转!而ShadowMap自身渲染消耗不應(yīng)該有這么大的差異才對突想,觀察了下Batch數(shù)量的差異,單純場景的Batch數(shù)量大約會從25增加到150左右究抓,這有點超出我們之前制定的美術(shù)規(guī)范了猾担。
在中配效果下,我們只有主角自己開啟了動態(tài)陰影刺下,因此最初的一個想法就是引入另外一套陰影繪制方案垒探,比如Dynamic Shadow Projector,來專門針對主角進(jìn)行陰影的繪制怠李。雖然我個人很不喜歡同時使用兩套技術(shù)方案,但目前看起來這似乎是在不降低效果的前提下唯一的選擇了蛤克。
2. Dynamic Shadow Projector插件
This simple Unity asset provides a few components to render a shadow onto a render texture so that the render texture can be used with Blob Shadow Projector. Blob Shadow Projector is usually used for dropping a round blurry shadow which is not suitable for a skinned mesh object. This asset enables a projector to drop a dynamic shadow which is perfect for skinned mesh objects.
Dynamic Shadow Projector插件的原理比較簡單捺癞,將角色的陰影繪制到一張rt上,然后使用Unity的Projector組件將這張rt作為繪制輸入构挤,再繪制一遍接受陰影的物體髓介。陰影的rt是每幀更新的,也就做到了可以讓帶有動畫的角色陰影是實時變化的筋现。
試用了一下唐础,還是比較簡單易上手的,幾個組件正確設(shè)置之后就可以看到效果了矾飞,由于是針對單個角色的一膨,因此使用比較小的rt就可以做到比shadowmap更加精細(xì)的效果,但是如果想讓一個projector處理多個角色洒沦,一旦擴(kuò)大projector的范圍豹绪,陰影效果質(zhì)量的下降就比shadowmap的方法還要厲害。
![128*128的rt只投影一個Cube的情況下rt的使用率和陰影質(zhì)量](http://o9hm1ti4o.bkt.clouddn.com/DynamicProjector1.png)
![512*512的rt投影三個Cube的情況下rt的使用率和陰影質(zhì)量](http://o9hm1ti4o.bkt.clouddn.com/DynamicProjector2.png)
上面兩張圖分別給出了模擬使用一個Projector針對單個角色進(jìn)行投影和多個角色進(jìn)行投影的效果對比圖申眼,在下面的那張圖中瞒津,三個Cube的距離相隔并不遠(yuǎn),但是即使使用了512*512的rt括尸,明顯可以看到其陰影已經(jīng)有了鋸齒感巷蚪,距離更大的時候鋸齒更加嚴(yán)重。
那我為什么糾結(jié)于一定想要使用一個Projector來進(jìn)行多個角色的動態(tài)陰影繪制呢濒翻?因為對于每一個Projector來說屁柏,繪制陰影的時候都需要把接受陰影的模型完整重回一遍啦膜,從下面抓幀的截圖可以看出,三個Cube分別使用三個不同的Projector前联,地表平面需要繪制三遍功戚。這其實就是Projector的方法不太適合移動設(shè)備上多個物體都需要進(jìn)行動態(tài)陰影繪制的原因。
![多個Projector的時候接收陰影的地表繪制抓幀截圖](http://o9hm1ti4o.bkt.clouddn.com/DynamicProjector3.png)
我們的地表使用了Terrain制作似嗤,轉(zhuǎn)為Mesh之后的三角形數(shù)量一般在大幾千的水平啸臀,多遍繪制對于整體面數(shù)的增加還是很可觀的,雖然在我們的中配下只有主角接受動態(tài)陰影烁落,只需要多一遍地表模型的繪制乘粒,拿一次Draw Call和幾千面的消耗換取100+次Batch的減少,理論上已經(jīng)夠劃算了伤塌,但是我還有些不太甘心灯萍,于是想嘗試下Dynamic Shadow Projector推薦配合“服用”的Fast Shadow Receiver插件。
3. Fast Shadow Receiver的試用
Fast Shadow Receiver插件是很久前我就關(guān)注過的一個插件每聪,錢康來在他的博客里也有提到旦棉。我一直保持一個敬而遠(yuǎn)之的心態(tài),一是因為從經(jīng)驗上來說ShadowMap沒有接受陰影方需要重繪的問題药薯,只是宏的改變绑洛,效率應(yīng)該挺高的(沒想到影響了Static Batching);二是對于運(yùn)行時對mesh進(jìn)行暴力重建一直心存懷疑童本,擔(dān)心其對于CPU和內(nèi)存的額外壓力真屯。
購買了插件,將其引入我自己本地的項目工程穷娱,玩了玩Demo之后绑蔫,嘗試將其和Dynamic Shadow Projector結(jié)合一起使用。和AssetStore上對于這個插件的評論一樣泵额,這個插件的文檔的確有些晦澀配深,大約玩了三四個小時的時間才正式在游戲中跑通整個流程,過程不詳述了嫁盲,幾個小坑記錄一下:
- 可能是官方被吐槽文檔太難讀凉馆,所以做了一套Wizard,一步步走教你怎么配置亡资,然而我按照步驟做完之后并沒有得到正確的結(jié)果澜共,反而因為Wizard隱藏了背后的部分設(shè)置步驟導(dǎo)致我無法正確理解過程,從而難以排查原因锥腻。而且Wizard是針對特定的需求嗦董,未必是我自己想要的效果。最終我還是按照Demo工程里的組件逐個對照配置實現(xiàn)的效果瘦黑。
- LayerMask設(shè)定需要注意京革,為了優(yōu)化效率奇唤,Projector組件上有Igore Layers的設(shè)定,在Draw Target Object上匹摇,也有Layer Mask的設(shè)定用于標(biāo)識要繪制的節(jié)點下哪些Layer會被繪制咬扇,最終的ShadowReceiver組件也會屬于某一個Layer,比如默認(rèn)的Default廊勃。這幾個Layer如果設(shè)定有問題懈贺,會導(dǎo)致最終沒有影子被繪制出來。我因為這里的失誤多花了1個小時的時間調(diào)試各種參數(shù)坡垫,如果你在使用中遇到了奇怪的問題梭灿,可以把自己設(shè)置的各種Layer梳理一遍,保證邏輯上的正確性冰悠。我當(dāng)時的問題之一是把ShadowReceiver所在的GameObject歸入到了Default Layer堡妒,而Projector又Igore掉了Default Layer,導(dǎo)致結(jié)果不正確溉卓。
- Fast Shadow Receiver的插件制作者估計沒有經(jīng)受過中國美術(shù)的洗禮皮迟,除了文檔晦澀之外,代碼中對于容錯的兼容考慮得也不周全……我們場景中有幾千個物體桑寨,在最初測試的時候沒有花心思標(biāo)記所有的地表接受陰影的物體伏尼,索性將所有物體都進(jìn)行標(biāo)注,結(jié)果MeshTree的生成一直存在問題西疤,查了下是因為我們場景中存在一個Mesh對象為miss狀態(tài)的GameObject導(dǎo)致的,做一下兼容就好了休溶,當(dāng)然根本上也要美術(shù)去修復(fù)掉mesh miss的問題代赁。
總之,經(jīng)過一系列的嘗試兽掰,最終在我們自己的工程內(nèi)使用正式的美術(shù)資源跑通了整個流程芭碍,也對于Fast Shadow Receiver的原理有了更深的理解:它使用Mesh Tree這樣一個繼承自Scriptable的類在離線階段來預(yù)計算并存儲需要接受陰影的地表網(wǎng)格信息,并且提供BinaryMeshTree孽尽、OctMeshTree和TerrainMeshTree三種類型來應(yīng)對不同的場景窖壕。運(yùn)行時,它提供MeshShadowReceiver這樣的組件杉女,根據(jù)Projector的設(shè)定實時計算出來接受陰影的地方需要覆蓋的那些面片瞻讽,生成一個新的網(wǎng)格作為陰影接收者的網(wǎng)格對象進(jìn)行渲染,從而做到可以將原本幾千面的模型只需要幾十個面就可以繪制出來熏挎,因為畢竟需要繪制動態(tài)陰影的只有鏡頭前的部分區(qū)域速勇。
![Fast Shadow Receiver的Demo中的示例截圖](http://o9hm1ti4o.bkt.clouddn.com/FastReceiver2.png)
4. 和ShadowMap的結(jié)合以及集成
在最初的設(shè)想中是針對單獨的主角使用Projector方式的動態(tài)陰影,然后用Fast Shadow Receiver進(jìn)行優(yōu)化坎拐,在Demo中看到Fast Shadow Receiver支持ShadowMap的方案時也沒有多想烦磁。后來在和同事討論這個問題的時候聊到Projector的動態(tài)陰影方案和ShadowMap的動態(tài)陰影方案的優(yōu)劣养匈,被問到兩種方案是不是有可能做一個結(jié)合,然后想起了在Demo中看到了使用Fast Shadow Receiver來優(yōu)化ShadowMap的例子都伪。正好也在糾結(jié)我們抽離式的戰(zhàn)斗中在中等配置下的效果呕乎,如果使用Projector,需要多幾張rt的繪制是否合算陨晶,那如果可以用Fast Shadow Receiver結(jié)合之前的Shadow Map方案猬仁,對于目前結(jié)構(gòu)的改動是最小的,也不必引入第二套動態(tài)陰影的產(chǎn)生方案珍逸,只相當(dāng)于用新的插件在中配下解決場景靜態(tài)合批的問題逐虚,這似乎是非常理想的一個方案。
沿著這個思路谆膳,學(xué)習(xí)了一下Fast Shadow Receiver中關(guān)于ShadowMap的例子叭爱,看上去也非常簡單。在理解了原理的情況下漱病,只是讓場景內(nèi)的其他Render組件的Receive Shadow屬性都更改為false买雾,然后只讓Fast Shadow Receiver生成的那樣一個面片讀取生成的ShadowMap進(jìn)行陰影的繪制即可,這樣額外增加1個Draw Call和幾十個面的渲染消耗杨帽,就可以做到和之前相似的效果漓穿,中高配置的切換邏輯也更加簡潔。
我們先來看一下最后經(jīng)過修改敲定下來的制作步驟注盈,然后再聊一些其中的設(shè)計細(xì)節(jié)晃危。
-
統(tǒng)一將場景中的Mesh相關(guān)的組件放置到同一個GameObject下。這一條原本沒有一條硬性的規(guī)定老客,完全看場編同學(xué)自覺僚饭,其實整理之后Unity中的Hierarchy面板也會更加干凈整潔;
場景Mesh統(tǒng)一放入ArtRoot根節(jié)點下 -
標(biāo)記接受陰影的物體胧砰。這一步是一個有點瑣碎的工作鳍鸵,需要美術(shù)標(biāo)記出來哪些物體是接收陰影的,BinaryMeshTree是根據(jù)這些標(biāo)記出來的物體來進(jìn)行網(wǎng)格的預(yù)處理的尉间。標(biāo)記的物體過少會出現(xiàn)應(yīng)當(dāng)接受陰影的物體沒有陰影效果偿乖,而過多會導(dǎo)致BinaryMeshTree的數(shù)據(jù)內(nèi)容過多,加載變慢哲嘲、檢索速度降低贪薪,內(nèi)存占用也會很多。由于我們目前只在中配下使用眠副,所以對于這部分只要求地表和表現(xiàn)明顯的物體加入到標(biāo)記中古掏。Fast Shadow Receiver只支持Layer和RenderType的過濾方式,在我們場景中有些物體已經(jīng)被標(biāo)記過了其他有邏輯意義的Layer侦啸,因此我針對這點進(jìn)行了改造槽唾,增加了Tag的過濾丧枪,和Mask Layer取或的方式來進(jìn)行處理,并且為美術(shù)提供了方便的快捷鍵進(jìn)行快速標(biāo)注庞萍。我自己測試拧烦,我們游戲內(nèi)的場景,標(biāo)注加上驗證需要的耗時大約也就半個小時到2個小時不等钝计。
提供FastReceiver的Tag進(jìn)行標(biāo)注 -
創(chuàng)建BinaryMeshTree恋博。我們最終選擇使用BinaryMeshTree這種結(jié)構(gòu),它和OctMeshTree的區(qū)別見下圖私恬。其實這個步驟還需要更多的測試來做對比债沮,因為官方也明說small和large的界限具體是什么。
兩種不同的MeshTree對比
創(chuàng)建BinaryMeshTree的過程也很簡單本鸣,插件提供了右鍵Create菜單的支持:
創(chuàng)建BinaryMeshTree -
生成Mesh Tree疫衩。在標(biāo)注完接收陰影的物體之后,就可以選中創(chuàng)建好的BinaryMeshTree荣德,填寫其Root Object為場景的根節(jié)點闷煤,設(shè)置好Layer進(jìn)行build。我們建議美術(shù)檢查最后創(chuàng)建完畢之后給出的build信息中對于內(nèi)存的占用要小于2M涮瞻,這是一個編輯幾個場景之后的經(jīng)驗值而已鲤拿,還需要更多驗證。
Mesh Tree生成時Layer的配置
Build之后的Mesh Tree信息統(tǒng)計 -
配置Projector和Mesh Tree信息署咽。這部分為了簡化美術(shù)的配置工作近顷,大部分的配置邏輯都寫在了代碼中,只需要美術(shù)復(fù)制一份prefab出來宁否,將新創(chuàng)建的Mesh Tree信息設(shè)置正確即可窒升。需要注意這份prefab是不保留在場景內(nèi)的,編輯完畢Apply后會從場景中刪除掉家淤。
創(chuàng)建BinaryMeshTree
這里一共只使用了兩個組件异剥,一個是圖中LightProjector對象上的LightProjector組件瑟由,用于設(shè)置陰影使用的方向光對象以及一些Projector的參數(shù)絮重,比如跟隨的Target對象,擴(kuò)展的Bound范圍等歹苦;另外一個是MeshShadowReceiver組件青伤,關(guān)聯(lián)Mesh Tree數(shù)據(jù),場景渲染物體的根節(jié)點和Projecter對象殴瘦,一些Fast Shadow Receiver的裁剪狠角、更新方式等屬性也可以在這里進(jìn)行設(shè)置。 -
在資源根節(jié)點上添加Shadow Receiver Controller組件蚪腋,并進(jìn)行配置丰歌。這一組件是我們自己實現(xiàn)的姨蟋,用于控制Fast Shadow Receiver的開關(guān),它會根據(jù)游戲配置在場景加載立帖、游戲配置切換等邏輯中對Fast Shadow Receiver進(jìn)行設(shè)置眼溶。并且基于這一組件實現(xiàn)對于Mesh Tree的懶加載功能。
Shadow Receiver Controller組件配置 在游戲運(yùn)行狀態(tài)下進(jìn)行測試晓勇。上述配置完畢之后堂飞,就可以在游戲邏輯的中等配置下看到優(yōu)化后的陰影效果了,可以跑跑游戲進(jìn)行測試绑咱。
大部分細(xì)節(jié)已經(jīng)在上述步驟中描述了绰筛,這里再說明以下幾個地方:
a) Projector和MeshShadowReceiver組件是不默認(rèn)放在場景里的。這是由于當(dāng)?shù)乇砦矬w較多的時候描融,Mesh Tree的加載是有時間消耗的(遇到過一個測試?yán)勇霖琈esh Tree的大小有18M左右,在PC上需要5s以上的情況稼稿,具體原因沒有細(xì)查)薄榛,也會有額外的內(nèi)存消耗,因此這里一方面建議美術(shù)確保這個文件不會特別大让歼,另一方面通過Lazy Load的方式敞恋,在需要的時候才加載,來保證在高配和低配的情況下谋右,不需要任何額外的CPU和內(nèi)存開銷硬猫。
b) 為美術(shù)提供更多便利的工具來標(biāo)記信息。由于標(biāo)記地表是一個相對瑣碎的工作改执,驗證標(biāo)記是否合理也是一個件需要花費(fèi)很多時間和精力的事情啸蜜,除了前面提到的快捷鍵可以一鍵標(biāo)注,還推薦通過Layer的顯隱功能辈挂,以及我們自己開發(fā)的Tag顯隱功能進(jìn)行快速檢查和問題定位衬横。
![Unity原生的Layer過濾功能](http://o9hm1ti4o.bkt.clouddn.com/FastReceiver20.png)
5. 優(yōu)化結(jié)果和代價
使用同樣的測試方式,對比優(yōu)化前后的游戲運(yùn)行幀率和時間消耗:
![優(yōu)化前后的性能消耗對比](http://o9hm1ti4o.bkt.clouddn.com/FastReceiver13.png)
可以看到终蒂,使用Fast Shadow Receiver在小米 Max2上有大約7.2ms的性能提升蜂林,幀率從26上升到33,這其中有Batch數(shù)量降低的功勞拇泣,應(yīng)該也有場景物體不需要采樣ShadowMap貼圖帶來的渲染性能提升噪叙,更加具體的數(shù)據(jù)就沒有去測試了。剩余的1.5ms的時間消耗包括了ShadowMap的繪制以及Fast Shadow Receiver的更新消耗霉翔,這是后續(xù)的優(yōu)化對象睁蕾,但這次優(yōu)化已經(jīng)有很大的提升了,中配下整體效率提升了20%,已經(jīng)是難得的“神級優(yōu)化”了子眶。當(dāng)然瀑凝,這建立在場景通過關(guān)閉Shadow接收的宏能夠降低較大Batch數(shù)量的前提下。
這次優(yōu)化的收益是很大的臭杰,但它也不全是一種無損優(yōu)化猜丹,需要付出的代價有這么幾點:
- 美術(shù)工作量。需要美術(shù)同學(xué)針對場景進(jìn)行地表接收陰影物體的標(biāo)注硅卢,雖然提供了快捷的工具射窒,但是依然需要花費(fèi)一些時間成本。
- 部分物體不再會受到動態(tài)陰影的影響将塑。在之前基于ShadowMap的方案中脉顿,幾乎所有的物體都可以標(biāo)記為接收陰影,而且可以保證效果的正確性点寥,但是目前這種方案如果要做到這點會導(dǎo)致Mesh Tree對于內(nèi)存的占用較多艾疟,對于外部的大世界場景也不適應(yīng),因此會有出現(xiàn)一些小石頭等物體不會接收角色陰影的問題敢辩,這是一些效果的降低蔽莱,但目前看是可以接受的范圍內(nèi)。
-
和靜態(tài)陰影的融合與ShadowMap的方案不同戚长。ShadowMap的方案是在場景繪制的時候進(jìn)行處理的盗冷,一次像素著色的過程中會采樣lightmap和shadowmap兩張貼圖,這就可以判斷出該像素點是否在靜態(tài)陰影之中同廉,這樣可以做到比如在屋檐下或者樹蔭下這樣的靜態(tài)陰影中仪糖,角色的實時陰影可以和靜態(tài)陰影做一個較好的融合,如下圖所示迫肖。
基于ShadowMap的方案動態(tài)陰影和靜態(tài)陰影的融合效果
而使用Fast Shadow Receiver方案之后锅劝,就比較難做融合的效果,除非在新生成的mesh中保存之前mesh的uv2信息以及使用的lightmap貼圖信息蟆湖,再做一次lightmap的采樣故爵。但這比較麻煩,性價比也不高隅津,于是在靜態(tài)隱形中的角色動態(tài)陰影的效果就變成了如下圖所示的樣子诬垂。
使用Fast Shadow Receiver方案的效果
除了這些之外的代價就是程序這邊花費(fèi)了大約半個多星期的時間來學(xué)習(xí)和集成這套方案,但是從優(yōu)化結(jié)果上看饥瓷,還是收獲很大剥纷,非常值得的~
6. 一個Projector同時處理多個角色的動態(tài)陰影
由于我們是類似回合制的抽離式戰(zhàn)斗方式痹籍,即玩家進(jìn)入戰(zhàn)斗后整場戰(zhàn)斗都會發(fā)生在一小塊固定區(qū)域內(nèi)呢铆,這里其實對于ShadowMap結(jié)合Fast Shadow Receiver的方案是一個非常合適的應(yīng)用場景——只需要在進(jìn)入戰(zhàn)斗前生成一次陰影接收的面片,整場戰(zhàn)斗中都不需要對其進(jìn)行修改和變動蹲缠!
我們將LightProjector的Target鎖定為戰(zhàn)斗的中心區(qū)域點棺克,然后通過修改Bound的方式擴(kuò)大其投射范圍到整個戰(zhàn)場悠垛。前面已經(jīng)討論過基于Projector的動態(tài)陰影方案的一個問題是當(dāng)projector較大的時候rt的使用率較低,導(dǎo)致陰影質(zhì)量驟降的問題娜谊,但因為我們使用的是ShadowMap的陰影方案确买,因此擴(kuò)大Projector的范圍并不會影響陰影精度,也不需要處理多個Projector帶來rt數(shù)量纱皆、draw call增加等問題湾趾。
![戰(zhàn)場中多個角色公用一個LightProjector的方案](http://o9hm1ti4o.bkt.clouddn.com/FastReceiver16.png)
7. 總結(jié)和展望
Fast Shadow Receiver這種通過CPU的實時計算來換取GPU的渲染性能的方案锈嫩,正好解決了我們場景靜態(tài)合批被動態(tài)陰影打斷的問題逾滥,大大提升了我們游戲在中配下的幀率切揭,是近期所做的優(yōu)化中效果最為顯著的一個了棘催,因此也記錄一下詳細(xì)的過程在這里分享出來馋艺。
對于這個插件的感覺打掘,在這一周的逐漸熟悉棘钞、應(yīng)用缭付、修改的過程中鉴竭,也從心存懷疑到由衷贊嘆歧譬。目前針對這個插件的魔改還不多,除了前面提到的增加Tag的支持搏存、建立Mesh Tree的時候缺少一些對于資源的錯誤兼容之外瑰步,只修改了部分Component的默認(rèn)參數(shù),更加適合我們項目的設(shè)定璧眠,讓美術(shù)和程序可以更加方便地使用面氓。它在運(yùn)行時對于內(nèi)存的分配和CPU的性能消耗也讓我們滿意,因此在這里也幫這個插件做一下廣告——別被它的文檔和使用過程嚇到蛆橡,用好之后舌界,你的游戲效率可以獲得很大的提升~
至于未來,當(dāng)中配下的效果和效率都被驗證可以接受之后泰演,可能考慮優(yōu)化一些它的效果呻拌,將它也應(yīng)用到高配下,當(dāng)然睦焕,對于貼花等需要處理高低不平地面效果的地方藐握,也可以考慮使用這個插件進(jìn)行效率的優(yōu)化。
PS:從Fast Shadow Receiver的啟發(fā)來思考場景靜態(tài)合批被打斷的問題垃喊,其實另外一個思路是自己來做哪些物體需要被接受陰影的判斷猾普。Unity內(nèi)部肯定也是有這樣的判定邏輯來設(shè)置各個場景Render的宏,由于Shadow的距離設(shè)定較大本谜,Unity的判定范圍也過廣初家,導(dǎo)致了雖然我們在中配下只有角色渲染陰影,但是接收陰影的物體數(shù)量過多,從而導(dǎo)致Batch被頻繁打斷的問題溜在。仿照Fast Shadow Receiver陌知,使用一個跟隨角色的投影,和場景物體相交來判斷有哪些物體需要被設(shè)置為接收陰影掖肋,由于角色腳下的物體可能只會有幾個仆葡,因此Batch的數(shù)量也只會增加幾個。目前沒有沿著這個思路來做的原因之一也是地表物體的面數(shù)實在是有點多志笼,F(xiàn)ast Shadow Receiver對于面數(shù)的降低也是我們想要的優(yōu)化之一沿盅。
2017年12月24日于杭州家中(圣誕快樂~ _)