夜夜躁很很躁日日躁麻豆,精品人妻无码,制服丝袜国产精品,成人免费看www网址入口

網(wǎng)易首頁(yè) > 網(wǎng)易號(hào) > 正文 申請(qǐng)入駐

《戀與深空》引擎工程師的一次純技術(shù)分享

0
分享至

在今天舉行 的 第十屆Unite開(kāi)發(fā)者大會(huì),《戀與深空》的引擎工程師們首次對(duì)游戲進(jìn)行深度技術(shù)分享,這是疊紙非常少有的在公開(kāi)場(chǎng)合的內(nèi)容分享,現(xiàn)場(chǎng)可以說(shuō)是座無(wú)虛席。

會(huì)議結(jié)束后,疊紙官方也將今天現(xiàn)場(chǎng)的內(nèi)容發(fā)到了官方公眾號(hào)【疊紙游戲招聘】中,我們將本文完整的轉(zhuǎn)發(fā)出來(lái),希望有更多的行業(yè)精英可以看到這次的技術(shù)“干貨”。

以下為《戀與深空》技術(shù)分享完整內(nèi)容回顧:


《戀與深空》渲染底層框架的分享內(nèi)容主要涵蓋【場(chǎng)景渲染優(yōu)化、光照方案與管線設(shè)計(jì)、陰影優(yōu)化】三部分。在開(kāi)發(fā)過(guò)程中,我們基于Unity 2019對(duì)引擎源碼進(jìn)行深度修改,開(kāi)發(fā)了一套自定義的SRP管線。目前Android線上版本為GLES 3.1,未來(lái)也將上線Vulkan版本,持續(xù)提升性能,滿(mǎn)足玩家對(duì)高品質(zhì)游戲的需求。

1. 場(chǎng)景渲染優(yōu)化

在場(chǎng)景渲染優(yōu)化中,我們開(kāi)發(fā)了一套名【RendererGroupRenderer】的場(chǎng)景渲染系統(tǒng),將每個(gè)渲染批次稱(chēng)之為一個(gè)RenderGroup。通過(guò)這套系統(tǒng)我們實(shí)現(xiàn)了以下功能:

  • 自定義靜態(tài)場(chǎng)景描述:我們?nèi)コ鼼ameObject,避免了更新大量GameObject時(shí)帶來(lái)的性能損耗。

  • 優(yōu)化CPU→GPU Upload 頻率:主要包括InstanceData和ConstantBuffer的Upload。關(guān)于InstanceData的Upload優(yōu)化,我們?cè)陧?xiàng)目初期針對(duì)室內(nèi)小規(guī)模場(chǎng)景,采用的是靜態(tài)生成InstanceDataBuffer,配合BVH分割裁剪的形式。隨著項(xiàng)目推進(jìn),場(chǎng)景精度要求不斷提高,后期便轉(zhuǎn)向在GPU端完成裁剪與instance填充。ConstantBuffer的Upload優(yōu)化將在后面【單DrawCall性能優(yōu)化】部分進(jìn)行詳細(xì)說(shuō)明。

  • CPU側(cè)Burst+Job System并行粗裁剪:對(duì)靜態(tài)物件我們通過(guò)Burst+Job System實(shí)現(xiàn)了一套高度并發(fā)的裁剪系統(tǒng),同時(shí)只在CPU側(cè)進(jìn)行粗略的裁剪,將細(xì)粒度的裁剪任務(wù)交由GPU完成。

InstanceData數(shù)據(jù)形式

業(yè)界常用Constant Buffer形式的InstanceData存在一些缺點(diǎn),比如64KB 尺寸限制、常量緩存小、動(dòng)態(tài)索引時(shí)容易發(fā)生緩存擊穿導(dǎo)致性能下降等。另一種常用形式是用SSBO來(lái)傳遞InstanceData,但這種方法讀取性能通常不如緩存未擊穿情況下的ConstantBuffer,并且部分安卓設(shè)備在GLES下不支持在vertex shader中讀取SSBO,這也限制了它的兼容性。同時(shí)這兩個(gè)方案都有共同的問(wèn)題:依賴(lài)動(dòng)態(tài)索引,對(duì)低端手機(jī)性能不友好。

針對(duì)以上問(wèn)題,我們提出了一種“新瓶裝舊酒”的方案——Vertex Stream based Instance Data

  • 使用PerInstance Step的Vertex Stream作為Instance Buffer;

  • 走Vertex Fetch緩存,無(wú)需動(dòng)態(tài)索引,Cache命中率高,無(wú)兼容性問(wèn)題;

  • 通過(guò)ComputeShader向Instance VertexBuffer輸出,實(shí)現(xiàn)GPU Driven。

使用PerInstance Step的Vertex Stream作為Instance Buffer——這是一種在GPU Instancing誕生之初就被支持的Instance方法,既可以避免動(dòng)態(tài)索引帶來(lái)的性能問(wèn)題,也避免了SSBO的兼容性問(wèn)題。我們還可以通過(guò)ComputeShader向Instance VertexBuffer輸出來(lái)實(shí)現(xiàn)GLES下兼容性較高的GPU Driven。

最后,由于Unity引擎在底層沒(méi)有支持PerInstance Step的Vertex Stream,我們對(duì)引擎也做了相應(yīng)的定制,最終暴露給上層的是CommandBuffer中添加的一個(gè)DrawMeshInstancedTraditional接口,它需要將另一個(gè)mesh作為instance data傳進(jìn)來(lái)。我們也加了相應(yīng)的接口來(lái)配置instance mesh中各個(gè)數(shù)據(jù)段對(duì)應(yīng)的頂點(diǎn)semantic。

GPU Driven

我們會(huì)依據(jù)Group數(shù)量與Instance數(shù)量,提前分配IndirectParameter Buffer與Instance Data Buffer(這里Instance Data Buffer只是提前分配了空間,實(shí)際的數(shù)據(jù)為GPU Cull時(shí)填入)。

同時(shí),我們會(huì)預(yù)計(jì)算每個(gè)Group的Instance Offset,并將其存儲(chǔ)到Parameter的InstanceStart項(xiàng),全程只綁定一份Instance Buffer。


此外,我們還需要生成逐物件信息Buffe(包含GroupID、LOD Distance Range、Bounds、Transform等信息),用于在GPU裁剪時(shí)獲取每個(gè)物件的屬性。

  • CPU剪裁:在GPU裁剪之前,我們會(huì)先執(zhí)行一次CPU粗裁剪,以判斷Group整體是否可見(jiàn)。從一個(gè)根包圍盒開(kāi)始,比較物件包圍盒體積總和與合并后包圍盒的體積比值,低于閾值就遞歸分裂包圍盒(主要目的為避免兩個(gè)物件距離過(guò)遠(yuǎn),拉出一個(gè)超大總包圍盒的情況發(fā)生)。同時(shí)結(jié)合PVS進(jìn)一步判斷Group的可見(jiàn)性,因?yàn)槲覀儧](méi)有類(lèi)似DX12的IndirectExecute,我們的GPU裁剪只能減少instance數(shù),并不能消除Group整體的drawcall,因此需要,通過(guò)CPU裁剪盡可能準(zhǔn)確地剔除掉完全不可見(jiàn)的Group。

  • GPU剪裁:GPU裁剪則通過(guò)一次dispatch對(duì)所有Group進(jìn)行逐物件3段裁剪,包含視錐裁剪、LOD裁剪、Hiz遮擋剔除,通過(guò)裁剪將Parameter的Instance Count加1,并輸出InstanceData。

  • 陰影剔除:我們參考了龍之教條分享的方法,將畫(huà)面深度重投影到陰影空間作為Shadow Reveiver Mask,若Shadow Caster投出的Volume與Mask不相交,就可剔除避免多余陰影渲染。

