溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Unity在如何使用Fast Shadow Receiver優(yōu)化渲染效率

發(fā)布時(shí)間:2021-11-10 16:30:57 來(lái)源:億速云 閱讀:281 作者:柒染 欄目:大數(shù)據(jù)

這篇文章將為大家詳細(xì)講解有關(guān)Unity在如何使用Fast Shadow Receiver優(yōu)化渲染效率,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。

1. 起因

關(guān)于Unity中的動(dòng)態(tài)陰影,已經(jīng)有挺多帖子聊過(guò)這個(gè)話題了,
無(wú)論是最簡(jiǎn)單的基于Planar投影的方案還是稍微“老式”一些的Projector的方案,乃至目前比較主流的ShadowMap的方案其實(shí)都各有優(yōu)劣和對(duì)應(yīng)的應(yīng)用場(chǎng)景,它們之間的原理和差異不是本文的重點(diǎn),有興趣的同學(xué)也可以很容易地找到相關(guān)的論文或者博客來(lái)看。

我們項(xiàng)目本著不要重復(fù)造輪子的想法,一直堅(jiān)持使用Unity原生的ShadowMap的方案來(lái)做動(dòng)態(tài)陰影。而且UWA也做過(guò)一些動(dòng)態(tài)陰影方案效率的對(duì)比,自己的輪子能做得比有源碼的官方好的并不多,更何況我們這種地表有起伏,高配需要支持多角色動(dòng)態(tài)陰影的“大型”MMORPG游戲,ShadowMap已經(jīng)是最適合的方案了。

然而!人生總會(huì)有然而,否則就太平淡無(wú)味了不是?……

大約1個(gè)多月前,我發(fā)現(xiàn)了這個(gè)問(wèn)題——《Unity中靜態(tài)合批與Shadowmap的宏設(shè)置沖突問(wèn)題》,簡(jiǎn)單來(lái)說(shuō),靜態(tài)合批首先對(duì)場(chǎng)景物體進(jìn)行了排序,保證結(jié)果正確,但是當(dāng)引入了動(dòng)態(tài)陰影之后,會(huì)去修改物體接受陰影的宏(這也是一種優(yōu)化,因?yàn)橛胁蓸雍完幱坝?jì)算的消耗,所以關(guān)閉掉宏著色器的效率更高),導(dǎo)致原本排序好的物體無(wú)法正常進(jìn)行合批,因?yàn)橹鞯暮瓴灰粯恿耍瑥亩鴮?dǎo)致之前靜態(tài)合批之后理論上可以做到很低的Batch數(shù)值增加了很多,使得場(chǎng)景渲染的效率大幅下降。

這個(gè)問(wèn)題在想清楚原因之后,在依然想要使用Unity的ShadowMap的前提下感覺(jué)是沒(méi)有什么特別簡(jiǎn)單的優(yōu)化方案的,于是就暫時(shí)擱置下來(lái),直到上周的時(shí)候?qū)τ螒蚋鱾€(gè)效果對(duì)于幀率的影響在真機(jī)上做了一個(gè)定量的測(cè)試之后,才發(fā)現(xiàn)問(wèn)題遠(yuǎn)比想象中的嚴(yán)重……

Unity在如何使用Fast Shadow Receiver優(yōu)化渲染效率

各個(gè)效果對(duì)于幀率影響的定量測(cè)試結(jié)果

上面的測(cè)試是在中配機(jī)型小米Max2上進(jìn)行的,可以看出陰影的開(kāi)關(guān)與否導(dǎo)致一幀的時(shí)間消耗有9.5ms左右的差異,是所有效果中影響最大的!而ShadowMap自身渲染消耗不應(yīng)該有這么大的差異才對(duì),觀察了下Batch數(shù)量的差異,單純場(chǎng)景的Batch數(shù)量大約會(huì)從25增加到150左右,這有點(diǎn)超出我們之前制定的美術(shù)規(guī)范了。

