王禰:虛幻引擎5的開(kāi)發(fā)路線圖及技術(shù)解析(虛幻引擎5宣傳片)
2021年11月22日-24日,由騰訊游戲?qū)W堂舉辦的第五屆騰訊游戲開(kāi)發(fā)者大會(huì)(Tencent Game Developers Conference,簡(jiǎn)稱TGDC)在線上舉行。本屆大會(huì)以“Five by Five”為主題,邀請(qǐng)了海內(nèi)外40多位行業(yè)嘉賓,從主論壇、產(chǎn)品、技術(shù)、藝術(shù)、獨(dú)立游戲、市場(chǎng)及游戲社會(huì)價(jià)值7大專場(chǎng)共同探討游戲產(chǎn)業(yè)趨勢(shì)和多元價(jià)值,以開(kāi)發(fā)者視角與需求為出發(fā)點(diǎn),助力游戲行業(yè)良性發(fā)展,探索游戲的更多可能性。
大家好,我是來(lái)自Epic Games中國(guó)的首席引擎開(kāi)發(fā)工程師王禰,主要負(fù)責(zé)引擎相關(guān)技術(shù)的開(kāi)發(fā)者支持工作,幫助國(guó)內(nèi)的開(kāi)發(fā)者解決各種使用UE開(kāi)發(fā)項(xiàng)目時(shí)遇到的技術(shù)問(wèn)題,同時(shí)也會(huì)參與部分引擎工作的開(kāi)發(fā)。
今天我主要為大家介紹UE5的新功能。當(dāng)然,UE5有太多新功能了,我會(huì)挑大家最關(guān)心的Nanite和Lumen多講一些。
在開(kāi)發(fā)UE5的時(shí)候,我們的目標(biāo)是:提高各方面的渲染品質(zhì),讓構(gòu)建的數(shù)字世界更動(dòng)態(tài)一些,提高整個(gè)虛擬世界構(gòu)建和表現(xiàn)的上限;同時(shí)我們也希望提高開(kāi)發(fā)和迭代的效率,提供更多更豐富易用的工具,改善用戶編輯和創(chuàng)造的體驗(yàn),降低大家使用的門檻。
相比UE4,UE5做了大量改進(jìn),主要是Nanite和Lumen等渲染技術(shù),構(gòu)建整個(gè)大世界的工具以及底層對(duì)渲染大量對(duì)象生成一些Proxy Mesh技術(shù)。
在協(xié)同工作方面,改進(jìn)包括管理大量資產(chǎn)的性能、編輯器和用戶體驗(yàn)、次世代的一些動(dòng)畫技術(shù)Chaos、網(wǎng)絡(luò)同步的物理系統(tǒng),以及一些全新模塊、游戲框架、AI集群系統(tǒng)、進(jìn)一步完善的Niagara系統(tǒng)以及各種音頻模塊,像Meta Sound之類的功能都有非常大的改善。
Nanite功能
首先是我們主打功能之一的Nanite,Nanite是全新的Mesh表示形式,是一種虛擬微表面幾何體,解放了之前美術(shù)同學(xué)制作模型時(shí)對(duì)大量細(xì)節(jié)的限制,現(xiàn)在可以直接使用真正用于影視級(jí)別的資產(chǎn),幾百萬(wàn)甚至上億面的模型直接可以導(dǎo)入到引擎中,非常順暢的放很多的實(shí)例去高效的渲染。
例如來(lái)自照片建?;蛘遉brush雕刻的高模,或者CAD的數(shù)據(jù)都可以直接放進(jìn)來(lái),我們有過(guò)測(cè)試可能幾萬(wàn)甚至十幾萬(wàn)的,這些實(shí)例每個(gè)都是百萬(wàn)面以上的都在view內(nèi)能被看到的情況下,用Nanite的方式渲染依然能在2080s這樣的GPU上跑到60fps,分辨率可能是1080P左右。Nanite還在開(kāi)發(fā)中,還有很多功能支持并不完善,我們?cè)诤罄m(xù)會(huì)慢慢改進(jìn)。
Nanite支持的平臺(tái)主要是新一代的主機(jī)和PC,相比去年我們放出來(lái)的Lumen in the land of Nanite ,這項(xiàng)技術(shù)的品質(zhì)和效率都有不少提升,包括磁盤的編解碼效率和壓縮、支持Lightmap烘焙光照、支持可破碎物體、對(duì)光線追蹤場(chǎng)景或者物理碰撞支持自動(dòng)生成減面高質(zhì)量的替代Proxy mesh。
另外通過(guò)這種方式,我們還可以用解析微分法決定像素誤差,使誤差肉眼不可見(jiàn)。最后,我們還高效支持了多光源投影,整個(gè)Nanite管線基于GPU driven的管線產(chǎn)生,主要流程我會(huì)分以下幾個(gè)部分來(lái)講。
為了讓大量對(duì)象在場(chǎng)景上高效剔除,我們需要把所有場(chǎng)景數(shù)據(jù)都送到GPU上。其實(shí)從4.22開(kāi)始,引擎就慢慢在不影響上層使用的情況下,在底層做出改進(jìn)了,使渲染器成為retained mode,維護(hù)了完整的GPU scene,Nanite在這個(gè)基礎(chǔ)上做了大量新的工作。
Nanite中cluster的生成
接下來(lái)我們簡(jiǎn)單講講Nanite的工作機(jī)制。首先在模型導(dǎo)入時(shí),我們會(huì)做一些預(yù)處理,比如按128面的cluster做切分處理。有了這些cluster以后,我們就可以在距離拉遠(yuǎn)拉近時(shí),做到對(duì)每個(gè)cluster group同時(shí)切換,讓肉眼看不到切換lod導(dǎo)致的誤差沒(méi)有crack,同時(shí)還能對(duì)這些不同層級(jí)、細(xì)節(jié)的cluster做streaming,這其實(shí)就是Nanite最關(guān)鍵的部分。
cluster的生成主要分以下幾步:首先,原始的mesh lod0數(shù)據(jù)進(jìn)來(lái)后,我們會(huì)做一個(gè)graph partition。partition條件是比如說(shuō)我希望共享的邊界盡可能少,這樣我在lock邊界做減面處理時(shí),減面的質(zhì)量會(huì)更高一些。
第二是希望這些面積盡可能均勻、大小一致,這樣在lod計(jì)算誤差處理投影到屏幕上時(shí),都是對(duì)每個(gè)cluster或cluster group一致處理。我們會(huì)把其中一組cluster合并成一個(gè)cluster group,又一次按照“l(fā)ock的邊界盡可能少、面積盡可能均勻”的條件找出,一組組cluster生成group,對(duì)這個(gè)group內(nèi)cluster的邊解鎖,等于把這組group看成一個(gè)大的cluster,然后對(duì)這組group做對(duì)半的減面。
減完面后,我們可以得到一個(gè)新的cluster誤差,我會(huì)對(duì)這個(gè)減面的group重新做cluster劃分。這時(shí),cluster的數(shù)量在同一個(gè)group里其實(shí)就已經(jīng)減半,然后我會(huì)計(jì)算每個(gè)新的cluster誤差。大家要注意,這個(gè)過(guò)程是循環(huán)的,遞歸一直到最終值 ,對(duì)每個(gè)instance、模型只生成一個(gè)cluster為止。這里有一個(gè)比較關(guān)鍵的點(diǎn):我們?cè)跍p面生成每個(gè)cluster時(shí),會(huì)通過(guò)減面算法(QEM)得到這個(gè)cluster的誤差值并存下。
除此之外,我們還會(huì)存group的誤差值,這個(gè)值其實(shí)就是更精細(xì)的那一級(jí)cluster group里cluster的最大誤差值,和我新一級(jí)里產(chǎn)生的每個(gè)cluster誤差值取maximum得到的值。這樣我就能保證這個(gè)cluster每次合并的group,去減面到上一級(jí)的group里的cluster時(shí)的誤差值,永遠(yuǎn)是從不精細(xì)到精細(xì)慢慢上升的狀態(tài)。
也就是說(shuō),我從最根結(jié)點(diǎn)的cluster慢慢到最細(xì)的cluster,里面的error一定是降序排序的。這一點(diǎn)很重要,因?yàn)樗鼙WC后續(xù)選擇culling和lod時(shí),恰好是在一個(gè)cluster組成的DAG上。因?yàn)閏luster會(huì)合并group,group生成打散以后在下一級(jí)里,又會(huì)有一個(gè)共享的cluster。
有了這個(gè)降序排列的誤差,我就能保證這個(gè)DAG上有一刀很干凈的cut,使我的邊界一定是跨lod的cluster group的邊界。最后,我們對(duì)這個(gè)生成的各個(gè)lod層級(jí)的cluster分別生成bvh,再把所有l(wèi)od的cluster的bvh的root,掛到總的bvh root上。
當(dāng)然,這里還有很多額外處理,現(xiàn)在沒(méi)有講是考慮到做streaming時(shí)的一些分頁(yè)處理。這個(gè)分頁(yè)可能會(huì)對(duì)cluster group造成切割,所以cluster group,還有一些group partition的概念,我們這里不做細(xì)化。
另外,對(duì)于一些微小物體離得很遠(yuǎn)以后的情況,我們減到最后一級(jí)cluster,其實(shí)它還是有128個(gè)面,那如果場(chǎng)景里非常小的東西位于很遠(yuǎn)的地方,這又是一個(gè)模塊化的構(gòu)成。我們又不能直接把它c(diǎn)ulling掉,這種情況下,我們會(huì)有另外一種Imposter atlas的方式,這里我也不展開(kāi)講了。
Nanite裁剪流程
最后裁減到它bvh的葉子節(jié)點(diǎn),其實(shí)就是我們剛才說(shuō)的cluster group,然后再對(duì)其中的cluster做裁減。裁減完之后,我們就會(huì)有一個(gè)特殊的光柵化過(guò)程,然后我們就能得到新的Depth Buffer,重新構(gòu)建HZB,再對(duì)這個(gè)新的HZB做一遍裁減。
前面那次HZB的可見(jiàn)性,我們用了上一幀可見(jiàn)的instance來(lái)做,做完之后形成新的HZB,我們?cè)侔焉弦粠豢梢?jiàn)的,在這一幀內(nèi)所有剩下的再做一遍,就能保守地保證沒(méi)有什么問(wèn)題。
重新經(jīng)過(guò)光柵化后,生成到新的visibility buffer,再?gòu)膙isibility buffer經(jīng)過(guò)material pass,最終合入Gbuffer。具體做culling時(shí)會(huì)有一些問(wèn)題,比如剛才cluster生成時(shí)我們說(shuō)到過(guò),生成cluster group的bvh結(jié)構(gòu),我們?cè)?span id="8fv51tz" class="candidate-entity-word" data-gid="701778">CPU上不會(huì)知道它有多少層。
也就是說(shuō),如果我要去做的話,CPU要發(fā)足夠多的dispatch,這時(shí)比如小一點(diǎn)的物件,它空的dispatch就會(huì)很多,這種情況下GPU的利用率也會(huì)很低。
所以我們選擇了一種叫persistent culling的方法,利用一個(gè)persistent thread去做culling,也就是只做一次dispatch,開(kāi)足夠多的線程,用一個(gè)簡(jiǎn)單的多生產(chǎn)者、多消費(fèi)者的任務(wù)隊(duì)列來(lái)喂?jié)M這些線程。
這些線程從隊(duì)列里執(zhí)行時(shí),每個(gè)node會(huì)在做封層級(jí)別剔除的同時(shí)產(chǎn)生新的node,也就是bvh node,Push back回新的。在可見(jiàn)的children的列表里,我們一直處理這個(gè)列表,直到任務(wù)為空。
這里的處理分為幾種類型:首先在一開(kāi)始的node里,只有我們開(kāi)始構(gòu)建的bvh的節(jié)點(diǎn),直到我一直做剔除,剔除到葉子節(jié)點(diǎn)以后,里面是個(gè)cluster group,再進(jìn)入下一級(jí),就是這個(gè)group里面所有的cluster culling。最后cluster并行獨(dú)立地判斷,自己是否被culling 掉,這里其實(shí)和剛剛lod選擇的條件是一模一樣的。
還記得我剛才說(shuō)的error的單調(diào)性吧?因?yàn)檫@里的cluster中,所有l(wèi)od都是混合在一起的,所以我們每個(gè)cluster在并行處理時(shí),我不知道父級(jí)關(guān)系是什么樣的,但我在每個(gè)cluster上存了自己的誤差,和我整個(gè)group在父一級(jí)上的最大誤差,所以這時(shí)我就知道,如果我自己的誤差足夠小,但是我Parent的誤差不夠小,我就不應(yīng)該被culling掉。
同理,跟我共處一個(gè)cluster group的這些節(jié)點(diǎn),如果它在我上一級(jí)lod里,也就是比較粗的那一級(jí)里,那它的error一定不夠大,所以上面那一級(jí)lod所在的整個(gè)group都會(huì)被拋棄掉,而選中下一個(gè)。
但是下一個(gè)里面,其實(shí)還是可能會(huì)有一些誤差太大的——它的誤差如果足夠大,就意味著它在再下一級(jí)更精細(xì)的地方,肯定屬于另外一個(gè)cluster group。所以它又在下一級(jí)的cluster group里又有一個(gè)邊界,和它下一級(jí)的cluster group邊界接起來(lái)會(huì)沒(méi)有接縫,整個(gè)cluster的選擇就是這樣并行做的。
同時(shí),對(duì)應(yīng)自己cluster group的parent,剛剛我們說(shuō)了,肯定會(huì)被剔除掉。這樣就能保證我們能分cluster group為邊界,去對(duì)接不同lod層級(jí)的cluster,并使經(jīng)過(guò)culling存活下來(lái)的cluster來(lái)到特殊的光柵化階段。
Nanite中的光柵化
由于當(dāng)前圖形硬件假設(shè)了pixel shading rate,肯定是高于triangle的,所以普通硬件光柵化處理器在處理非常的微小表面時(shí),光柵化效率會(huì)很差,完整并行也只能一個(gè)時(shí)鐘周期處理4個(gè)triangle,因?yàn)?×2像素的會(huì)有很多quad overdraw,所以我們選擇使用自己用compute shader實(shí)現(xiàn)的軟件光柵化,輸出的結(jié)果就是Visibility Buffer。
我這里列出的結(jié)構(gòu)總共是64位的,所以我需要atomic64的支持,利用interlocked maximum的實(shí)現(xiàn)來(lái)做模擬深度排序。所以我最高的30位存了depth、instanceID、triangleID。因?yàn)槊總€(gè)cluster128個(gè)面,所以triangleID只要7位,我們現(xiàn)在其實(shí)整個(gè)opaque的Nanite pass,一個(gè)draw就能畫完生成到visibility Buffer,后續(xù)的材質(zhì)pass會(huì)根據(jù)數(shù)量,為每種材質(zhì)分配一個(gè)draw,輸出到Gbuffer,然后像素大小的三角面就會(huì)經(jīng)過(guò)我們的軟件光柵化。
我們以cluster為單位來(lái)計(jì)算,比如我當(dāng)前這個(gè)cluster覆蓋屏幕多大范圍,來(lái)估算我接下來(lái)這個(gè)cluster里是要做軟件光柵化還是硬件光柵化。我們也利用了一些比如浮點(diǎn)數(shù)當(dāng)定點(diǎn)數(shù)的技巧,加速整個(gè)掃描線光柵化的效率。
比如我在subpixel sample的時(shí)候是256,我就知道是因?yàn)檫呴L(zhǎng)是16。亞像素的修正保證了8位小數(shù)的精度,這時(shí)我們分界使用軟光柵的邊界,剛好是16邊長(zhǎng)的三角面片的時(shí)候,可以保證整數(shù)部分需要4位的精度,在后續(xù)計(jì)算中最大誤差,比如乘法縮放導(dǎo)致小數(shù)是8位、整數(shù)是4位,就是4.8。
乘法以后精度縮放到8.16,依然在浮點(diǎn)精度范圍內(nèi),實(shí)際的深度測(cè)試是通過(guò)Visibility buffer高位的30位的深度,利用一些原子化的指令,比如InterlockedMax實(shí)現(xiàn)了光柵化。大家感興趣可以去看看Rasterizer.ush里面有Write Pixel去做了,其實(shí)我們?yōu)榱瞬⑿械貓?zhí)行軟件光柵化和硬件光柵化,最終硬件光柵化也依然是用這個(gè)Write Pixel去寫的。
Nanite中的材質(zhì)處理
有了Visibility buffer后,我們實(shí)際的材質(zhì)pass會(huì)為每種材質(zhì)繪制一個(gè)draw call,這里我們?cè)诿總€(gè)cluster用了32位的材質(zhì)信息去儲(chǔ)存,有兩種編碼方式共享這32位,每個(gè)三角面都有自己對(duì)應(yīng)的材質(zhì)索引,支持最多每個(gè)對(duì)象有64種材質(zhì),所以需要6位去編碼。
普通的編碼方式一共有兩種,一種是fast path直接編碼,這時(shí)只要每個(gè)cluster用的材質(zhì)不超過(guò)三種就可以,比如每一種64個(gè)材質(zhì),我需要用6位來(lái)表示索引是第幾位,用掉3X6=18位還剩下14位,剛好每7位分別存第一,和第二種材質(zhì)索引的三角面片數(shù)的范圍,因?yàn)?位可以存cluster 128個(gè)面, 這是最大范圍了。
前幾個(gè)面索引用第一種,剩下的范圍用第二種,再多出來(lái)的就是第三種。當(dāng)一個(gè)cluster超過(guò)3種材質(zhì)時(shí),我們會(huì)用一種間接的slow path,高7位本來(lái)存第一種材質(zhì),三角面片的范圍的那7位,我們現(xiàn)在padding 0 剩余其中19位存到一個(gè)全局的,材質(zhì)范圍表的Buffer Index,還有6位存Buffer Length,Slow path會(huì)間接訪問(wèn)全局的GPU上的材質(zhì)范圍表,每個(gè)三角面在表里面順著entry找自己在哪一組范圍內(nèi)。
這個(gè)結(jié)構(gòu)里存有兩個(gè)8位三角面index開(kāi)始和結(jié)束,6位(64種)材質(zhì)index,其實(shí)這種方式也很快。大家想一下,其實(shí)我們大部分材質(zhì)、模型,就算用滿64個(gè)材質(zhì),我切成小小的cluster以后,128個(gè)面里你切了好多section,超過(guò)三種材質(zhì)的可能性其實(shí)很低。
這里可以看到不同的繪制對(duì)象,它在Material Index表里面其實(shí)順序是不一樣的,我們需要重新統(tǒng)一映射材質(zhì)ID,也能幫助合并同樣材質(zhì)的shading計(jì)算開(kāi)銷。
在處理Nanite的mesh pass時(shí),我們會(huì)對(duì)每一種material ID做一個(gè)screen quad的繪制,這個(gè)繪制只寫一個(gè)“材質(zhì)深度”,我們用24位存“材質(zhì)深度”可表示幾百萬(wàn)種材質(zhì),肯定是夠了。每一種材質(zhì)有一個(gè)材質(zhì)深度平面,我們利用屏幕空間的小Tile做instanced draw,用深度材質(zhì)的深度平面做depth equal的剔除,來(lái)對(duì)每種材質(zhì)實(shí)際輸出的Gbuffer做無(wú)效像素的剔除。
那為什么要切tile做instanced draw呢?因?yàn)榫退阌糜布鯡arly Z,做了rejection,也還是會(huì)耗一些時(shí)間的。所以如果在vs階段,某個(gè)tile里根本沒(méi)有的材質(zhì)的話,就能進(jìn)一步減少開(kāi)銷,具體可以看ExportGbuffer.usf里的FullScreenVS這里的處理。
Nanite中的串流
處理完渲染部分,我們來(lái)看看串流。因?yàn)闀r(shí)間關(guān)系,我這里可能要稍微簡(jiǎn)化一下:因?yàn)橘Y源很大,我們希望占用內(nèi)存是比較固定的,有點(diǎn)類似VT這種概念。但是geometry對(duì)比virtual texture有特殊的challenge。
還記得之前l(fā)od選擇的時(shí)候我們說(shuō)過(guò),最終結(jié)果剛好是讓DAG上有一個(gè)干凈的Cut,所以如果數(shù)據(jù)還沒(méi)進(jìn)來(lái),這個(gè)cut就不對(duì)了,我們也不能在cluster culling時(shí)加入已有數(shù)據(jù)信息的判斷,只能在runtime去patching這個(gè)實(shí)際的數(shù)據(jù)指針。
所以我們保留了所有用來(lái)culling的層級(jí)信息,讓每個(gè)instance加載的時(shí)候都在GPU里面,只streaming實(shí)際用到的geometry的細(xì)節(jié)數(shù)據(jù)。這樣做有很多好處——在新的對(duì)象被看到的一瞬間,我們最低一級(jí)的root那一級(jí)的cluster還是有的,我們就不用一級(jí)一級(jí)請(qǐng)求。
并且我有整個(gè)cluster表,所以我可以在一幀中就準(zhǔn)確知道,我feedback時(shí)實(shí)際要用到的那些cluster實(shí)際層級(jí)的數(shù)據(jù)。整個(gè)層級(jí)信息本身是比較小的,在內(nèi)存里的占用,相對(duì)來(lái)說(shuō)不那么可觀。
回憶之前culling的過(guò)程可以知道,我們?cè)趕treaming粒度最小的時(shí)候, 也是在cluster group層級(jí)的,所以我們的streaming會(huì)按照我剛剛說(shuō)的cluster group來(lái)切配置。因?yàn)橛行┣懈畹倪吔缱詈檬窃赾luster group的中間,所以我們會(huì)有一些partial group的概念,在最后讓GPU發(fā)出請(qǐng)求。
在哪個(gè)cluster group里,我就發(fā)這個(gè)group所在的那個(gè)page。如果我是partial的切到幾個(gè)page,我就會(huì)同時(shí)發(fā)這幾個(gè)page的請(qǐng)求。加載完之后,我會(huì)重新在GPU上patch,我剛剛整個(gè)culling的算法,條件如果變成了是葉子節(jié)點(diǎn),我剛剛說(shuō)的誤差滿足條件里還有一個(gè)并行條件——是不是葉子節(jié)點(diǎn)。
除了真的lod0的cluster是葉子節(jié)點(diǎn),還有就是我現(xiàn)在沒(méi)有填充patch完、沒(méi)有加載進(jìn)來(lái)的時(shí)候,內(nèi)存里最高、最精細(xì)的那一級(jí)是什么?也是葉子節(jié)點(diǎn),總體概念就是這樣的。
Nanite中的壓縮
實(shí)際上,我們?cè)谟脖P里利用了通用的壓縮,因?yàn)榇蟛糠值闹鳈C(jī)硬件都有LZ77這類通用的壓縮格式,這種壓縮一般都是基于重復(fù)字串的index length編碼,把長(zhǎng)字符串和利用率高的字符串利用Huffman編碼方式。
按頻度來(lái)做優(yōu)化的,我們其實(shí)可以重新調(diào)整。比如在我們切成cluster以后,每個(gè)cluster的index buffer是高度相似的,我們的vertex 在cluster的局部位移又很小,所以我們可以做大量的position量化,用normal八面體編碼把vertex的所有index排到一起,來(lái)幫助重復(fù)字符串的編碼和壓縮。
其實(shí)我們每個(gè)三角形就用一個(gè)bit,表示我這個(gè)index是不是不連續(xù)下去要重新開(kāi)始算,并且另外一個(gè)bit表示重新開(kāi)始算的朝向的是減還是加,這樣頂點(diǎn)數(shù)據(jù)跨culster的去重,做過(guò)這樣的操作后,我們磁盤上的壓縮率是非常非常高的。當(dāng)然,我們還在探索進(jìn)一步壓縮的可能性。
Nanite的未來(lái)與其他
由于時(shí)間關(guān)系, 借助Nanite其他的一些feature,尤其是Virtual Shadow Map,我們可以高效地通過(guò)Nanite去做多個(gè)view的渲染,并且?guī)秙hadow的光源——每個(gè)都有16k的shadowmap,自動(dòng)選擇每個(gè)texel投到屏幕一個(gè)pixel的精度,應(yīng)該在哪個(gè)miplevel里面,并且只渲染屏幕可見(jiàn)像素到shadowmap,效率非常高,具體細(xì)節(jié)這里就不詳細(xì)講了。
接下來(lái)我們看看Nanite未來(lái)有什么樣的計(jì)劃:盡管我們目前只支持了比如純opaque的剛體幾何類型,對(duì)于微小物體,最后我們還是會(huì)用Imposter的方式來(lái)畫,但是在超過(guò)90%的情況下,場(chǎng)景中其實(shí)都是全靜態(tài)對(duì)象。
所以目前的Nanite,其實(shí)已經(jīng)能處理復(fù)雜場(chǎng)景的渲染,在大部分情況下都能起到非常大的作用。至于那些不支持的情況,我們依然會(huì)走傳統(tǒng)管線,然后整合起來(lái)。當(dāng)然,這遠(yuǎn)沒(méi)有達(dá)到我們的目標(biāo),我們希望以后能支持幾乎所有類型的幾何體,讓場(chǎng)景里不再有概念,不再需要去區(qū)分哪些對(duì)象是啟用了Nanite的,包括植被、動(dòng)畫、地形、opaque、mask和半透。
伴隨Nanite的研究,我們也希望達(dá)成一些新技術(shù),比如核外光線追蹤,就是做到讓實(shí)際ray Tracing的數(shù)據(jù),真的是Nanite已經(jīng)加載進(jìn)來(lái)的細(xì)節(jié)層級(jí)的數(shù)據(jù)。當(dāng)然,離屏的數(shù)據(jù)可能還是proxy mesh。
另外,因?yàn)槲覀儸F(xiàn)在已經(jīng)不支持曲面細(xì)分了,所以也希望在Nanite的基礎(chǔ)上做微多邊形的曲面細(xì)分。
Lumen
UE5的另一大功能Lumen,是全新的全動(dòng)態(tài)GI和反射系統(tǒng),支持在大型高細(xì)節(jié)場(chǎng)景中無(wú)限次反彈的漫反射GI,以及間接的高光反射,跨度可以從幾公里到幾厘米,一些CVar的設(shè)置甚至可以到5厘米的精度。
美術(shù)和設(shè)計(jì)師們可以用Lumen創(chuàng)建更加動(dòng)態(tài)的場(chǎng)景。譬如做實(shí)時(shí)日夜變化、開(kāi)關(guān)手電筒,甚至是場(chǎng)景變換。比如炸開(kāi)天花板后,光從洞里射進(jìn)來(lái),整個(gè)光線和場(chǎng)景變化都能實(shí)時(shí)反饋。所以Lumen改善了烘焙光照帶來(lái)的大量迭代時(shí)間損失,也不需要再處理lightmap的uv,讓品質(zhì)和項(xiàng)目迭代效率都有了很大提升。
為了跨不同尺度提供高質(zhì)量GI,Lumen在不同平臺(tái)上也適用不同的技術(shù)組合。但是目前Lumen還有很多功能不足正在改善。我們先來(lái)簡(jiǎn)單了解下Lumen的大框架:為了支持高效追蹤,我們除了支持RTX硬件的ray tracing,其他情況下我們也用Lumen在GPU上維護(hù)了完整的簡(jiǎn)化場(chǎng)景結(jié)構(gòu),我們稱之為L(zhǎng)umen scene。
其中部分?jǐn)?shù)據(jù)是離線通過(guò)mesh烘焙生成一些輔助的信息,包括mesh SDF和mesh card,這里的card只標(biāo)記這個(gè)mesh經(jīng)過(guò)grid切分之后,從哪些位置去拍它的一些朝向,和Bounding Box的一些標(biāo)記。
利用剛剛這些輔助信息,和Nanite的多view高效光柵化生成Gbuffer,以及后續(xù)需要用到的其他數(shù)據(jù),運(yùn)行時(shí)會(huì)通過(guò)兩個(gè)層面更新LumenScene:一層是CPU上控制新的Instance進(jìn)來(lái),或者一些合并的streaming的計(jì)算;另一層是更新的GPU數(shù)據(jù),以及更新LumenScene注入,直接和間接Diffuse光照到光照緩存里面。
我們會(huì)基于當(dāng)前屏幕空間放一些Radiance Probe,利用比較特殊的手段去做重要度采樣。通過(guò)高效的Trace probe得到Probe里面的光照信息,對(duì)Probe的光照信息進(jìn)行編碼,生成Irradiance Cache 做spatial filter。
當(dāng)然,接著還會(huì)有一些fallback到global世界空間,最后再Final Gather回來(lái),和全屏幕的bentnormal合成生成,最終全屏幕的間接光照,再在上面做一些temporal濾波。這就是我們Diffuse整個(gè)全屏的光照,最后再跟Direct光照合起來(lái),就得到了最終的渲染結(jié)果。
Lumen中的tracing
Lumen的整體框架是軟件追蹤,靠Mesh SDF來(lái)做快速的Ray Tracing。在硬件允許時(shí),我們會(huì)用RTX,這個(gè)今天不展開(kāi)講。Lumen的追蹤是個(gè)Hybrid的方案,包括優(yōu)先利用HZB做屏幕空間的Trace,如果失敗的話,我們?cè)诮嚯x用一個(gè)全屏做Mesh SDF的Trace,這里因?yàn)镸esh SDF的instance做遍歷效率其實(shí)還比較低。
因?yàn)橛胋vh在GPU上訪問(wèn)時(shí),樹(shù)形結(jié)構(gòu)的緩存一致性很不好,所以我們只在很近距離1.8米內(nèi)做第一層級(jí)的加速結(jié)構(gòu),這時(shí)我們利用一個(gè)簡(jiǎn)單的Froxel去做grid劃分,快速求交所有instance的Bounding Sphere和對(duì)應(yīng)cell相交結(jié)果,并存在對(duì)應(yīng)cell的列表里,這是全屏做一次的。
接下來(lái)在tracing時(shí),我每次只需要訪問(wèn)當(dāng)前tracing點(diǎn),比如marching以后所在的位置,所在的cell就能很快算出來(lái),然后直接查詢里面的instance列表,將第二層加速結(jié)構(gòu)實(shí)際的,以及查出來(lái)列表里instance的SDF,都做一遍marching,取一個(gè)minimum值。
對(duì)于稍遠(yuǎn)一點(diǎn)的,我們會(huì)對(duì)場(chǎng)景做一個(gè)合并生成Global的SDF,它是個(gè)clipmap。但因?yàn)樘岣呔纫院?,?shù)據(jù)存儲(chǔ)等各方面每翻一倍精度會(huì)有8倍增加,我們會(huì)有一些稀疏的表達(dá),我之后會(huì)簡(jiǎn)單講一下。
在都沒(méi)有trace到的情況下,我們會(huì)循環(huán)Global SDF的clipmap,對(duì)每一級(jí)clipmap做loop,直到Global SDF。比如二百多米全都沒(méi)有trace到,那就是miss。當(dāng)然,我們?cè)谥暗腄emo里也用了RSM做最后的fallback,現(xiàn)在這個(gè)版本我們還沒(méi)有放進(jìn)去。
在SDF生成時(shí),tracing我們都會(huì)做一些保守的處理,保證不會(huì)有薄墻被穿透。SDF其實(shí)是個(gè)volumetric,按voxel間隔來(lái)采樣的生成過(guò)程,如果我的面很薄,在你的voxel精度以內(nèi),其實(shí)我們會(huì)有一些保守處理。
Lumen與場(chǎng)景結(jié)構(gòu)
隨之而來(lái)的問(wèn)題是,我們trace到了某個(gè)表面之后,SDF里面沒(méi)有辦法拿到我們實(shí)際需要的數(shù)據(jù),只能幫助快速找到交點(diǎn)位置,這個(gè)時(shí)候我們能拿到什么?近場(chǎng)MeshSDF時(shí)MeshId是我知道的,因?yàn)楸闅v列表的時(shí)候存了;另外我還知道SDF,所以可以靠SDF的gradient算出對(duì)應(yīng)的normal,但是我有ID、normal和位置,要怎樣得到我要的Radiance呢?包括Gbuffer的一些數(shù)據(jù),這時(shí)我們是沒(méi)有三角面片數(shù)據(jù)來(lái)插值計(jì)算的,沒(méi)有各種材質(zhì)的屬性,所以我們需要一種高效的參數(shù)化方法。
我們使用了一種平鋪的CubeMapTree結(jié)構(gòu):首先在Mesh導(dǎo)入時(shí)我們會(huì)預(yù)先處理,剛剛提到生成一組Card的描述,在runtime的時(shí)候,我們對(duì)放在地圖里的每個(gè)實(shí)例,會(huì)根據(jù)mesh的Card信息實(shí)際利用Nanite高效光柵化,生成對(duì)應(yīng)的Gbuffer。
Atlas在一張大的Atlas里面,其實(shí)是幾張里面存了MRT,存了三張——包括albedo,opacity,normal,depth這樣的信息。存的這個(gè)Atlas我們叫做Surface Cache,其實(shí)就是大家最終看到的LumenScene。當(dāng)然,LumenScene還會(huì)經(jīng)過(guò)SDF tracing,然后做tri-planar reprojection,這其實(shí)就是我們 tracing的結(jié)果。
我們tracing時(shí)tracing到哪個(gè)位置,就會(huì)找到它對(duì)應(yīng)三個(gè)方向的Lumen card,把光柵化完的那些信息tri-planar reproject出來(lái),得到的就是這個(gè)點(diǎn)要的信息。包括Gbuffer、Radiance信息。
Radiance信息從哪里來(lái)呢?是在生成這個(gè)card時(shí),還會(huì)做直接的光照注入,然后生成它Irradiance的Atlas,并且這個(gè)Atlas中會(huì)根據(jù)維護(hù)的budget更新對(duì)應(yīng)的Card,從texel出發(fā),利用GlobalSDF去trace上一幀的lighting狀態(tài),也就是上一幀LumenScene的信息。
所以我們用屏幕空間Probe去trace時(shí),trace到的那個(gè)Irradiance cache里的東西,就是多次反彈的結(jié)果。這個(gè)Atlas里card存的cache,其實(shí)都是2的整數(shù)次冪,為了方便我們做mip。因?yàn)槲覀冇行╇A段要用prefilter的mip,利用conetracing快速地做prefiltering結(jié)果的tracing。對(duì)于更遠(yuǎn)的Ray,我們其實(shí)在trace的時(shí)候,就已經(jīng)借助的GlobalSDF,超過(guò)1.8米時(shí),這個(gè)時(shí)候我們也沒(méi)有對(duì)應(yīng)的MeshID了。
所以類似地,在對(duì)應(yīng)生成GlobalSDF的clipmap時(shí),我們也會(huì)用Surface Cache生成一個(gè)voxel Lighting Cache,也就是LumenScene更低精度的voxel的表達(dá)。這個(gè)voxel Scene就是來(lái)自Cube Map Tree預(yù)處理后,radiance合并生成出來(lái)的。
這時(shí)我們每一幀都會(huì)重新生成voxel Lighting Cache,整個(gè)Lumen的結(jié)構(gòu)是持續(xù)存在GPU上的,在CPU上維護(hù)對(duì)它的增減。我們哪些東西重新Streaming進(jìn)來(lái)了,視角調(diào)整以后哪些card變得可見(jiàn),為了控制開(kāi)銷,我會(huì)每幀固定更新一定數(shù)量的card,并且根據(jù)對(duì)應(yīng)的Lighting類型,對(duì)這個(gè)Surface cache做一些裁減。對(duì)于那些tracing時(shí)不在屏幕中的shadow遮擋,我們都是靠Global SDF Trace來(lái)做的。
Final Gather
有了Tracing的手段,又從中獲得了想要的數(shù)據(jù)的信息后,我們就要解決最終的GI問(wèn)題了。傳統(tǒng)模式中,比如Cards里存的是Surface Cache,已經(jīng)有了多次反彈的照度信息,這里我們已經(jīng)把追蹤到的表面緩存不一致的求解計(jì)算分離到Card Capture和Card光照計(jì)算部分,就只需要在屏幕空間直接來(lái)Trace Ray,Trace這些Surface Cache里的Irradiance就可以了。
傳統(tǒng)做RTX GI時(shí),往往只能支撐1-2spp在Gbuffer發(fā)出BentNormal半球空間均勻分布的光線,如果靠SpatialTemporay,方差引導(dǎo)的這種濾波,在光線相對(duì)充足的情況下效果會(huì)非常好,但是當(dāng)光線很不充足,譬如只有一束光從門縫或小窗口照進(jìn)來(lái)時(shí),離遠(yuǎn)一點(diǎn)的地方你Trace出來(lái)的Ray能采樣到,實(shí)際有光源的地方概率太低,導(dǎo)致在濾波前的畫面信息實(shí)在太少,最終濾波完的品質(zhì)也是非常差、不能接受的。
我們的方法,是利用遠(yuǎn)低于Gbuffer分辨率的Screen Space的Probe,約每16個(gè)像素,根據(jù)實(shí)際像素插值失敗的情況下,我們?cè)诟褡永锩孢€會(huì)進(jìn)一步細(xì)化放置,放到一個(gè)Atlas里,我的每個(gè)Probe其實(shí)有8×8個(gè)Atlas,小的一個(gè)八面體投影的就是半球,自己World Space normal的半球,均勻分布我的立體角朝向的那個(gè)Tracing的方向,每一幀我還會(huì)對(duì)這個(gè)采樣點(diǎn)做一些jitter,之后再去插值。
我們也會(huì)在像素平面,將最后全屏每個(gè)像素按照BRDF重要度采樣,找周圍Screen的Probe做跟我方向一致的weight調(diào)整,再去做插值,然后在計(jì)算probe的時(shí)候,我們利用半球投到八面體的方式,存了8×8的像素全都Atlas到一起,在細(xì)化時(shí)一直往下放。
所以最壞的情況,是比如每個(gè)像素都是一個(gè)前景,下一個(gè)像素就是一個(gè)后景——這其實(shí)不太可能,只是極端情況。這種情況我就變成要細(xì)化到每個(gè)像素,又變成逐像素去做這個(gè)tracing的Probe Cache。為了避免這種情況,我們其實(shí)是粗暴地限制了整個(gè)Atlas的大小,也就是最細(xì)化的東西,我填不下就不要了。
這樣的好處是,我按照1/16的精度去做的Screen Probe,其實(shí)是1/256的精度,即使8×8我處理的像素?cái)?shù)還是以前的1/4或者1/8,在做Spatial Filter最后每個(gè)像素插值時(shí),我只要做Screen Probe3×3的filter,其實(shí)就相當(dāng)于以前48×48的filter大小,而且效率很高。并且在求解間接的環(huán)境光蒙特卡洛積分時(shí),可以靠上一幀這些ScreenProbe里reproject回來(lái)的Incoming Radiance的值,作為lighting的importance sampling的引導(dǎo)。
同樣,BRDF也可以這樣做。譬如BRDF值小于0的部分,無(wú)論入射光如何都不會(huì)貢獻(xiàn)出射,隨便這個(gè)方向上lighting在上一幀的incoming radiance。在這個(gè)點(diǎn)上有多少,這個(gè)朝向有光過(guò)來(lái),我貢獻(xiàn)也是0——我不需要它,所以我最終就把這兩個(gè)東西乘到一起,作為我新的這一幀probe的importance sampling的方向。
最后,我就會(huì)根據(jù)這個(gè)方向去tracing,之后radiance會(huì)存到跟它對(duì)應(yīng)起來(lái)另外一張8×8的圖里,Atlas到一起。對(duì)于小而亮的部分離的表面越遠(yuǎn),每幀又有jitter又有方向,引導(dǎo)方向不一樣。有時(shí)沒(méi)追蹤到,它的噪點(diǎn)就會(huì)比較多,并且trace長(zhǎng)度越長(zhǎng)光線的一致性也不好,所以相反離得遠(yuǎn)的光源,相對(duì)貢獻(xiàn)得光照變化頻率也比較低。因?yàn)槲译x的很遠(yuǎn)以后局部光有一些位移,對(duì)我這里的影響是很小的。
所以我們可以用一個(gè)世界空間的probe來(lái)處理,因?yàn)檫@個(gè)時(shí)候可以做大量的cache,這里我的世界空間也是一個(gè)clipmap,它也是稀疏存儲(chǔ)的。因?yàn)橹挥形襍creen Space的Probe Tracing訪問(wèn)不到的東西,我才會(huì)去布置更多的World Space的Probe去做更新處理,這里就不展開(kāi)講了。
最終,我們需要在全分辨率的情況下做積分,這時(shí)有一個(gè)辦法,就是根據(jù)全分辨率像素得到BRDF采樣,方法就是我剛才說(shuō)的,從Screen Probe里面找。比如8×8像素周圍的都去找跟它方向一致的weight去插值,但這樣噪點(diǎn)還是很多,所以我們其實(shí)是從它的mip里面去預(yù)處理,從filter過(guò)的結(jié)果里去找。
這樣還會(huì)有一個(gè)問(wèn)題:我自己朝向的平面,比如8×8像素周圍的都去找跟它方向一致的weight去插值,所以最終我們把八面體的radiance轉(zhuǎn)成了三階球諧,這樣全分辨率的時(shí)候能非常高效的利用球諧系數(shù)做漫反射積分,這樣的結(jié)果質(zhì)量和效率都很好。
最后的最后我們又做了一次,我對(duì)每個(gè)像素都做完之后,再做一次temporal的濾波,但是會(huì)根據(jù)像素追蹤到的位置的速度和深度來(lái)決定我這個(gè)像素的變化,是不是快速移動(dòng)物體區(qū)域投影過(guò)來(lái)的,來(lái)決定我這個(gè)temporal filter的強(qiáng)度。
我temporal filter越弱,其實(shí)就相當(dāng)于前面我去采樣的時(shí)候積分起來(lái)的時(shí)候,我采樣周圍3×3 Spatial Filter效果就越強(qiáng)。整體上Lumen的框架就是這樣,我略過(guò)了大量細(xì)節(jié)和一些特殊處理的部分。譬如半透明物體的GI沒(méi)有講到,Spectular我也沒(méi)有特殊講,但是像spectular在粗糙度0.3到1的情況下,和這里importance sampling的diffuse其實(shí)是一致的。
Lumen的未來(lái)
在未來(lái),我們也希望能做進(jìn)一步改進(jìn),比如鏡面反射,Glossy反射我們已經(jīng)能很好處理,但是鏡面反射在不用硬件追蹤的情況下,現(xiàn)在Lumen效果還是不夠的,包括SkeletalMesh的場(chǎng)景表達(dá)方式、破碎物體的場(chǎng)景表達(dá)方式,以及更好處理非模塊化的整個(gè)物體。因?yàn)楝F(xiàn)在模塊化整體captured card或者SDF的各種精度處理,可能還不夠完善。
我們希望提升植被品質(zhì),以及更快速地支持光照變化,因?yàn)槲覀冇泻芏鄅ard limiter的更新,比如card數(shù)量之類的,會(huì)導(dǎo)致你過(guò)快更新時(shí)跟不上。最后,我們還希望能支持更大的世界,譬如可以串流SDF數(shù)據(jù),以及做GPU driven的Surface Cache。關(guān)于Lumen我們今天就先講到這里。
其他功能與Q&A
講完兩大招牌功能,我們快速過(guò)一下別的功能:比如最常被大家提到的大世界支持。從UE5開(kāi)始我們有了更好的工具,比如World Partition就升級(jí)成了全新的數(shù)據(jù)組織方式,配合一套streaming系統(tǒng),我們不需要手動(dòng)處理runtime的streaming,引擎會(huì)幫你自動(dòng)切分出不同的Partition,自動(dòng)處理加載策略。
而且在這個(gè)基礎(chǔ)上,我們又有Data Layer對(duì)于不同邏輯的處理,有World Partition Stream Policy根據(jù)layer對(duì)不同的Policy的定制,有Level Instance——可以把Level看成Actor、嵌套組成模板、模塊化搭建地圖,并且在Level Instance層級(jí)上設(shè)置Hlod的參數(shù)。
為了協(xié)同工作,我們還引入了One File Per Actor,大家每次在地圖上編輯或新增時(shí),其實(shí)只改到了一個(gè)獨(dú)立的actor所對(duì)應(yīng)的文件,文件鎖的粒度比較細(xì),就不會(huì)去動(dòng)整個(gè)地圖文件,這樣引擎也會(huì)自動(dòng)幫你管理這些散文件的changelist生成。
最后,我們還做了大世界的精度支持,把整個(gè)Transform的各種計(jì)算都改到了雙精度浮點(diǎn)支持。另外,我們?cè)贛obile上也做了更多支持,比如Turnkey全新的打包工作流程,移動(dòng)端延遲渲染也進(jìn)入了beta階段。
除此之外,iOS我們也做了很多改進(jìn),在正式版本我們新增了opengles延遲渲染管線的支持,比如mali上的pixel local storage。同時(shí)我們也加入了DFShadow支持,以及一些新的shading model:例如和pc統(tǒng)一利用Burley SSS參數(shù)驅(qū)動(dòng)的移動(dòng)版本的preintegrated皮膚。
同時(shí)我們終于對(duì)DXC下的半精度做了支持,而且把所有的Metal Vulkan openGLES都用DXC做了轉(zhuǎn)換。同時(shí)我們還加入了point light shadow、CSM cache和帶寬優(yōu)化過(guò)的565的RVT,做了全新的 gpu instance culling和更高效的auto-instancing等功能。
對(duì)于其他的各種平臺(tái),我們Unreal Turnkey工作流是跨所有平臺(tái)開(kāi)發(fā)打包發(fā)布的流程。目標(biāo)是一鍵就把項(xiàng)目發(fā)布到任意支持的平臺(tái)的全新設(shè)備上,自動(dòng)完成所有工具鏈和SDK的安裝部署,從4.25后面版本開(kāi)始我們已經(jīng)支持下一代主機(jī)了,伴隨接下來(lái)《堡壘之夜》在這些平臺(tái)上的優(yōu)化和遷移,UE5上我們對(duì)這些支持會(huì)更完善一些。
在這些主機(jī)平臺(tái)上我們對(duì)體積云、物理場(chǎng)等,包括加載效率 TSR等都做了大量的優(yōu)化。也有大量?jī)?nèi)存優(yōu)化(尤其DX12,buddy allocator改pooling)。rdg insights提供了對(duì)RHI層的每幀中間渲染資源的復(fù)用的這種profiling編輯器。
編輯器我們改善了用戶體驗(yàn),用了比較深色的主題的統(tǒng)一配色,大家可以自己去靈活配置。擴(kuò)大了視窗的利用率,集成Quixel Bridge能方便的瀏覽bridge庫(kù)中的資產(chǎn)并直接拖到場(chǎng)景中。
另外我們也加入了Game Feature plugin,是一個(gè)全新的數(shù)據(jù)驅(qū)動(dòng)的框架,類似之前的游戲框架,現(xiàn)在可以干凈的分離到gamefeature插件里方便的激活和卸載,做Game Features和模塊化的Gameplay,你可以把各種類、數(shù)據(jù)、內(nèi)容以及對(duì)應(yīng)的debug/cheat相關(guān)的內(nèi)容封裝到不同的插件模塊里面,可以針對(duì)性的通過(guò)component來(lái)在特定的Actor上啟用,這樣 gameplay模塊的擴(kuò)展性、重用性、穩(wěn)定性都能有很好的改善。
MetaSounds也是在EA版本就發(fā)布的, 是讓音頻系統(tǒng)有跟渲染管線類似的可編程性的一套工具。類似audio用的shader,所以可以更靈活的使用和操縱原始的音頻數(shù)據(jù)。MetaSounds用來(lái)替換以前比較簡(jiǎn)陋的soundcue,可以更高效、更靈活、更可擴(kuò)展,Quartz 是暴露給bp系統(tǒng)的一套用來(lái)精確采樣音頻數(shù)據(jù)和事件的系統(tǒng),可以讓你完善地完成類似吉他英雄這種的需要非常準(zhǔn)確的幀時(shí)間的采樣音效、同步控制的這樣一套系統(tǒng)。
另外我們還有別的一套系統(tǒng)(Audio Synesthesia),可以幫助你離線也可以實(shí)時(shí)對(duì)音頻做分析,然后把音頻做可視化。比如利用niagara或者材質(zhì)做可視化。
chaos的物理系統(tǒng),在UE5開(kāi)始我們整個(gè)物理系統(tǒng)都會(huì)切換到chaos,它的一大目標(biāo)是能有更多的gameplay的交互接口,跟gameplay系統(tǒng)結(jié)合更緊密,并且支持網(wǎng)絡(luò)同步。Early Access版本中我們Rigid body模擬已經(jīng)修了很多bug,減少了碰撞對(duì)的生成、預(yù)先做了更多剔除、修復(fù)了一些查詢巨大三角面時(shí)的錯(cuò)誤結(jié)果、改進(jìn)了超高速移動(dòng)物體或很低幀數(shù)下默認(rèn)啟用CCD時(shí)不正常的效果、也改了ragdoll模擬穩(wěn)定性的一些bug。
在正式版本中,對(duì)于PBD的性能和穩(wěn)定性做了更多優(yōu)化,做了很好的載具的支持,并且支持網(wǎng)絡(luò)同步的物理模擬的框架。然后還有各種特殊的solver,比如布料和流體的模擬也得到了增強(qiáng)和改善。
關(guān)于整套Unreal Insights工具,我們改善了現(xiàn)有的Timing, Loading, Network和Animation 的功能,同時(shí)新版本里面還有Memory Insights。通過(guò)Memory Insights,我們能按照LLM的方式按類型來(lái)看內(nèi)存是怎么分配的,然后我們?nèi)绻覯emory Malloc這樣一個(gè)參數(shù)的話,Memory Insights還可以幫助大家看到所有的調(diào)用、堆棧、分類 甚至查Memory Leak。有很多這種好用的工具,剛剛也說(shuō)到RDG Insights,來(lái)看整個(gè)渲染的管線資源分配、復(fù)用、生命周期各種各樣比較好用的功能。
最后是Meta Human Creator,高質(zhì)量的數(shù)字人創(chuàng)建工具,可以幫助小團(tuán)隊(duì)在幾分鐘或者幾小時(shí)內(nèi)就創(chuàng)作出3A品質(zhì)的、帶完整rigging,可以用來(lái)做動(dòng)畫的數(shù)字角色。伴隨UE5的發(fā)布,我們MHC的創(chuàng)建角色在引擎里面會(huì)有更多更好的表現(xiàn)。這樣品質(zhì)的數(shù)字角色本來(lái)只在3A作品里能看到,現(xiàn)在每個(gè)人都能制作,并且通過(guò)bridge直接在content browser拓出來(lái),在引擎里面使用。
Q & A
UE5.0正式版會(huì)在什么時(shí)候發(fā)布?
王禰:目前預(yù)計(jì)是明年上半年,可能在4月份左右發(fā)布。
UE5.0之后還會(huì)支持曲面細(xì)分嗎?
王禰:由于不少硬件平臺(tái)曲面細(xì)分效率的問(wèn)題,我們打算徹底去掉。未來(lái)我們會(huì)嘗試用Nanite去做,但是目前還沒(méi)有做到。所以現(xiàn)在的workaround如果不做變形,那就只能靠Nanitemesh或者靠Virtual Heightfield Mesh來(lái)處理。