此外關(guān)于我們“為什么沒(méi)有實(shí)現(xiàn)Cluster/Meshlet”部分,首先它在移動(dòng)端存在較大基礎(chǔ)開(kāi)銷(xiāo),其次在GLES下實(shí)現(xiàn)Cluster也存在兼容性問(wèn)題。綜合考慮下,我們認(rèn)為優(yōu)先優(yōu)化單DrawCall的性能更能為我們帶來(lái)免費(fèi)且直接的性能提升。

單DrawCall性能優(yōu)化

在過(guò)往的觀察中,我們發(fā)現(xiàn)許多對(duì)于渲染的CPU耗時(shí)優(yōu)化往往過(guò)于關(guān)注DrawCall數(shù)量,而忽視了每個(gè)DrawCall本身的耗時(shí)。我們認(rèn)為降低DrawCall數(shù)量只是一種優(yōu)化方法,最終的CPU耗時(shí)才是唯一的衡量指標(biāo)。

現(xiàn)代移動(dòng)設(shè)備與圖形標(biāo)準(zhǔn)其實(shí)早就可以勝任大量drawcall,這部分在HypeHype引擎團(tuán)隊(duì)在Siggraph 2023中也有過(guò)分享——他們?cè)趇phone 6s上測(cè)試了一萬(wàn)個(gè)不同Mesh與材質(zhì)的DrawCall,耗時(shí)僅有11.27ms。其他同等的安卓設(shè)備也都基本能維持在60幀以上。而在2014年Metal剛剛誕生時(shí),也提出過(guò)比GLES多畫(huà)10倍DrawCall的口號(hào)。

11年后的今天,我們?nèi)詾镈rawCall過(guò)多而苦惱的原因,主要來(lái)自多方面的開(kāi)銷(xiāo),包括PSO切換過(guò)多、Buffer提交與拷貝、引擎渲染邏輯以及過(guò)多RHI接口調(diào)用,都會(huì)增加CPU負(fù)擔(dān)。因此我們認(rèn)為性能優(yōu)化不能只盯著DrawCall數(shù)量,而要綜合考量這些因素。

  • PSO切換優(yōu)化:主要取決于每個(gè)項(xiàng)目對(duì)shader變體數(shù)量和shader復(fù)雜度的權(quán)衡。RenderGroup渲染隊(duì)列會(huì)根據(jù)shader,material,mesh的優(yōu)先級(jí)排序,同時(shí)我們對(duì)陰影進(jìn)行特殊處理:無(wú)AlphaTest的材質(zhì)統(tǒng)一用相同shader渲染Shadow Depth,減少陰影渲染時(shí)的PSO切換頻率。

  • Buffer提交優(yōu)化:在GLES下,Map/Unmap buffer會(huì)帶來(lái)顯著開(kāi)銷(xiāo),現(xiàn)代RHI支持的persistent map雖能顯著減少u(mài)pload耗時(shí),但仍無(wú)法避免數(shù)據(jù)從主線程到渲染線程,再到buffer內(nèi)存的多次拷貝以及memcmp。因此我們采用了以下三種針對(duì)性的策略,顯著減少了Buffer Upload:

    • PerRendererBuffer將逐Renderer的參數(shù)(如物體所受的環(huán)境光SH),存放在由Renderer對(duì)象維護(hù)的Uniform Buffer中,渲染時(shí)直接綁定;

    • PerShaderBuffer針對(duì)不需要逐材質(zhì)變化的uniform buffer,只在shader切換時(shí)提交一次,相比PerRendererBuffer來(lái)說(shuō),PerShaderBuffer更加靈活,可以支持不同的shader變體;

    • 針對(duì)PerMaterialBuffer,我們借用了SRP Batcher代碼預(yù)生成逐材質(zhì)buffer并直接綁定。

  • 渲染邏輯優(yōu)化:商業(yè)游戲引擎為保證靈活性與穩(wěn)定性,渲染時(shí)會(huì)進(jìn)行復(fù)雜的邏輯判斷。比如在Unity引擎內(nèi)部,每次調(diào)用Draw時(shí)會(huì)先調(diào)用一個(gè)ApplyMaterial函數(shù),它會(huì)在渲染之前更新所有的渲染狀態(tài)與參數(shù),當(dāng)DrawCall數(shù)量較多時(shí)存在可觀的耗時(shí)。因此我們進(jìn)行了以下優(yōu)化:

    • 對(duì)ApplyMaterial接口進(jìn)行了單獨(dú)拆分,僅在材質(zhì)或參數(shù)需要切換時(shí)才由上層主動(dòng)調(diào)用;

    • 只需改變PerMaterialBuffer時(shí),改用簡(jiǎn)化后的專(zhuān)用接口。

優(yōu)化后,我們的CPU在在相同DrawCall下耗時(shí)減少1/3。

  • RHI調(diào)用優(yōu)化:RHI調(diào)用優(yōu)化主要的目標(biāo)是減少除了Draw Primitive以外的其他圖形API調(diào)用,具體優(yōu)化包括:

    • 合并相同stride的Vertex&Index Buffer,避免逐Draw Call bind VB/IB,耗時(shí)減少15%;

    • Resource未發(fā)生變化時(shí),跳過(guò)DescriptorSet設(shè)置,耗時(shí)進(jìn)一步減少30%;SetDescriptors本身耗時(shí)較高時(shí)候,而且切換Descriptor還會(huì)增加下一次draw的耗時(shí),這個(gè)在Arm的Best Practice Guide里有過(guò)介紹。

我們?cè)诘投税沧吭O(shè)備上測(cè)試了5000個(gè)DrawCall的耗時(shí)。使用引擎原生的渲染時(shí),渲染線程的耗時(shí)是34.79ms。當(dāng)我們對(duì)Buffer提交與渲染邏輯進(jìn)行優(yōu)化后,耗時(shí)降低到22.97ms。在進(jìn)一步優(yōu)化RHI調(diào)用次數(shù)后,耗時(shí)進(jìn)一步大幅降至了11.8ms。最終我們?cè)贒rawCall數(shù)量不變的前提下,讓CPU耗時(shí)減少到了原來(lái)的1/3以下。


其他優(yōu)化嘗試Benchmark場(chǎng)景測(cè)試結(jié)果

我們還嘗試了一些新的RHI特性,包括:

  • Multi-Draw Indirect(MDI):在支持的設(shè)備上能夠帶來(lái)明顯優(yōu)化,一定程度上改善GPU遮擋剔除可能會(huì)提交空DrawCall的問(wèn)題(CPU端提交減少);

  • Bindless:然而,Bindless的表現(xiàn)卻不盡如人意,即便在最新的安卓設(shè)備上也出現(xiàn)了神秘的負(fù)優(yōu)化。結(jié)合MDI與Bindless,我們可以實(shí)現(xiàn)幾乎用一個(gè)DrawCall渲染所有物件,但是CPU耗時(shí)卻比不合批時(shí)還更高。這也是一個(gè)過(guò)度關(guān)注DrawCall數(shù)量的反面案例。當(dāng)然,我們期待以后的移動(dòng)芯片對(duì)bindless能有更好的支持。現(xiàn)階段的話(huà),我們嘗試基于Unity Texture Streaming擴(kuò)展出了一套無(wú)Feedback SVT系統(tǒng)作為替代方案,這個(gè)方案也還在驗(yàn)證階段。

從Benchmark場(chǎng)景測(cè)試結(jié)果來(lái)看,RenderGroupRenderer對(duì)比原始無(wú)instancing渲染,DrawCall減少了1/3,渲染線程耗時(shí)大幅減少3/4,主線程耗時(shí)也減少了2/3(雖然C,但引擎原生裁剪與GameObject更新耗時(shí)減少,整體仍然帶來(lái)了大幅的優(yōu)化)。

2. 光照方案

光照方案

  • 前向渲染管線:

我們?cè)陧?xiàng)目中選擇使用前向渲染管線,包含以下多方面考慮:首先,前向管線在應(yīng)對(duì)美術(shù)復(fù)雜且多變的需求方面有其優(yōu)勢(shì),我們不需要擔(dān)心一些材質(zhì)屬性的添加是否會(huì)導(dǎo)致GBuffer膨脹。