在中配效果下,我們只有主角自己開(kāi)啟了動(dòng)態(tài)陰影,因此最初的一個(gè)想法就是引入另外一套陰影繪制方案,比如Dynamic Shadow Projector,來(lái)專門(mén)針對(duì)主角進(jìn)行陰影的繪制。雖然我個(gè)人很不喜歡同時(shí)使用兩套技術(shù)方案,但目前看起來(lái)這似乎是在不降低效果的前提下唯一的選擇了。

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插件的原理比較簡(jiǎn)單,將角色的陰影繪制到一張rt上,然后使用Unity的Projector組件將這張rt作為繪制輸入,再繪制一遍接受陰影的物體。陰影的rt是每幀更新的,也就做到了可以讓帶有動(dòng)畫(huà)的角色陰影是實(shí)時(shí)變化的。

試用了一下,還是比較簡(jiǎn)單易上手的,幾個(gè)組件正確設(shè)置之后就可以看到效果了,由于是針對(duì)單個(gè)角色的,因此使用比較小的rt就可以做到比shadowmap更加精細(xì)的效果,但是如果想讓一個(gè)projector處理多個(gè)角色,一旦擴(kuò)大projector的范圍,陰影效果質(zhì)量的下降就比shadowmap的方法還要厲害。

Unity在如何使用Fast Shadow Receiver優(yōu)化渲染效率

128*128的rt只投影一個(gè)Cube的情況下rt的使用率和陰影質(zhì)量

Unity在如何使用Fast Shadow Receiver優(yōu)化渲染效率

512*512的rt投影三個(gè)Cube的情況下rt的使用率和陰影質(zhì)量

上面兩張圖分別給出了模擬使用一個(gè)Projector針對(duì)單個(gè)角色進(jìn)行投影和多個(gè)角色進(jìn)行投影的效果對(duì)比圖,在下面的那張圖中,三個(gè)Cube的距離相隔并不遠(yuǎn),但是即使使用了512*512的rt,明顯可以看到其陰影已經(jīng)有了鋸齒感,距離更大的時(shí)候鋸齒更加嚴(yán)重。
那我為什么糾結(jié)于一定想要使用一個(gè)Projector來(lái)進(jìn)行多個(gè)角色的動(dòng)態(tài)陰影繪制呢?因?yàn)閷?duì)于每一個(gè)Projector來(lái)說(shuō),繪制陰影的時(shí)候都需要把接受陰影的模型完整重回一遍,從下面抓幀的截圖可以看出,三個(gè)Cube分別使用三個(gè)不同的Projector,地表平面需要繪制三遍。這其實(shí)就是Projector的方法不太適合移動(dòng)設(shè)備上多個(gè)物體都需要進(jìn)行動(dòng)態(tài)陰影繪制的原因。

Unity在如何使用Fast Shadow Receiver優(yōu)化渲染效率

多個(gè)Projector的時(shí)候接收陰影的地表繪制抓幀截圖

我們的地表使用了Terrain制作,轉(zhuǎn)為Mesh之后的三角形數(shù)量一般在大幾千的水平,多遍繪制對(duì)于整體面數(shù)的增加還是很可觀的,雖然在我們的中配下只有主角接受動(dòng)態(tài)陰影,只需要多一遍地表模型的繪制,拿一次Draw Call和幾千面的消耗換取100+次Batch的減少,理論上已經(jīng)夠劃算了,但是我還有些不太甘心,于是想嘗試下Dynamic Shadow Projector推薦配合“服用”的Fast Shadow Receiver插件。

3. Fast Shadow Receiver的試用