其次,傳統(tǒng)的延遲管線對(duì)于移動(dòng)平臺(tái)而言帶寬不太友好。OnePassDeferred則在靈活性方面存在一些局限,比如無(wú)法在RenderPass中間改變RT的尺寸,也不能fetch當(dāng)前位置以外的像素內(nèi)容。

在GLES下,F(xiàn)rameBufferFetch的兼容性也存在問(wèn)題,不同芯片支持的fetch RT數(shù)量不同,有的只支持1張RT,需要改成通過(guò)PLS實(shí)現(xiàn),但是我們測(cè)試PLS的性能并不理想。

另外,引擎自帶的逐物件4盞光源對(duì)于較大的物件來(lái)說(shuō)不太夠用,因此我們嘗試了Forward+。但是Forward+在早期設(shè)備上耗時(shí)太高,若限制逐tile最大光源數(shù),鏡頭變化時(shí),tile內(nèi)光源數(shù)量不可控,超上限會(huì)帶來(lái)表現(xiàn)bug。

為解決這些問(wèn)題,我們采用了水平世界空間Tile劃分——默認(rèn)2米一格,分布于相機(jī)前方,逐Tile最多4盞光源,128*128 Index Map。這種劃分方式使Tile光源重疊狀態(tài)穩(wěn)定,便于在制作時(shí)及時(shí)發(fā)現(xiàn)超限問(wèn)題。


  • Vulkan版本管線改進(jìn)

我們?cè)谖磥?lái)的Vulkan版本的管線中增加了基于Subpass的Light Pre-Pass。

在Pre-Z Pass中,我們會(huì)輸出一張簡(jiǎn)易的GBuffer RT并且store下來(lái)。由于我們的local light光照使用了無(wú)fresnel的簡(jiǎn)化PBR模型,所以我們不需要在GBuffer中輸出specular或者Albedo,只將normal,roughness和一些特殊的材質(zhì)id或?qū)傩孕畔ack到一張RGBA8的Gbuffer上,然后就可以跑一遍類(lèi)似Deferred Shading的光源Volume渲染流程,將幾何光照結(jié)果保存到Tile Memory上。

之后在Shading Pass中,我們會(huì)把物件再畫(huà)一遍并fetch這些光照信息,再結(jié)合渲染時(shí)獲得的albedo等材質(zhì)屬性,得到最終的光照結(jié)果。

我們將TAA所需的MotionVector Encode為RGBA8,R + G == 0代表無(wú)有效速度,這樣某些不輸出速度的材質(zhì)可在BA通道存其他信息。

比如我們針對(duì)一些簡(jiǎn)易且大量的植被,會(huì)在MotionVector的BA通道上保存他們的UV信息,這樣在Shading Pass時(shí),我們只需要后處理獲取gbuffer中的幾何信息與MotionVector中的UV信息,即可還原出植被的材質(zhì)表現(xiàn)。

Vulkan版本的管線流程大致如下:首先由PreZ Pass輸出Depth,GBuffer與MotionVector,然后計(jì)算陰影的遮擋剔除,接著執(zhí)行陰影的深度渲染,再然后是一些AO和屏幕空間SSS之類(lèi)的計(jì)算然后我們就進(jìn)入NativeRenderPass,在SubPass中計(jì)算ShadowMask,Light Pre-Pass,以及執(zhí)行正常的Shading Pass。最后退出RenderPass,再執(zhí)行其他后處理Pass。


Vulkan版本管線改進(jìn)也存在一定局限,比如Light Pre-Pass只能替換默認(rèn)Lighting Model,對(duì)于需要更多Gbuffer通道的Lighting Model,還是需要采用Forward+。

不過(guò)我們提供了一個(gè)逐光源可選參數(shù),可以針對(duì)某個(gè)光源強(qiáng)行使用Standard Lit Model,對(duì)所有材質(zhì)統(tǒng)一處理,這樣可以在犧牲Lighting Model準(zhǔn)確性的條件下實(shí)現(xiàn)讓同Tile內(nèi)的像素受4盞以上燈的影響。

  • GI

Diffuse GI部分,我們采用了較為傳統(tǒng)的Lightmap+Light Probe的方式,Lightmap只保存間接光信息,Light Probe除了正常的逐物件單個(gè)采樣點(diǎn)的模式以外,我們還提供了一種多采樣點(diǎn)模式,能為每個(gè)物體設(shè)置多個(gè)采樣點(diǎn),依據(jù)線段、三角形或四面體的重心坐標(biāo)進(jìn)行插值。

在以下兩張對(duì)比圖中,左圖為單采樣點(diǎn)的效果,box的底部為統(tǒng)一的環(huán)境光照;右圖則為使用兩個(gè)采樣點(diǎn)的結(jié)果,可以發(fā)現(xiàn)左右兩邊受到了不同的間接光照。


Specular GI方面,我們主要是基于使用了AABB校正的Reflection Probe。另外對(duì)于一些特定的地板或水面,我們還會(huì)使用平面反射代理。大致可以看成一種專(zhuān)門(mén)用來(lái)畫(huà)反射的HLOD。

此外我們還參考了戰(zhàn)神的做法,對(duì)Reflection Probe的CubeMap做了歸一化。具體來(lái)說(shuō)就是根據(jù)CubeMap的像素生成一份環(huán)境光照的SH系數(shù),將CubeMap中的像素顏色與該方向的環(huán)境光照相除,得到歸一化的CubeMap。在實(shí)際渲染時(shí),再用每個(gè)像素在反射方向上所受的實(shí)際環(huán)境光照與CubeMap像素相乘,還原出反射顏色。

這種做法的好處是,即使大量物件采樣同一個(gè)Reflection Probe,不同區(qū)域的反射也能產(chǎn)生不同的明暗差別。

3. 陰影優(yōu)化

功能設(shè)計(jì)

我們陰影系統(tǒng)的基本設(shè)計(jì)為:

  • 三級(jí)CSM+角色特寫(xiě)陰影/多角色POSM:3級(jí)Cascade的CSM+1級(jí)角色專(zhuān)屬的特寫(xiě)陰影,在某些多角色場(chǎng)景時(shí)會(huì)使用POSM(Per-Object Shadow Map);

  • 可支持兩盞錐燈投影;

  • ScreenSpaceShadowMask:將以上陰影的結(jié)果都將輸出到了一張RGBA8的ScreenSpaceShadowMask上;

  • R:Directional Shadow, G: Local Shadow 1, B: Local Shadow 2, A: AO:R通道保存主光陰影,G和B保存了錐燈陰影,A通道保存了AO信息。

距離剔除

我們首先做了一個(gè)簡(jiǎn)單的距離剔除,根據(jù)陰影距離修改ScreenSpaceShadow后處理三角形頂點(diǎn)的深度值,之后再用ZTest Greater渲染,剔除陰影距離外的Shadow計(jì)算。

因?yàn)樵谟?jì)算陰影時(shí)要采樣depth,我們需要兩份depth分別用于Test與Sample,我們會(huì)在NativeRenderPass中拷貝一份Memoryless的Depth Buffer用于Test,盡量避免額外的讀寫(xiě)帶寬。

半影區(qū)域檢測(cè)

我們?cè)黾恿税胗皡^(qū)域檢測(cè)功能,先在1/4分辨率下計(jì)算一次PCF,隨后在全分辨率Shadow Pass里采樣1/4 mask,僅對(duì)shadow值處于中間區(qū)域的像素執(zhí)行全分辨率PCF,在保證效果的同時(shí)降低計(jì)算量。

為了避免這樣做之后存在某些細(xì)節(jié)像素檢測(cè)不準(zhǔn)確的問(wèn)題,我們會(huì)分別依據(jù)1/4 Buffer中Position的偏導(dǎo)與全分辨率Gather的4個(gè)深度值計(jì)算兩組法線。若法線夾角大于閾值,則判定低分辨率像素不可靠,強(qiáng)行執(zhí)行全分辨率PCF。

以下為場(chǎng)景的Debug視圖,紅色區(qū)域被我們判定為半影區(qū)間,只有這些像素才會(huì)執(zhí)行全分辨率的PCF。


逐像素bias

我們利用Receiver Plane Depth Bias算法實(shí)現(xiàn)了逐像素的Shadow Bias。它的原理也比較簡(jiǎn)單,首先對(duì)屏幕空間shadow coordinates偏導(dǎo)應(yīng)用二維鏈?zhǔn)椒▌t,求出陰影空間偏導(dǎo)。


利用偏導(dǎo)與PCF采樣偏移我們可以求出bias值。對(duì)于中心點(diǎn)來(lái)說(shuō),我們?cè)黾恿?個(gè)像素偏移的bias結(jié)果作為起始bias。

下圖為固定bias與逐像素bias的對(duì)比結(jié)果:


左圖使用固定bias值,可以看到box的底部有一段漏光區(qū)域,并且與光照方向接近垂直的表面存在部分自陰影走樣;使用逐像素bias之后(右圖),我們只會(huì)在偏導(dǎo)較大的區(qū)域增加bias,可以在保持細(xì)節(jié)投影的同時(shí)解決自陰影的走樣問(wèn)題。

不過(guò),當(dāng)屏幕深度不連續(xù)時(shí),逐像素bias可能算出錯(cuò)誤結(jié)果,導(dǎo)致一些漏光現(xiàn)象。為了解決這一問(wèn)題,需要美術(shù)手動(dòng)指定bias的最大最小范圍。

Scrolling Cached Shadow Map

針對(duì)DrawCall較多的場(chǎng)景,我們還嘗試了Scrolling Cached Shadow Map,具體包括:

  • 緩存CSM深度,對(duì)于前后兩幀都被陰影視錐完全包含的對(duì)象,將上一幀的CSM滾動(dòng)到當(dāng)前幀投影位置直接得到陰影深度,避免直接渲染對(duì)象;

  • 只對(duì)最后一級(jí)cascade應(yīng)用Scrolling,當(dāng)cascade范圍比較小時(shí),大量物體與會(huì)與視錐相交,優(yōu)化效果就會(huì)受限;

  • 間隔多幀更新緩存,減緩帶寬壓力。

在未來(lái),我們還準(zhǔn)備支持Local ShadowMap Atlas以及緩存機(jī)制。我們將會(huì)支持兩盞以上的局部燈投影,并且根據(jù)光源的屏占比動(dòng)態(tài)調(diào)整ShadowDepth精度了,對(duì)于遠(yuǎn)距離的局部光源,也會(huì)引入靜態(tài)緩存支持。


1. 角色光照方案

在角色光照方案中,相信大家多多少少都會(huì)遇到以下幾類(lèi)問(wèn)題:


對(duì)這些問(wèn)題進(jìn)行拆解,則可以總結(jié)為以下3個(gè)需求:


基于以上需求,我們進(jìn)行了具體角色光照方案設(shè)計(jì)。

光照是由【直接光】和【間接光】組成的,一般情況下我們只會(huì)有一個(gè)平行光——我們習(xí)慣稱(chēng)之為主光。主光正常照亮場(chǎng)景,但在照亮角色的時(shí)候我們保留它的方向,用一個(gè)類(lèi)似后處理盒子的方式覆寫(xiě)主光的顏色和亮度。具體實(shí)現(xiàn)方式為:

  • 給Shader多傳一份角色主光顏色,角色的Shader在獲取主光時(shí)獲取到的顏色為角色主光顏色;

  • 給角色提供了一盞額外的不投影的平行光用來(lái)做輪廓光;

  • 同時(shí)預(yù)留了兩個(gè)額外光給角色,額外光可以是任意的點(diǎn)光和射燈組合,可以正常照亮范圍內(nèi)的角色和場(chǎng)景物件( 因?yàn)橐粋€(gè)2米的格子最多四盞額外光,所以將2個(gè)燈光劃分給角色)。

間接光我們使用Unity的LightProbe系統(tǒng)來(lái)創(chuàng)建探針,自己實(shí)現(xiàn)了保存間接光到探針里的部分,把場(chǎng)景的探針和角色的探針?lè)珠_(kāi)兩套,分別存儲(chǔ)和使用;

環(huán)境光高光我們使用同一個(gè)反射探針,但對(duì)于一些特殊的材質(zhì),我們提供了材質(zhì)上輸入CubeMap覆蓋環(huán)境的反射探針的選項(xiàng)。


我們把這些影響角色的光照信息存到一個(gè)Scriptableobject里,由燈光師調(diào)整好之后保存為一個(gè)模板;下方右圖為角色燈光方案保存的信息,包含了上面提到的兩盞平行光,兩個(gè)額外光,還有探針保存下來(lái)的sh,以及一些后處理盒子上可以額外調(diào)整的信息和是否使用自定義的反射探針。

最后用一個(gè)manager使用類(lèi)似棧的方式去管理,這里選用棧的管理方式跟具體使用強(qiáng)相關(guān)——通常情況下除了加載新的燈光方案之外,最常用的一個(gè)功能就是還原上一個(gè)燈光方案效果,因此我們采用了棧的管理方式。


到這里,這個(gè)方案已經(jīng)具備了角色/場(chǎng)景分開(kāi)、可實(shí)時(shí)切換、支持定制保持模板這些功能。最后我們把切換燈光方案定義成劇情編輯器上的一個(gè)事件行為,支持了可銜接光照動(dòng)畫(huà)。

可銜接光效果如下所示:


下圖為項(xiàng)目專(zhuān)用劇情編輯工具,基本上所有的燈光和陰影相關(guān)的參數(shù)及部分后處理、物理效果都可以在這個(gè)劇情編輯器控制。


2. 特寫(xiě)陰影

光和影一直都是密不可分的。如前文所提到,我們的陰影方案為三級(jí)CSM加特寫(xiě)陰影,實(shí)現(xiàn)原理就使用角色身上的一根可指定的骨骼做球心,構(gòu)成一個(gè)指定半徑的球,用這個(gè)球來(lái)構(gòu)建和生成這張陰影圖,在屏幕空間陰影的時(shí)候會(huì)進(jìn)行精度比較,使用這張陰影圖和級(jí)聯(lián)陰影中精度較高的一張作為這個(gè)像素的Shadow Map。


通過(guò)以下動(dòng)圖可以看到,角色原本整個(gè)都在主光陰影里,打開(kāi)特寫(xiě)陰影的時(shí)候變成了可以被主光正常照亮,就是因?yàn)樘貙?xiě)陰影修改了近裁切平面;也就是說(shuō)我們的特寫(xiě)陰影是一張單獨(dú)可調(diào)參數(shù)的陰影圖,具體參數(shù)包括遠(yuǎn)近裁切平面,最遠(yuǎn)距離,還有使用哪一盞光和往往最讓人頭疼的bias。


3. 皮膚細(xì)節(jié)

皮膚上我們聚焦一些細(xì)節(jié)表現(xiàn),具體以臉紅效果和流汗效果為例。

  • 臉紅效果

通常來(lái)講,臉紅的過(guò)程是一個(gè)逐漸變化并且不同區(qū)域變紅程度不一樣的過(guò)程,比如大部分人在臉紅的時(shí)候會(huì)先從耳朵開(kāi)始紅,然后是臉頰,偶爾會(huì)有整張臉變紅的表現(xiàn)。


為了模擬這個(gè)過(guò)程,我們采取了以下方式,使畫(huà)面更加生動(dòng)和真實(shí):

    • 手繪遮罩:基于遮罩紋理控制臉紅區(qū)域、顏色梯度與強(qiáng)度;

    • 多通道獨(dú)立:可分別調(diào)節(jié)面部、耳朵、鼻子等不同區(qū)域的紅暈效果;

    • 預(yù)存變化過(guò)程:臉紅的過(guò)渡過(guò)程分通道記錄在對(duì)應(yīng)曲線上,實(shí)現(xiàn)自然的情緒表達(dá)。

  • 流汗效果