Fast Shadow Receiver插件是很久前我就關(guān)注過(guò)的一個(gè)插件,錢(qián)康來(lái)在他的博客里也有提到。我一直保持一個(gè)敬而遠(yuǎn)之的心態(tài),一是因?yàn)閺慕?jīng)驗(yàn)上來(lái)說(shuō)ShadowMap沒(méi)有接受陰影方需要重繪的問(wèn)題,只是宏的改變,效率應(yīng)該挺高的(沒(méi)想到影響了Static Batching);二是對(duì)于運(yùn)行時(shí)對(duì)mesh進(jìn)行暴力重建一直心存懷疑,擔(dān)心其對(duì)于CPU和內(nèi)存的額外壓力。

購(gòu)買(mǎi)了插件,將其引入我自己本地的項(xiàng)目工程,玩了玩Demo之后,嘗試將其和Dynamic Shadow Projector結(jié)合一起使用。和AssetStore上對(duì)于這個(gè)插件的評(píng)論一樣,這個(gè)插件的文檔的確有些晦澀,大約玩了三四個(gè)小時(shí)的時(shí)間才正式在游戲中跑通整個(gè)流程,過(guò)程不詳述了,幾個(gè)小坑記錄一下:

  1. 可能是官方被吐槽文檔太難讀,所以做了一套Wizard,一步步走教你怎么配置,然而我按照步驟做完之后并沒(méi)有得到正確的結(jié)果,反而因?yàn)閃izard隱藏了背后的部分設(shè)置步驟導(dǎo)致我無(wú)法正確理解過(guò)程,從而難以排查原因。而且Wizard是針對(duì)特定的需求,未必是我自己想要的效果。最終我還是按照Demo工程里的組件逐個(gè)對(duì)照配置實(shí)現(xiàn)的效果。

  2. LayerMask設(shè)定需要注意,為了優(yōu)化效率,Projector組件上有Igore Layers的設(shè)定,在Draw Target Object上,也有Layer Mask的設(shè)定用于標(biāo)識(shí)要繪制的節(jié)點(diǎn)下哪些Layer會(huì)被繪制,最終的ShadowReceiver組件也會(huì)屬于某一個(gè)Layer,比如默認(rèn)的Default。這幾個(gè)Layer如果設(shè)定有問(wèn)題,會(huì)導(dǎo)致最終沒(méi)有影子被繪制出來(lái)。我因?yàn)檫@里的失誤多花了1個(gè)小時(shí)的時(shí)間調(diào)試各種參數(shù),如果你在使用中遇到了奇怪的問(wèn)題,可以把自己設(shè)置的各種Layer梳理一遍,保證邏輯上的正確性。我當(dāng)時(shí)的問(wèn)題之一是把ShadowReceiver所在的GameObject歸入到了Default Layer,而Projector又Igore掉了Default Layer,導(dǎo)致結(jié)果不正確。

  3. Fast Shadow Receiver的插件制作者估計(jì)沒(méi)有經(jīng)受過(guò)中國(guó)美術(shù)的洗禮,除了文檔晦澀之外,代碼中對(duì)于容錯(cuò)的兼容考慮得也不周全……我們場(chǎng)景中有幾千個(gè)物體,在最初測(cè)試的時(shí)候沒(méi)有花心思標(biāo)記所有的地表接受陰影的物體,索性將所有物體都進(jìn)行標(biāo)注,結(jié)果MeshTree的生成一直存在問(wèn)題,查了下是因?yàn)槲覀儓?chǎng)景中存在一個(gè)Mesh對(duì)象為miss狀態(tài)的GameObject導(dǎo)致的,做一下兼容就好了,當(dāng)然根本上也要美術(shù)去修復(fù)掉mesh miss的問(wèn)題。