我們游戲里提供了運(yùn)動(dòng)陪伴功能,男主會(huì)進(jìn)行一些運(yùn)動(dòng)訓(xùn)練的陪伴,因此也就需要提供相應(yīng)的流汗效果。具體實(shí)現(xiàn)主要通過(guò)以下三個(gè)方面:

  • 材質(zhì)與粒子結(jié)合:材質(zhì)著色器模擬皮膚表面光澤與濕潤(rùn)度,汗珠效果提供附著在皮膚上的材質(zhì)實(shí)現(xiàn)和vfx實(shí)現(xiàn)可供選擇;

  • 遮罩控制流汗區(qū)域:使用遮罩圖確定材質(zhì)流汗區(qū)域,增強(qiáng)流汗效果的真實(shí)性和藝術(shù)性;

  • 數(shù)據(jù)自動(dòng)化傳遞:主控參數(shù)變化自動(dòng)驅(qū)動(dòng)材質(zhì)與粒子參數(shù)。

下圖為一些具體的計(jì)算方式與最終效果示意。


△計(jì)算汗滴生成位置并修改汗滴位置粗糙度


△通過(guò)uv格子id生成隨機(jī)數(shù)


△模擬汗滴下落的軌跡


△運(yùn)動(dòng)陪伴系統(tǒng)流汗效果


物理效果的分享主要圍繞四個(gè)方面,包括布料模擬實(shí)現(xiàn)、實(shí)時(shí)表演控制、基于Unity DOTS的開(kāi)發(fā)、碰撞檢測(cè)模塊。

1. 布料模擬實(shí)現(xiàn)

為了解決項(xiàng)目中的一些針對(duì)性的問(wèn)題,我們內(nèi)部自研了一套布料模擬的系統(tǒng)。

基于骨骼的布料模擬系統(tǒng):StrayCloth

StrayCloth采用XPBD結(jié)合sub step的模擬方式。相比PBD,XPBD的優(yōu)點(diǎn)是擺脫了迭代次數(shù)和時(shí)間步長(zhǎng)的依賴(lài),結(jié)合Substep可以顯著提升解算的收斂效果。

比較特殊的地方在于,我們使用骨骼作為模擬粒子,也就說(shuō)每個(gè)粒子除了位置以外還帶旋轉(zhuǎn)信息。

在具體的substep實(shí)現(xiàn)中,我們針對(duì)不同性能壓力場(chǎng)景采用動(dòng)態(tài)的子步幅時(shí)間,在1/200 -1/300之間。并且對(duì)場(chǎng)景中的運(yùn)動(dòng)對(duì)象進(jìn)行運(yùn)行插值,這樣碰撞的效果會(huì)更加穩(wěn)定。事實(shí)上運(yùn)動(dòng)插值雖然性能開(kāi)銷(xiāo)不是很高,但是由于類(lèi)型眾多,比如有靜態(tài)粒子,碰撞體,風(fēng)場(chǎng)等,實(shí)踐起來(lái)還是非常麻煩的。


為什么使用骨骼而不是代理網(wǎng)格?主要出于以下三個(gè)原因:

  • 戀與深空在劇情、戰(zhàn)斗、換裝中的表現(xiàn)需求復(fù)雜,骨骼方案可以很好的過(guò)渡動(dòng)畫(huà)和解算;

  • 在可控性需求和移動(dòng)端性能限制下,骨骼方案給美術(shù)的自由調(diào)節(jié)空間更大;

  • 使用骨骼+約束可以構(gòu)建類(lèi)似Mesh的結(jié)構(gòu)來(lái)達(dá)到相近的效果。

骨骼約束方案

在已有的骨骼布料方案里,骨骼約束實(shí)現(xiàn)常采用基于Local和Global形狀約束的實(shí)現(xiàn)方式,雖然簡(jiǎn)單快速,但是也有明顯的缺點(diǎn)——在用來(lái)做布料模擬時(shí),效果偏向卡通風(fēng)格,不符合《戀與深空》追求的3D寫(xiě)實(shí)風(fēng)格;而且它的參數(shù)調(diào)整不直觀,因?yàn)樗術(shù)loabl和local兩個(gè)彎曲強(qiáng)度參數(shù),不利于美術(shù)調(diào)整以及在不同場(chǎng)景下的效果匹配。


因此,我們?cè)诠趋兰s束方案上,選擇了基于Cosserat Rod的骨骼約束。它的優(yōu)點(diǎn)包括:

  • 效果上更加自然,貼近戀與深空整體的寫(xiě)實(shí)美術(shù)表現(xiàn)風(fēng)格

  • 參數(shù)調(diào)整上更加直觀,并且三個(gè)軸向強(qiáng)度分離,在一些場(chǎng)合比如模擬裙子的時(shí)候,可以通過(guò)各向異性的彎曲強(qiáng)度來(lái)近似裙撐的效果。

  • 頭發(fā)模擬中可以直接復(fù)用,所以我們頭發(fā)和衣服也可以共用一套約束。

具體效果可以參考最新日卡的表現(xiàn):


布料與角色連接

布料和角色的連接主要通過(guò)兩種方式:

  • 層級(jí):靜態(tài)骨骼直接受角色的骨骼動(dòng)畫(huà)影響,根據(jù)層級(jí)關(guān)系進(jìn)行移動(dòng)。

    這種方式比較簡(jiǎn)單,在一些偏向于剛性的連接部位時(shí)表現(xiàn)良好。但是對(duì)于一些骨骼交界有多個(gè)骨骼影響或者存在一定幅度拉伸和收縮的較為復(fù)雜的位置,例如手肘、肩部、腰部,表現(xiàn)上容易出現(xiàn)布料和角色分離。

  • 吸附:靜態(tài)粒子受角色模型的錨定三角形控制。并行bake mesh,通過(guò)重心坐標(biāo)每幀計(jì)算更新。

對(duì)于三角形存在的退化的特殊情況,我們使用三角形頂點(diǎn)的蒙皮骨骼的變換,進(jìn)行加權(quán)平權(quán)來(lái)更新靜態(tài)粒子的transform。


碰撞方案

碰撞方案上,我們使用一個(gè)dynamic Bvh來(lái)作為場(chǎng)景碰撞的broad phase管理,每個(gè)角色作為sub tree包含其內(nèi)部的碰撞體作為sub tree node。

同時(shí),我們通過(guò)角色id,分享可見(jiàn)性還有部件類(lèi)型,這個(gè)三個(gè)規(guī)則來(lái)實(shí)現(xiàn)不同角色、不同部件的碰撞規(guī)則的共享規(guī)則管理。

在narrow phase 當(dāng)中,我們不直接生成contact,而是緩存碰撞體對(duì),在substep中再具體的解決,因?yàn)槲覀儾捎玫膕ub step的優(yōu)點(diǎn),大多數(shù)情況下直接使用DCD就可以避免一些快速運(yùn)動(dòng)下造成的穿透問(wèn)題,不需要引入ccd或者predictive contact等一些操作。


  • Mesh Collider實(shí)現(xiàn)

對(duì)于參數(shù)化的幾何碰撞體,例如plane、capsule、box,可以比較簡(jiǎn)單的解決它們和粒子以及edge的碰撞。在肩頸和胸背部等復(fù)雜部位,參數(shù)化的幾何體難以準(zhǔn)確的表達(dá)角色模型形態(tài),表現(xiàn)上容易發(fā)生穿透,所以在這些部位我們大量的使用Mesh collider。

但是mesh collider作為不規(guī)則的凹體,有時(shí)也可能是非閉合的,想達(dá)到精準(zhǔn)的碰撞效果相對(duì)參數(shù)化幾何體就比較困難,特別是在移動(dòng)設(shè)備下,因此我們采用散列哈希來(lái)作為三角形的粗略查找方式,結(jié)合緩存的鄰近三角形結(jié)果,在迭代開(kāi)始前生成一次粒子-三角形碰撞對(duì),后續(xù)的迭代中判讀粒子是否在三角形的范圍,如果超出三角形的范圍,通過(guò)模型的三角形鄰接關(guān)系進(jìn)行限制步幅的三角形查找,來(lái)獲取最近的三角形,并且緩存結(jié)果作為下一次使用。

下方的動(dòng)圖是項(xiàng)目中的一些具體表現(xiàn)示例,可以看到表現(xiàn)上是比較穩(wěn)定的。


Face Collider

面部碰撞體可以看作是特殊的Mesh collider,相對(duì)于基本的mesh collider,它形態(tài)較為固定,也較為平滑,從模型中心出發(fā)基本上沒(méi)有三角形重疊,所以我們使用16x16的CubeMap來(lái)預(yù)計(jì)算各個(gè)方向上的三角形,這樣碰撞計(jì)算時(shí)可以快速查找到鄰近的三角形。


層間碰撞

游戲當(dāng)中布料模擬的自碰撞是最難處理的部分,出于性能上的考慮,我們給出的方案如下:

  • 使用spatial hashing作為查找加速結(jié)構(gòu)

  • 由美術(shù)預(yù)先分層,只考慮層之間粒子和三角形碰撞

  • 避免層之間卡住的情況,只計(jì)算粒子和三角形單法線方向的碰撞

由美術(shù)預(yù)先對(duì)布料進(jìn)行分層,只考慮這些層之間的碰撞。使用散列哈希作為查找的加速結(jié)構(gòu),并且為了避免層之間卡住的情況,我們只考慮單法線方向的碰撞,如果已經(jīng)穿透了則略過(guò),交給后面的步驟來(lái)修復(fù)。

實(shí)際實(shí)踐中,我們使用上一次substep的粒子位置來(lái)和當(dāng)前的粒子位置進(jìn)行碰撞,這樣可以很簡(jiǎn)單的就解耦數(shù)據(jù)避免依賴(lài)。


層間穿透分離

對(duì)于層碰撞已經(jīng)穿透的部分,我們參考了untanging cloth的方式,使用了一個(gè)輕量的解決辦法,通過(guò)布料分層,從布料的固定點(diǎn)出發(fā),計(jì)算不同層級(jí)的邊和三角形的交點(diǎn),因?yàn)槲覀兊馁Y產(chǎn)結(jié)構(gòu)必定為一個(gè)uniform的網(wǎng)格,因此可以通過(guò)網(wǎng)格交點(diǎn)比較簡(jiǎn)單的推測(cè)出其它粒子的推出三角形,最后對(duì)穿透的粒子-三角形對(duì)施加彈簧約束來(lái)解決穿透。在實(shí)踐中由于substep的關(guān)系,穿透的概率相對(duì)不大,因此我們采用分幀分塊執(zhí)行來(lái)減輕性能壓力。

2. 實(shí)時(shí)表演控制

戀與深空劇情表現(xiàn)中大部分的物理表現(xiàn),都是依托于cutscene來(lái)實(shí)現(xiàn)的各種物理效果的控制和調(diào)節(jié)。我們的工具同學(xué)開(kāi)發(fā)和維護(hù)了一套非常強(qiáng)大的cutscene工具,在他們的基礎(chǔ)上我們開(kāi)發(fā)了多種的功能軌道來(lái)具體調(diào)控物理效果。

這邊是我們一個(gè)動(dòng)卡的Cutscene Physcs Track的例子,因?yàn)槲覀兠佬g(shù)同學(xué)對(duì)于畫(huà)面表現(xiàn)扣的非常細(xì),所以可以看到整個(gè)物理軌道的配置還是非常復(fù)雜的。


△Cutscene Physcs Track 示例

SmoothBlendPose Track

在表現(xiàn)當(dāng)中,一個(gè)非常常見(jiàn)的問(wèn)題就是動(dòng)作瞬切切換帶來(lái)的物理抖動(dòng),無(wú)論是在劇情表演中還是換裝中,都經(jīng)常出現(xiàn)。

我們開(kāi)發(fā)了一個(gè)較為通用的辦法,通過(guò)記錄初始物理姿態(tài),在切換的時(shí)候在初始姿態(tài)和當(dāng)前姿態(tài)進(jìn)行姿態(tài)插值計(jì)算,這樣就可以大幅度的緩解抖動(dòng),當(dāng)然這個(gè)會(huì)帶來(lái)一些時(shí)間開(kāi)銷(xiāo),一般會(huì)在幾十毫秒左右,在大多數(shù)情況下都可以接受,提供一些參數(shù)例如插值次數(shù),插值的步幅大小來(lái)讓美術(shù)可以根據(jù)實(shí)際需要來(lái)去調(diào)整。


Pose Track

當(dāng)然,SmoothBlendPose存在局限性,不能保證的完全順暢,特別是在一些劇情表演的復(fù)雜鏡頭切鏡下。我們還提供了一個(gè)比較直接的方案——離線直接保存某個(gè)時(shí)間幀的物理狀態(tài),在播放時(shí),將保存的物理狀態(tài)直接應(yīng)用到布料上,這樣就可以完美避免切鏡帶來(lái)的問(wèn)題。


Edit Param Track

單一的物理資產(chǎn)是很難滿(mǎn)足劇情當(dāng)中的各種不同場(chǎng)景下的表現(xiàn)的,比如有的時(shí)候希望布料軟一些硬一些,阻尼大一些小一些。我們提供編輯參數(shù)的軌道,通過(guò)這個(gè)軌道來(lái)實(shí)時(shí)的編輯修改參數(shù),絕大部分的參數(shù)都可以覆蓋大,可以非常方便的針對(duì)一小段時(shí)間幀進(jìn)行修改。這個(gè)參數(shù)修改還可以用來(lái)做一些特殊的效果,比如動(dòng)圖當(dāng)中的利用編輯約束參數(shù)來(lái)實(shí)現(xiàn)的斷裂的效果。


Animation Track

完全的物理效果實(shí)際上不足以支持起整個(gè)畫(huà)面方方面面的表現(xiàn)的,很多時(shí)候表現(xiàn)上需要?jiǎng)赢?huà)和物理的結(jié)合來(lái)做一些互動(dòng)。我們通過(guò)動(dòng)畫(huà)軌道來(lái)實(shí)現(xiàn)動(dòng)畫(huà)和物理的銜接和融合,精細(xì)的控制不同時(shí)間幀范圍下的表現(xiàn)。在實(shí)際制作流程當(dāng)中,動(dòng)作在dcc里和最終進(jìn)引擎的表現(xiàn)差異是比較大的,包括一些引擎的實(shí)時(shí)rig系統(tǒng)修改后,動(dòng)畫(huà)可能和其它地方有穿透,所以我們?cè)趧?dòng)畫(huà)融合的基礎(chǔ)上,可以疊加上物理的碰撞效果,來(lái)避免一些穿插。

動(dòng)圖當(dāng)中展示是項(xiàng)鏈在物理和動(dòng)畫(huà)的交互效果,包括從物理到動(dòng)畫(huà)的狀態(tài)切換以及在不同動(dòng)畫(huà)之間的切換。


Collider Track & Wind Track

Collider Track與Wind Track可以在cutscene中動(dòng)態(tài)的創(chuàng)建、銷(xiāo)毀碰撞體和風(fēng)場(chǎng)。根據(jù)不同畫(huà)面需求,靈活改變碰撞體和風(fēng)場(chǎng)的狀態(tài)。通過(guò)角色、部件類(lèi)型、還有布料的層分組來(lái)細(xì)節(jié)控制所要影響的對(duì)象范圍。

并且,碰撞體和風(fēng)場(chǎng)軌道的絕大部分參數(shù)可以添加動(dòng)畫(huà)幀控制,包括碰撞體的形態(tài)大小、風(fēng)場(chǎng)的方向、范圍、強(qiáng)度、湍流等,方便美術(shù)把控物理效果,精準(zhǔn)控制變化。