總之,經(jīng)過(guò)一系列的嘗試,最終在我們自己的工程內(nèi)使用正式的美術(shù)資源跑通了整個(gè)流程,也對(duì)于Fast Shadow Receiver的原理有了更深的理解:它使用Mesh Tree這樣一個(gè)繼承自Scriptable的類在離線階段來(lái)預(yù)計(jì)算并存儲(chǔ)需要接受陰影的地表網(wǎng)格信息,并且提供BinaryMeshTree、OctMeshTree和TerrainMeshTree三種類型來(lái)應(yīng)對(duì)不同的場(chǎng)景。運(yùn)行時(shí),它提供MeshShadowReceiver這樣的組件,根據(jù)Projector的設(shè)定實(shí)時(shí)計(jì)算出來(lái)接受陰影的地方需要覆蓋的那些面片,生成一個(gè)新的網(wǎng)格作為陰影接收者的網(wǎng)格對(duì)象進(jìn)行渲染,從而做到可以將原本幾千面的模型只需要幾十個(gè)面就可以繪制出來(lái),因?yàn)楫吘剐枰L制動(dòng)態(tài)陰影的只有鏡頭前的部分區(qū)域。

Unity在如何使用Fast Shadow Receiver優(yōu)化渲染效率

Fast Shadow Receiver的Demo中的示例截圖

4. 和ShadowMap的結(jié)合以及集成

在最初的設(shè)想中是針對(duì)單獨(dú)的主角使用Projector方式的動(dòng)態(tài)陰影,然后用Fast Shadow Receiver進(jìn)行優(yōu)化,在Demo中看到Fast Shadow Receiver支持ShadowMap的方案時(shí)也沒(méi)有多想。后來(lái)在和同事討論這個(gè)問(wèn)題的時(shí)候聊到Projector的動(dòng)態(tài)陰影方案和ShadowMap的動(dòng)態(tài)陰影方案的優(yōu)劣,被問(wèn)到兩種方案是不是有可能做一個(gè)結(jié)合,然后想起了在Demo中看到了使用Fast Shadow Receiver來(lái)優(yōu)化ShadowMap的例子。正好也在糾結(jié)我們抽離式的戰(zhàn)斗中在中等配置下的效果,如果使用Projector,需要多幾張rt的繪制是否合算,那如果可以用Fast Shadow Receiver結(jié)合之前的Shadow Map方案,對(duì)于目前結(jié)構(gòu)的改動(dòng)是最小的,也不必引入第二套動(dòng)態(tài)陰影的產(chǎn)生方案,只相當(dāng)于用新的插件在中配下解決場(chǎng)景靜態(tài)合批的問(wèn)題,這似乎是非常理想的一個(gè)方案。

沿著這個(gè)思路,學(xué)習(xí)了一下Fast Shadow Receiver中關(guān)于ShadowMap的例子,看上去也非常簡(jiǎn)單。在理解了原理的情況下,只是讓場(chǎng)景內(nèi)的其他Render組件的Receive Shadow屬性都更改為false,然后只讓Fast Shadow Receiver生成的那樣一個(gè)面片讀取生成的ShadowMap進(jìn)行陰影的繪制即可,這樣額外增加1個(gè)Draw Call和幾十個(gè)面的渲染消耗,就可以做到和之前相似的效果,中高配置的切換邏輯也更加簡(jiǎn)潔。