動(dòng)圖當(dāng)中是軌道膠囊體和風(fēng)場(chǎng)的一些表現(xiàn)例子。


3. 基于Unity DOTS的開(kāi)發(fā)

Jobs + Burst + Mathematics

DOTS這套工具非常強(qiáng)大,在C。我們的物理系統(tǒng)使用DOTS完全構(gòu)建在C,功能迭代和debug都非常便利。目前來(lái)說(shuō)我們最高可以支持2000+骨骼粒子的模擬。

當(dāng)然,我們也針對(duì)性的在項(xiàng)目中,做了一些優(yōu)化進(jìn)一步提升性能。


Cache Job

模擬中的job數(shù)量和依賴(lài)關(guān)系確定,job data并不頻繁變化,幀內(nèi)一般為相同數(shù)量和依賴(lài)關(guān)系的job組多次循環(huán)執(zhí)行,Unity Jobs 在發(fā)起任務(wù)時(shí)每次都需要重新創(chuàng)建job,雖然可以提前發(fā)起任務(wù)緩解,但是依然會(huì)卡主線程。并且在執(zhí)行完成job還需要clear?;谝陨系挠^察,我們開(kāi)發(fā)了Cache Job的方案,預(yù)先創(chuàng)建好job data,然后每次執(zhí)行時(shí)復(fù)用,避免每次重新創(chuàng)建job帶來(lái)的性能開(kāi)銷(xiāo)。

實(shí)現(xiàn)上比較簡(jiǎn)單,因?yàn)槭且粋€(gè)專(zhuān)用的結(jié)構(gòu),只考慮一些固定的使用場(chǎng)景。額外添加了一個(gè)Atomic Queue用來(lái)存cache job,使用fetch and add array 來(lái)存具體的job。右邊是worker執(zhí)行cache job的流程示意圖。


Neon Intrinsics

Burst會(huì)針對(duì)不同平臺(tái)生成高性能的simd code,在Burst Inspector中可以非常方便的查看。經(jīng)過(guò)檢查Burst Inspector和實(shí)機(jī)測(cè)試,在某些場(chǎng)合下也可以通過(guò)手寫(xiě)Arm Neon Intrinsics來(lái)進(jìn)一步提升性能。

這里給出例子是判斷向量是否存在大于0的元素的實(shí)現(xiàn)。



Dot(float4)

對(duì)于點(diǎn)乘,我這里列出了3種方式,使用neon intrinsics相比于mathematics在測(cè)試用例中可以獲得約30%的性能提升。如果目標(biāo)機(jī)型支持armv8.2的話(huà),可以使用新增的規(guī)約加法指令,來(lái)進(jìn)一步的提升性能。一般來(lái)說(shuō)現(xiàn)在市面上的大部分流行機(jī)型都是支持armv8.2的。


Transpose(float4x4)

對(duì)于轉(zhuǎn)置計(jì)算,可以看到mathematics生成的assembly code看起來(lái)性能是非常低的,通過(guò)手寫(xiě)neon intrinsics, 可以得到一個(gè)巨大的性能提升。

如果只是純粹的需要轉(zhuǎn)置,可以直接使用交錯(cuò)讀,這里這樣實(shí)現(xiàn)因?yàn)樵谖乙话愕膶?shí)際使用中是通過(guò)對(duì)4個(gè)float4轉(zhuǎn)置來(lái)將點(diǎn)乘變成矢量乘。

這里只是給出這兩個(gè)項(xiàng)目里比較常用的例子。因?yàn)閙athematics的代碼一般被內(nèi)聯(lián),在具體優(yōu)化時(shí)還需要根據(jù)代碼的上下文進(jìn)行具體的優(yōu)化,可以結(jié)合burst inspector和真機(jī)測(cè)試來(lái)進(jìn)行具體的性能測(cè)試。


4. 碰撞檢測(cè)模塊

為什么要脫離Unity成熟的物理模塊重新開(kāi)發(fā)?

Unity 本身具有基于physx的一套成熟的物理模塊,而脫離Unity成熟的物理模塊重新開(kāi)發(fā),主要基于以下考慮:

  • 戀與深空有相當(dāng)多的不同種類(lèi)的玩法,玩法間的layer設(shè)置相對(duì)獨(dú)立,非常希望能夠各自維護(hù)一套layer設(shè)置。

  • 有些模塊例如戰(zhàn)斗需要特殊的Trigger觸發(fā)和退出機(jī)制希望在底層就可以支持,對(duì)于執(zhí)行流程也希望有更靈活的控制。

  • 最后是在性能探索上我們也有一些想法,就是在僅需要碰撞檢測(cè)的情況下,利用DOTS能否提升性能?


《戀與深空》中的實(shí)現(xiàn)包括:

  • 基本實(shí)現(xiàn)了所有原生的碰撞查詢(xún)功能

  • 定制化的Update和Trigger邏輯

  • 線程安全的查詢(xún)接口,上層可以無(wú)負(fù)擔(dān)調(diào)用

  • 結(jié)合DOTS的輕量化結(jié)構(gòu)實(shí)現(xiàn),在性能測(cè)試中,最高可獲得~15%的提升

查詢(xún)流程示例

由于真機(jī)上,我們實(shí)際的線程數(shù)量是固定的為4,所以對(duì)于memory allocator可以預(yù)先按照線程數(shù)量分配好,在分配時(shí)可以直接根據(jù)當(dāng)前線程索引來(lái)獲取。

使用基于SAH的dynamic bvh作為broadphase加速結(jié)構(gòu),在插入、刪除以及超出范圍的移動(dòng)時(shí),對(duì)當(dāng)前操作節(jié)點(diǎn)的鄰近的幾個(gè)層級(jí)節(jié)點(diǎn)進(jìn)行旋轉(zhuǎn)平衡。

因?yàn)榕鲎矙z測(cè)的功能目標(biāo)相對(duì)概括,對(duì)于精度要求沒(méi)有那么高,所以我們也適當(dāng)?shù)臓奚恍┚群?jiǎn)化了一些碰撞檢測(cè)算法來(lái)提升性能。


觸發(fā)流程示例

為了滿(mǎn)足戰(zhàn)斗模塊的需求,我們?cè)O(shè)計(jì)了特殊的trigger觸發(fā)邏輯,Trigger的 Enter 和 Exit必須要成對(duì)出現(xiàn),可以看到以下流程示意圖中,在a觸發(fā)b的函數(shù)中移除b后,會(huì)觸發(fā)所有和b存在overlap的collider,這里和unity原生的有所不同——原生的unity中在trigger邏輯中刪除掉b是不會(huì)觸發(fā)其它碰撞體的trigger的。最后,我們通過(guò)History計(jì)數(shù)來(lái)標(biāo)記collider的版本,解決復(fù)用邏輯可能會(huì)導(dǎo)致的一些潛在問(wèn)題。


特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺(tái)“網(wǎng)易號(hào)”用戶(hù)上傳并發(fā)布,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相關(guān)推薦
熱點(diǎn)推薦
俞敏洪在南極給員工寫(xiě)信翻車(chē)上熱搜!員工:23點(diǎn)我還在打電話(huà)續(xù)費(fèi)

俞敏洪在南極給員工寫(xiě)信翻車(chē)上熱搜!員工:23點(diǎn)我還在打電話(huà)續(xù)費(fèi)

柴狗夫斯基
2025-11-17 21:16:32
雷軍急壞了,小米汽車(chē)賣(mài)不動(dòng)了,銷(xiāo)量下滑22%

雷軍急壞了,小米汽車(chē)賣(mài)不動(dòng)了,銷(xiāo)量下滑22%

吃瓜盟主
2025-11-18 14:29:35
太及時(shí)了!防止規(guī)模性返鄉(xiāng)滯鄉(xiāng),農(nóng)民工的工作“出口”是關(guān)鍵

太及時(shí)了!防止規(guī)模性返鄉(xiāng)滯鄉(xiāng),農(nóng)民工的工作“出口”是關(guān)鍵