我們先來(lái)看一下最后經(jīng)過(guò)修改敲定下來(lái)的制作步驟,然后再聊一些其中的設(shè)計(jì)細(xì)節(jié)。

  1. 統(tǒng)一將場(chǎng)景中的Mesh相關(guān)的組件放置到同一個(gè)GameObject下。這一條原本沒(méi)有一條硬性的規(guī)定,完全看場(chǎng)編同學(xué)自覺(jué),其實(shí)整理之后Unity中的Hierarchy面板也會(huì)更加干凈整潔;

    Unity在如何使用Fast Shadow Receiver優(yōu)化渲染效率

    場(chǎng)景Mesh統(tǒng)一放入ArtRoot根節(jié)點(diǎn)下

  2. 標(biāo)記接受陰影的物體。這一步是一個(gè)有點(diǎn)瑣碎的工作,需要美術(shù)標(biāo)記出來(lái)哪些物體是接收陰影的,BinaryMeshTree是根據(jù)這些標(biāo)記出來(lái)的物體來(lái)進(jìn)行網(wǎng)格的預(yù)處理的。標(biāo)記的物體過(guò)少會(huì)出現(xiàn)應(yīng)當(dāng)接受陰影的物體沒(méi)有陰影效果,而過(guò)多會(huì)導(dǎo)致BinaryMeshTree的數(shù)據(jù)內(nèi)容過(guò)多,加載變慢、檢索速度降低,內(nèi)存占用也會(huì)很多。由于我們目前只在中配下使用,所以對(duì)于這部分只要求地表和表現(xiàn)明顯的物體加入到標(biāo)記中。Fast Shadow Receiver只支持Layer和RenderType的過(guò)濾方式,在我們場(chǎng)景中有些物體已經(jīng)被標(biāo)記過(guò)了其他有邏輯意義的Layer,因此我針對(duì)這點(diǎn)進(jìn)行了改造,增加了Tag的過(guò)濾,和Mask Layer取或的方式來(lái)進(jìn)行處理,并且為美術(shù)提供了方便的快捷鍵進(jìn)行快速標(biāo)注。我自己測(cè)試,我們游戲內(nèi)的場(chǎng)景,標(biāo)注加上驗(yàn)證需要的耗時(shí)大約也就半個(gè)小時(shí)到2個(gè)小時(shí)不等。

    Unity在如何使用Fast Shadow Receiver優(yōu)化渲染效率

    提供FastReceiver的Tag進(jìn)行標(biāo)注

  3. 創(chuàng)建BinaryMeshTree。我們最終選擇使用BinaryMeshTree這種結(jié)構(gòu),它和OctMeshTree的區(qū)別見(jiàn)下圖。其實(shí)這個(gè)步驟還需要更多的測(cè)試來(lái)做對(duì)比,因?yàn)楣俜揭裁髡f(shuō)small和large的界限具體是什么。

    Unity在如何使用Fast Shadow Receiver優(yōu)化渲染效率

    兩種不同的MeshTree對(duì)比

    創(chuàng)建BinaryMeshTree的過(guò)程也很簡(jiǎn)單,插件提供了右鍵Create菜單的支持:

    Unity在如何使用Fast Shadow Receiver優(yōu)化渲染效率

    創(chuàng)建BinaryMeshTree

  4. 生成Mesh Tree。在標(biāo)注完接收陰影的物體之后,就可以選中創(chuàng)建好的BinaryMeshTree,填寫(xiě)其Root Object為場(chǎng)景的根節(jié)點(diǎn),設(shè)置好Layer進(jìn)行build。我們建議美術(shù)檢查最后創(chuàng)建完畢之后給出的build信息中對(duì)于內(nèi)存的占用要小于2M,這是一個(gè)編輯幾個(gè)場(chǎng)景之后的經(jīng)驗(yàn)值而已,還需要更多驗(yàn)證。

    Unity在如何使用Fast Shadow Receiver優(yōu)化渲染效率

    Mesh Tree生成時(shí)Layer的配置

    Unity在如何使用Fast Shadow Receiver優(yōu)化渲染效率

    Build之后的Mesh Tree信息統(tǒng)計(jì)

  5. 配置Projector和Mesh Tree信息。這部分為了簡(jiǎn)化美術(shù)的配置工作,大部分的配置邏輯都寫(xiě)在了代碼中,只需要美術(shù)復(fù)制一份prefab出來(lái),將新創(chuàng)建的Mesh Tree信息設(shè)置正確即可。需要注意這份prefab是不保留在場(chǎng)景內(nèi)的,編輯完畢Apply后會(huì)從場(chǎng)景中刪除掉。

    Unity在如何使用Fast Shadow Receiver優(yōu)化渲染效率

    創(chuàng)建BinaryMeshTree

    這里一共只使用了兩個(gè)組件,一個(gè)是圖中LightProjector對(duì)象上的LightProjector組件,用于設(shè)置陰影使用的方向光對(duì)象以及一些Projector的參數(shù),比如跟隨的Target對(duì)象,擴(kuò)展的Bound范圍等;另外一個(gè)是MeshShadowReceiver組件,關(guān)聯(lián)Mesh Tree數(shù)據(jù),場(chǎng)景渲染物體的根節(jié)點(diǎn)和Projecter對(duì)象,一些Fast Shadow Receiver的裁剪、更新方式等屬性也可以在這里進(jìn)行設(shè)置。

  6. 在資源根節(jié)點(diǎn)上添加Shadow Receiver Controller組件,并進(jìn)行配置。這一組件是我們自己實(shí)現(xiàn)的,用于控制Fast Shadow Receiver的開(kāi)關(guān),它會(huì)根據(jù)游戲配置在場(chǎng)景加載、游戲配置切換等邏輯中對(duì)Fast Shadow Receiver進(jìn)行設(shè)置。并且基于這一組件實(shí)現(xiàn)對(duì)于Mesh Tree的懶加載功能。

    Unity在如何使用Fast Shadow Receiver優(yōu)化渲染效率

    Shadow Receiver Controller組件配置

  7. 在游戲運(yùn)行狀態(tài)下進(jìn)行測(cè)試。上述配置完畢之后,就可以在游戲邏輯的中等配置下看到優(yōu)化后的陰影效果了,可以跑跑游戲進(jìn)行測(cè)試。

大部分細(xì)節(jié)已經(jīng)在上述步驟中描述了,這里再說(shuō)明以下幾個(gè)地方:

a) Projector和MeshShadowReceiver組件是不默認(rèn)放在場(chǎng)景里的。這是由于當(dāng)?shù)乇砦矬w較多的時(shí)候,Mesh Tree的加載是有時(shí)間消耗的(遇到過(guò)一個(gè)測(cè)試?yán)樱琈esh Tree的大小有18M左右,在PC上需要5s以上的情況,具體原因沒(méi)有細(xì)查),也會(huì)有額外的內(nèi)存消耗,因此這里一方面建議美術(shù)確保這個(gè)文件不會(huì)特別大,另一方面通過(guò)Lazy Load的方式,在需要的時(shí)候才加載,來(lái)保證在高配和低配的情況下,不需要任何額外的CPU和內(nèi)存開(kāi)銷。
b) 為美術(shù)提供更多便利的工具來(lái)標(biāo)記信息。由于標(biāo)記地表是一個(gè)相對(duì)瑣碎的工作,驗(yàn)證標(biāo)記是否合理也是一個(gè)件需要花費(fèi)很多時(shí)間和精力的事情,除了前面提到的快捷鍵可以一鍵標(biāo)注,還推薦通過(guò)Layer的顯隱功能,以及我們自己開(kāi)發(fā)的Tag顯隱功能進(jìn)行快速檢查和問(wèn)題定位。

Unity在如何使用Fast Shadow Receiver優(yōu)化渲染效率

Unity原生的Layer過(guò)濾功能

5. 優(yōu)化結(jié)果和代價(jià)

使用同樣的測(cè)試方式,對(duì)比優(yōu)化前后的游戲運(yùn)行幀率和時(shí)間消耗:

Unity在如何使用Fast Shadow Receiver優(yōu)化渲染效率

優(yōu)化前后的性能消耗對(duì)比

可以看到,使用Fast Shadow Receiver在小米 Max2上有大約7.2ms的性能提升,幀率從26上升到33,這其中有Batch數(shù)量降低的功勞,應(yīng)該也有場(chǎng)景物體不需要采樣ShadowMap貼圖帶來(lái)的渲染性能提升,更加具體的數(shù)據(jù)就沒(méi)有去測(cè)試了。剩余的1.5ms的時(shí)間消耗包括了ShadowMap的繪制以及Fast Shadow Receiver的更新消耗,這是后續(xù)的優(yōu)化對(duì)象,但這次優(yōu)化已經(jīng)有很大的提升了,中配下整體效率提升了20%,已經(jīng)是難得的“神級(jí)優(yōu)化”了。當(dāng)然,這建立在場(chǎng)景通過(guò)關(guān)閉Shadow接收的宏能夠降低較大Batch數(shù)量的前提下。