火山詩(shī)話(huà)
2025-11-18 09:14:18
3-0!王曼昱大獲全勝:國(guó)乒世界第四敗北,全運(yùn)會(huì)女單冠軍太強(qiáng)勢(shì)

3-0!王曼昱大獲全勝:國(guó)乒世界第四敗北,全運(yùn)會(huì)女單冠軍太強(qiáng)勢(shì)

郝小小看體育
2025-11-18 11:06:09
臺(tái)灣退役少校怒懟日本:這次千萬(wàn)別投降

臺(tái)灣退役少校怒懟日本:這次千萬(wàn)別投降

揚(yáng)子晚報(bào)
2025-11-18 12:25:32
衡水中學(xué)崩了!考入清北人數(shù)越來(lái)越少,只因不能全省掐尖

衡水中學(xué)崩了!考入清北人數(shù)越來(lái)越少,只因不能全省掐尖

西虹市閑話(huà)
2025-11-18 12:48:41
王妃精致到發(fā)絲,王子直接變禿子

王妃精致到發(fā)絲,王子直接變禿子

Yuki女人故事
2025-11-17 15:03:06
日本歌手美依禮芽發(fā)文稱(chēng)永遠(yuǎn)支持一個(gè)中國(guó),目前其賬號(hào)IP仍在日本;曾參加《乘風(fēng)2023》人氣暴漲

日本歌手美依禮芽發(fā)文稱(chēng)永遠(yuǎn)支持一個(gè)中國(guó),目前其賬號(hào)IP仍在日本;曾參加《乘風(fēng)2023》人氣暴漲

極目新聞
2025-11-18 13:14:13
日本高官離京前,中方收抗議通知,美國(guó)已介入,高市在等友邦幫忙

日本高官離京前,中方收抗議通知,美國(guó)已介入,高市在等友邦幫忙

時(shí)時(shí)有聊
2025-11-18 15:14:19
已確認(rèn)!是知名演員周潤(rùn)發(fā)

已確認(rèn)!是知名演員周潤(rùn)發(fā)

大象新聞
2025-11-18 13:14:07
超市被偷到倒閉,女老板起訴合伙人案二審因法官為同一人延期,提交的審計(jì)材料也被弄丟

超市被偷到倒閉,女老板起訴合伙人案二審因法官為同一人延期,提交的審計(jì)材料也被弄丟

大風(fēng)新聞
2025-11-18 11:34:09
著名藥物化學(xué)家李敏勇教授突發(fā)疾病逝世,年僅49歲

著名藥物化學(xué)家李敏勇教授突發(fā)疾病逝世,年僅49歲

極目新聞
2025-11-18 09:42:29
不好,開(kāi)始還錢(qián)了?。?>
    </a>
        <h3>
      <a href=TopView
2025-11-18 11:32:38
突發(fā)兩大利空!全球股市大跳水,A股超4100家下跌,AI泡沫帶崩全球?

突發(fā)兩大利空!全球股市大跳水,A股超4100家下跌,AI泡沫帶崩全球?

看財(cái)經(jīng)show
2025-11-18 17:09:18
速報(bào) |高市早苗正考慮12 月 26 日參拜靖國(guó)神社

速報(bào) |高市早苗正考慮12 月 26 日參拜靖國(guó)神社

日本評(píng)論
2025-11-18 08:49:50
突然走紅,深圳也有!有人吃完直接燒到39℃進(jìn)ICU!

突然走紅,深圳也有!有人吃完直接燒到39℃進(jìn)ICU!

深圳晚報(bào)
2025-11-18 16:25:39
為什么三體火了之后,幾乎所有的星際航行劇都在中國(guó)遭受嘲諷?

為什么三體火了之后,幾乎所有的星際航行劇都在中國(guó)遭受嘲諷?

帶你感受人間冷暖
2025-11-18 00:20:04
退費(fèi)、取消!中國(guó)旅行社凍結(jié)寒假赴日?qǐng)F(tuán),全日空、資生堂、伊勢(shì)丹等股價(jià)大跌

退費(fèi)、取消!中國(guó)旅行社凍結(jié)寒假赴日?qǐng)F(tuán),全日空、資生堂、伊勢(shì)丹等股價(jià)大跌

愛(ài)看頭條
2025-11-17 14:24:36
東部戰(zhàn)區(qū)重磅發(fā)布!

東部戰(zhàn)區(qū)重磅發(fā)布!

新京報(bào)
2025-11-18 16:23:55
長(zhǎng)榮貨輪入天津港被拒?幫美運(yùn)坦克入臺(tái)!損失慘重苦不堪言

長(zhǎng)榮貨輪入天津港被拒?幫美運(yùn)坦克入臺(tái)!損失慘重苦不堪言

云舟史策
2025-11-18 07:30:28
2025-11-18 17:52:49
游娛fan incentive-icons
游娛fan
精彩游戲資訊
1758文章數(shù) 462關(guān)注度
往期回顧 全部

游戲要聞

拿卡牌當(dāng)食譜的模擬經(jīng)營(yíng)《食神的卡組》史低特惠

頭條要聞

孟加拉國(guó)前總理哈西娜被判死刑 中方回應(yīng)

頭條要聞

孟加拉國(guó)前總理哈西娜被判死刑 中方回應(yīng)

體育要聞

結(jié)束最后一次對(duì)決,陳夢(mèng)和朱雨玲笑著相擁

娛樂(lè)要聞

宋佳奪影后動(dòng)了誰(shuí)的奶酪

財(cái)經(jīng)要聞

剛剛,中美機(jī)器人爆發(fā)了一場(chǎng)論戰(zhàn)

科技要聞

馬斯克破防了!貝索斯62億美金入局"實(shí)體AI"

汽車(chē)要聞

更加豪華 更加全地形 極石ADAMAS

態(tài)度原創(chuàng)

家居
房產(chǎn)
教育
公開(kāi)課
軍事航空

家居要聞

彰顯奢華 意式經(jīng)典風(fēng)格

房產(chǎn)要聞

29.4億!海南“地王”片區(qū),要賣(mài)超級(jí)宅地!

教育要聞

思辨性閱讀與表達(dá)任務(wù)群的模型建構(gòu)——語(yǔ)文組第四屆學(xué)術(shù)節(jié)觀課評(píng)課交流

公開(kāi)課

李玫瑾:為什么性格比能力更重要?

軍事要聞

日媒揚(yáng)言要"擊沉福建艦" 專(zhuān)家:玩火自焚

無(wú)障礙瀏覽 進(jìn)入關(guān)懷版 在线观看国产精品无码| 又大又粗又爽少妇高潮ijzz| 国产jiZZHD精品巨大粗暴长| 国产精品尤物在线| 人与嘼AV免费网站| 人人人人操人人玩妻| 18禁黄久久久aaa片| 精品国产午夜| 国产精品88吃瓜久久久久久妇女| 黄色美女网站在线观看| 色偷偷www.8888在线观看| 天天做天天摸天天爽视频| 男人边吻奶边挵进去视频| 免费观看国产短视频的方法| 啊灬啊灬啊灬快灬高潮少妇| yazouxingaiwang| 亚洲 欧美 国产 制服 动漫| 日本激情字幕免费中文| 成 人 色 网 站免费观看| 激情一区二区三区成人文| 久久精品www人人爽人人| 国产内射AAA无吗大片| 51精品视频一区二区三区| 亚洲婷婷六月| 蜜臀亚洲一区二区| 亚洲AV无码专区亚洲AV| 日韩不卡AV| 国产成人毛片无码视频软件| 美女禁区a级全片免费观看| 调教鞭打视频| 国产无码综合| 又爽又黄又无遮挡网站| 亚洲无码vr| 久久伊人超碰| 97精品国产手机| 亚欧洲乱码视频一二三区| 你懂的国产精品| 日本A级视频| 免费A级毛片樱桃视频| 亚洲av片不卡无码一| 精品久久无码|