這次優(yōu)化的收益是很大的,但它也不全是一種無(wú)損優(yōu)化,需要付出的代價(jià)有這么幾點(diǎn):

  1. 美術(shù)工作量。需要美術(shù)同學(xué)針對(duì)場(chǎng)景進(jìn)行地表接收陰影物體的標(biāo)注,雖然提供了快捷的工具,但是依然需要花費(fèi)一些時(shí)間成本。

  2. 部分物體不再會(huì)受到動(dòng)態(tài)陰影的影響。在之前基于ShadowMap的方案中,幾乎所有的物體都可以標(biāo)記為接收陰影,而且可以保證效果的正確性,但是目前這種方案如果要做到這點(diǎn)會(huì)導(dǎo)致Mesh Tree對(duì)于內(nèi)存的占用較多,對(duì)于外部的大世界場(chǎng)景也不適應(yīng),因此會(huì)有出現(xiàn)一些小石頭等物體不會(huì)接收角色陰影的問(wèn)題,這是一些效果的降低,但目前看是可以接受的范圍內(nèi)。

  3. 和靜態(tài)陰影的融合與ShadowMap的方案不同。ShadowMap的方案是在場(chǎng)景繪制的時(shí)候進(jìn)行處理的,一次像素著色的過(guò)程中會(huì)采樣lightmap和shadowmap兩張貼圖,這就可以判斷出該像素點(diǎn)是否在靜態(tài)陰影之中,這樣可以做到比如在屋檐下或者樹(shù)蔭下這樣的靜態(tài)陰影中,角色的實(shí)時(shí)陰影可以和靜態(tài)陰影做一個(gè)較好的融合,如下圖所示。

    Unity在如何使用Fast Shadow Receiver優(yōu)化渲染效率

    基于ShadowMap的方案動(dòng)態(tài)陰影和靜態(tài)陰影的融合效果

    而使用Fast Shadow Receiver方案之后,就比較難做融合的效果,除非在新生成的mesh中保存之前mesh的uv2信息以及使用的lightmap貼圖信息,再做一次lightmap的采樣。但這比較麻煩,性價(jià)比也不高,于是在靜態(tài)隱形中的角色動(dòng)態(tài)陰影的效果就變成了如下圖所示的樣子。

    Unity在如何使用Fast Shadow Receiver優(yōu)化渲染效率

    使用Fast Shadow Receiver方案的效果

除了這些之外的代價(jià)就是程序這邊花費(fèi)了大約半個(gè)多星期的時(shí)間來(lái)學(xué)習(xí)和集成這套方案,但是從優(yōu)化結(jié)果上看,還是收獲很大,非常值得的~

6. 一個(gè)Projector同時(shí)處理多個(gè)角色的動(dòng)態(tài)陰影

由于我們是類似回合制的抽離式戰(zhàn)斗方式,即玩家進(jìn)入戰(zhàn)斗后整場(chǎng)戰(zhàn)斗都會(huì)發(fā)生在一小塊固定區(qū)域內(nèi),這里其實(shí)對(duì)于ShadowMap結(jié)合Fast Shadow Receiver的方案是一個(gè)非常合適的應(yīng)用場(chǎng)景——只需要在進(jìn)入戰(zhàn)斗前生成一次陰影接收的面片,整場(chǎng)戰(zhàn)斗中都不需要對(duì)其進(jìn)行修改和變動(dòng)
我們將LightProjector的Target鎖定為戰(zhàn)斗的中心區(qū)域點(diǎn),然后通過(guò)修改Bound的方式擴(kuò)大其投射范圍到整個(gè)戰(zhàn)場(chǎng)。前面已經(jīng)討論過(guò)基于Projector的動(dòng)態(tài)陰影方案的一個(gè)問(wèn)題是當(dāng)projector較大的時(shí)候rt的使用率較低,導(dǎo)致陰影質(zhì)量驟降的問(wèn)題,但因?yàn)槲覀兪褂玫氖荢hadowMap的陰影方案,因此擴(kuò)大Projector的范圍并不會(huì)影響陰影精度,也不需要處理多個(gè)Projector帶來(lái)rt數(shù)量、draw call增加等問(wèn)題。

Unity在如何使用Fast Shadow Receiver優(yōu)化渲染效率

戰(zhàn)場(chǎng)中多個(gè)角色公用一個(gè)LightProjector的方案

7. 總結(jié)和展望

Fast Shadow Receiver這種通過(guò)CPU的實(shí)時(shí)計(jì)算來(lái)?yè)Q取GPU的渲染性能的方案,正好解決了我們場(chǎng)景靜態(tài)合批被動(dòng)態(tài)陰影打斷的問(wèn)題,大大提升了我們游戲在中配下的幀率,是近期所做的優(yōu)化中效果最為顯著的一個(gè)了,因此也記錄一下詳細(xì)的過(guò)程在這里分享出來(lái)。
對(duì)于這個(gè)插件的感覺(jué),在這一周的逐漸熟悉、應(yīng)用、修改的過(guò)程中,也從心存懷疑到由衷贊嘆。目前針對(duì)這個(gè)插件的魔改還不多,除了前面提到的增加Tag的支持、建立Mesh Tree的時(shí)候缺少一些對(duì)于資源的錯(cuò)誤兼容之外,只修改了部分Component的默認(rèn)參數(shù),更加適合我們項(xiàng)目的設(shè)定,讓美術(shù)和程序可以更加方便地使用。它在運(yùn)行時(shí)對(duì)于內(nèi)存的分配和CPU的性能消耗也讓我們滿意,因此在這里也幫這個(gè)插件做一下廣告——?jiǎng)e被它的文檔和使用過(guò)程嚇到,用好之后,你的游戲效率可以獲得很大的提升~

至于未來(lái),當(dāng)中配下的效果和效率都被驗(yàn)證可以接受之后,可能考慮優(yōu)化一些它的效果,將它也應(yīng)用到高配下,當(dāng)然,對(duì)于貼花等需要處理高低不平地面效果的地方,也可以考慮使用這個(gè)插件進(jìn)行效率的優(yōu)化。

PS:從Fast Shadow Receiver的啟發(fā)來(lái)思考場(chǎng)景靜態(tài)合批被打斷的問(wèn)題,其實(shí)另外一個(gè)思路是自己來(lái)做哪些物體需要被接受陰影的判斷。Unity內(nèi)部肯定也是有這樣的判定邏輯來(lái)設(shè)置各個(gè)場(chǎng)景Render的宏,由于Shadow的距離設(shè)定較大,Unity的判定范圍也過(guò)廣,導(dǎo)致了雖然我們?cè)谥信湎轮挥薪巧秩娟幱?,但是接收陰影的物體數(shù)量過(guò)多,從而導(dǎo)致Batch被頻繁打斷的問(wèn)題。仿照Fast Shadow Receiver,使用一個(gè)跟隨角色的投影,和場(chǎng)景物體相交來(lái)判斷有哪些物體需要被設(shè)置為接收陰影,由于角色腳下的物體可能只會(huì)有幾個(gè),因此Batch的數(shù)量也只會(huì)增加幾個(gè)。目前沒(méi)有沿著這個(gè)思路來(lái)做的原因之一也是地表物體的面數(shù)實(shí)在是有點(diǎn)多,F(xiàn)ast Shadow Receiver對(duì)于面數(shù)的降低也是我們想要的優(yōu)化之一。

關(guān)于Unity在如何使用Fast Shadow Receiver優(yōu)化渲染效率就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI