導航:首頁 > 數據分析 > 點數據的熱點分析怎麼渲染

點數據的熱點分析怎麼渲染

發布時間:2024-06-21 18:40:19

㈠ Cocos 3.x 由淺到淺入門批量渲染

參考
由淺到淺入門批量渲染(一)
由淺到淺入門批量渲染(二)
由淺到淺入門批量渲染(三)
由淺到淺入門批量渲染(四)
由淺到淺入門批量渲染(完)
【Unity游戲開發】靜態、動態合批與GPU Instancing

本文只摘抄部分原文,達到概念性了解。

批量渲染其實是個老生常談的話題,它的另一個名字叫做「合批」。在日常開發中,通常說到優化、提高幀率時,總是會提到它。

可以簡單的理解為: 批量渲染是通過減少CPU向GPU發送渲染命令(DrawCall)的次數,以及減少GPU切換渲染狀態的次數,盡量讓GPU一次多做一些事情,來提升邏輯線和渲染線的整體效率。 但這是建立在GPU相對空閑,而CPU把更多的時間都耗費在渲染命令的提交上時,才有意義。

如果瓶頸在GPU,比如GPU性能偏差,或片段著色器過於復雜等,那麼沒准適當減少批處理,反而能達到優化的效果。所以要做性能優化,還是應該先定位瓶頸到底在哪兒,然後再考慮優化方案,而不是一股腦的就啪啪啪合批。當然,通常情況下,確實是以CPU出現瓶頸更為常見,所以適當的兆握了解些批量渲染的技法,是有那麼一丟丟必要的。

靜態合批是一種聽起來很常用,但在大多數手游項目里又沒那麼常用的合批技術。這里,我簡單的將靜態合批分為預處理階段的合並,和運行階段的批處理。

合並時,引擎將符合合批條件的渲染器身上的網格取出,對網格上的頂點進行空間變換,變換到合並根節點的坐標系下後,再合並成一個新的網格;這里需要注意的是,新網格是以若干個子網格的形式組合而成的,因為需要記錄每一個合並前網格的索引數量和起始索引(相對於合並後的新網格)。

空間變換的目的,是為了「固化」頂點緩沖區和索引緩沖區內的數據,使其頂點位置等信息都在相同的坐標系下。這樣運行時如果需要對合並後的對象進行空間變換(手動靜態合批對象的根節點可被空間變換),則無需修改緩沖區內的頂點屬性,只提供根節點的變換矩陣即可。

在Unity中,可以通過勾選靜態批處理標記,讓引擎在打包時自動合並;當然,也可以在運行時鬧鄭調用合並函數,手動合並。打包時的自動合並會膨脹場景文件,會在一定程度上影響場景的載入時間。此外,不同平台對於合並是有頂點和索引數量限制的,超過此限制則會合並成多個新網格。

運行時是否可以合批(Batch)成功,還取決於渲染器材質的設置。

當然,如果手動替換過場景中所有Material,也會打斷批次。

靜態合批與直接使用大網格(是指直接製作而成,非靜態合並產生的網格)的不同,主要體現液猜頌在兩方面。

其一,靜態合批可以主動隱藏部分對象。靜態合批在運行時,由於每個參與合並的對象可以通過起始索引等彼此區分,因此可以通過上述多次DrawCall的策略,實現隱藏指定的對象;而直接使用大網格,則無法做到這一點。

其二,靜態合批可以有效參與CPU的視錐剔除。當有剔除發生時,被送進渲染管線的頂點數量就會減少(通過參數控制),也就意味著被頂點著色器處理的頂點會減少,提升了GPU的效率;而使用大網格渲染時,由於整個網格都會被送進渲染管線,因此每一個頂點都需要被頂點著色器處理,如果攝像機只能照到一點點,那麼絕大多數參與計算的頂點最後都會被裁減掉,有一些浪費。

當然,這並不意味著靜態合批一定就比使用大網格要更好。如果子網格數量非常多,視錐剔除時CPU的壓力也會增加,所以具體情況具體分析吧~

靜態合批採用了以空間換時間的策略來提升渲染效率。

其優勢在於:網格通常在預處理階段(打包)時合並,運行時頂點、索引信息也不會發生變化,所以無需CPU消耗算力維護;若採用相同的材質,則以一次渲染命令,便可以同時渲染出多個本來相對獨立的物體,減少了DrawCall的次數。

在渲染前,可以先進行視錐體剔除,減少了頂點著色器對不可見頂點的處理次數,提高了GPU的效率。

其弊端在於:合批後的網格會常駐內存,在有些場景下可能並不適用。比如森林中的每一棵樹的網格都相同,如果對它採用靜態合批策略,合批後的網格基本等同於:單顆樹網格 x 樹的數量,這對內存的消耗可能就十分巨大了。

總而言之,靜態合批在解決場景中材質基本相同、網格不同、且自始至終都保持靜止的物體上時,很適用。

試想一個場景:一場激烈的戰斗中,雙方射出的箭矢飛行在空中,數量很多,材質也相同;但因為都在運動狀態,所以無法進行靜態合批;倘若一個一個的繪制這些箭矢,則會產生非常多次繪制命令的調用。

對於這些模型簡單、材質相同、但處在運動狀態下的物體,有沒有適合的批處理策略呢?有吧,動態合批就是為了解決這樣的問題。

動態合批沒有像靜態合批打包時的預處理階段,它只會在程序運行時發生。 動態合批會在每次繪制前,先將可以合批的對象整理在一起(Unity中由引擎自動完成),然後將這些單位的網格信息進行「合並」,接著僅向GPU發送一次繪制命令,就可以完成它們整體的繪制。

動態合批比較簡單,但有兩點仍然需要注意:

動態合批不會在繪制前創建新的網格,它只是將可以參與合批單位的頂點屬性,連續填充到一塊頂點和索引緩沖區中,讓GPU認為它們是一個整體。

在Unity中,引擎已自動為每種可以動態合批的渲染器分配了其類型公用的頂點和索引緩沖區,所以動態合批不會頻繁的創建頂點和索引緩沖區。

在向頂點和索引緩沖區內填充數據前,引擎會處理被合批網格的每個頂點信息,將其空間變換到世界坐標系下。

這是因為這些對象可能都不屬於相同的父節點,因此無法對其進行統一的空間轉換(本地到世界),需要在送進渲染管線前將每個頂點的坐標轉換為世界坐標系下的坐標(所以Unity中,合並後對象的頂點著色器內被傳入的M矩陣,都是單位矩陣)。

相對於上述看起來有點厲害但是本質上無用的知識而言,了解動態合批規則其實更為重要。比如:

當我們想要呈現這樣的場景:一片茂密的森林、廣闊的草原或崎嶇的山路時,會發現在這些場景中存在大量重復性元素:樹木、草和岩石。它們都使用了相同的模型,或者模型的種類很少,比如:樹可能只有幾種;但為了做出差異化,它們的顏色略有不同,高低參差不齊,當然位置也各不相同。

使用靜態合批來處理它們(假設它們都沒有動畫),是不合適的。因為數量太多(林子大了,多少樹都有), 所以合並後的網格體積可能非常大,這會引起內存的增加 ;而且,這個合並後的網格還是由大量重復網格組成的,不劃算。

使用動態合批來處理他們,雖然不會「合並」網格,但是仍然需要在渲染前遍歷所有頂點,進行空間變換的操作;雖然單顆樹、石頭的頂點數量可能不多,但由於 數量很多,所以也會在一定程度上增加CPU性能的開銷,沒必要

那麼,對於場景中這些模型重復、數量多的渲染需求,有沒有適合的批處理策略呢?有吧,實例化渲染就是為了解決這樣的問題。

實例化渲染,是通過調用「特殊」的渲染介面,由GPU完成的「批處理」。

它與傳統的渲染方式相比,最大的差別在於:調用渲染命令時需要告知GPU這次渲染的次數(繪制N個)。當GPU接到這個命令時,就會連續繪制N個物體到我們的屏幕上,其效率遠高於連續調用N次傳統渲染命令的和(一次繪制一個)。

舉個例子,假設希望在屏幕上繪制出兩個顏色、位置均不同的箱子。如果使用傳統的渲染,則需要調用兩次渲染命令(DrawCall = 2),分別為:畫一個紅箱子 和 畫一個綠箱子。

如果使用實例化渲染,則只需要調用一次渲染命令(DrawCall = 1),並且附帶一個參數2(表示繪制兩個)即可。

當然,如果只是這樣,那GPU就會把兩個箱子畫在相同的位置上。所以我們還需要告訴GPU兩個箱子各自的位置(其實是轉換矩陣)以及顏色。

這個位置和顏色我們會按照數組的方式傳遞給GPU,大概這個樣子吧:

那接下來GPU在進行渲染時,就會在渲染每一個箱子的時候,根據當前箱子的索引(第幾個),拿到正確的屬性(位置、顏色)來進行繪制了。

靜、動態合批實質上是將可以合批的對象真正的合並成一個大物體後,再通知GPU進行渲染,也就是其頂點索引緩沖區中必須包含全部參與合批對象的頂點信息; 因此,可以認為是CPU完成的批處理。

實例化渲染是對網格信息的重復利用,無論最終要渲染出幾個單位,其頂點和索引緩沖區內都只有一份數據, 可以認為是GPU完成的批處理

其實這么總結也有點問題,本質上講: 動、靜態合批解決的是合批問題,也就是先有大量存在的單位,再通過一些手段合並成為批次;而實例化渲染其實是個復制的事兒,是從少量復制為大量,只是利用了它「可以通過傳入屬性實現差異化」的特點,在某些條件下達到了與合批相同的效果。

無論是靜態合批、動態合批或實例化渲染,本質上並無孰優孰劣,它們都只是提高渲染效率的解決方案,也都有自己適合的場景或擅長解決的問題。個人以為:

Unity下可以通過以下兩種方式快速優化骨骼蒙皮動畫:

在相同的測試環境下,再次進行測試後可以發現,這種方法確實可以產生一定效果。其原因我認為主要有以下兩點:

開啟GPU蒙皮,Unity會通過ComputeShader的方式,使用GPU進行蒙皮。GPU上有大量的ALU(算數邏輯單元),可以並行大量的數值計算,效率較高,應該很適合這種針對頂點屬性的數值計算。

但是實際情況是:在移動設備上使用GPU蒙皮反而會使主線程的耗時增加。通過Profiler可以發現,CPU把更多的時間放在了執行ComputeShader上,由於骨骼動畫的實例很多(500個),所以這個調用時間本身成為了性能熱點。所以,以目前的情況來看,這種在移動設備上使用GPU蒙皮的方式,似乎不適合處理大量骨骼蒙皮動畫實例(也許是我使用的方式存在問題)。

簡單來說,它們基本的思路,都是將骨骼蒙皮動畫的「結果」預先保存在一張紋理中;然後在運行時通過GPU從這張紋理中采樣,並使用采樣結果來更新頂點屬性; 再結合實例化技術(GPU instancing) ,達到高效、大批量渲染的目的。

可以簡單的將它的工作流程分為兩個階段:

這個階段其實是為後面的播放階段准備動畫資源,你也可以把這個資源簡單的理解為一種特殊類型的動畫文件。

首先,在編輯狀態下,讓攜帶骨骼蒙皮動畫的角色,按照一定幀率播放動畫。我們知道:動畫播放時,角色網格會被蒙皮網格渲染器(SkinnedMeshRenderer)更新而產生變形(頂點變化);如果在動畫播放的同時,記錄下每一個頂點在這一時刻相對於角色坐標系(通常是角色腳下)的位置。那麼,當動畫播放完畢時,我們會得到一張「每一個頂點在每一個關鍵幀時的位置表」,我們就叫它「幀頂點位置表」吧。可是「幀頂點位置表」名字太長,你可能不太好記,我打字也比較麻煩,所以我們後面就叫它「表表」吧。

除了表表,我們還能得到與它對應的動畫信息,比如這個動畫的名稱、時長、幀率、總幀數、是否需要循環播放等信息。

到這里,第一個階段我們需要的內容就准備就緒了,可以進入下一個階段:播放動畫階段。

在動畫播放時,通過一個變數(播放時長)來更新播放進度;結合上一階段我們記錄下來的動畫總長度、動畫總幀數信息,就可以計算出當前動畫播放到了第幾幀(當前幀數 = 已播放時長 / 動畫總時長 x 動畫總幀數)。一旦得到當前動畫幀,就表示可以通過表表鎖定一行頂點數據。

接下來,只要遍歷這行頂點數據;然後根據索引找到網格中對應的頂點並更新它的位置,就等於完成了蒙皮工作。

既然通過一個播放進度、表表和一些簡單的動畫信息,就能直接完成蒙皮(對頂點屬性的更新),那麼我們就不再需要以下內容了:

使用CPU來讀取表表,並遍歷更新所有頂點,顯然不如GPU來的高效;所以接下來,我們將這一步放到渲染管線中的頂點變換階段,借著GPU處理頂點的契機,完成使用表表中的數據對頂點屬性進行更新。

實例化渲染的特點是使用相同網格,相同材質,通過不同的實例屬性完成大批量的帶有一定差異性的渲染;而烘焙頂點恰好符合了實例化渲染的使用需求。

所以,我們只需將控制動畫播放的關鍵屬性:比如過渡動畫播放的V坐標、當前和下一個動畫的插值比例等,放入實例化數據數組中進行傳遞;再在頂點著色器中,對關鍵屬性獲取並使用即可。

與蒙皮網格渲染器的比較

烘焙頂點的主要問題

除了烘焙頂點,另一種常用的優化方案是烘焙骨骼矩陣動畫。

聽名字就知道,烘焙骨骼矩陣與烘焙頂點位置,原理十分相似;最大的差異在於它們在烘焙時所記錄的內容不一樣:烘焙頂點記錄下來的是每個頂點的位置,而烘焙骨骼矩陣記錄下來的是每一根骨骼的矩陣,僅此而已。

烘焙骨骼矩陣最大的意義在於它補上了烘焙頂點的短板:受頂點數量限制、烘焙的動畫紋理過大 及 紋理數量較多。

烘焙頂點對於紋理(面積)的使用是受頂點數量決定的,可以簡單理解為:

所以,當模型的頂點數量過多時(數以千計),這種烘焙方式或者無法烘焙下整個模型(頂點數量>2048),或者需要一張或多張(法線、切線)大尺寸紋理(<2048 && > 1024)。

但是,烘焙骨骼矩陣主要取決於骨骼的數量,可以簡單理解為:

在移動平台上,通常20根左右的骨骼就可以取得不錯的表現效果,所以相對於烘焙頂點,烘焙骨骼可以記錄下更長的動畫,同時它也不再受頂點數量的限制,也無需對法線或切線進行特殊處理(因為可以在采樣後通過矩陣計算得出)。

針對這兩種方案,我個人認為並沒有絕對的孰優孰劣;正如你所看到的,烘焙骨骼在處理復雜模型或多動作時更具優勢;但如果渲染數量較多、模型頂點數較少、表現需求較弱(無需法向量參與計算)時,烘焙頂點也是值得嘗試的,因為它在性能上會更好一些。

目前靜態合批方案為運行時靜態合批,通過調用 BatchingUtility.batchStaticModel 可進行靜態合批。
該函數接收一個節點,然後將該節點下的所有 MeshRenderer 里的 Mesh 合並成一個,並將其掛到另一個節點下。
在合批後,將無法改變原有的 MeshRenderer 的 transform,但可以改變合批後的根節點的 transform。只有滿足以下條件的節點才能進行靜態合批:

引擎目前提供兩套動態合批系統,instancing 合批和合並 VB 方式的合批,兩種方式不能共存,instancing 優先順序大於合並 VB。
要開啟合批,只需在模型所使用的材質中對應勾選 USE_INSTANCING 或 USE_BATCHING 開關即可。

通過 Instancing 的合批適用於繪制大量頂點數據完全相同的動態模型,啟用後繪制時會根據材質和頂點數據分組,每組內組織 instanced attributes 信息,然後一次性完成繪制。

合並 VB 合批適用於繪制大量低面數且頂點數據各不相同的非蒙皮動態模型,啟用後繪制時會根據材質分組,然後每組內每幀合並頂點和世界變換信息,然後分批完成繪制

通常來說合批系統的使用優先順序為:靜態合批 > instancing 合批 > 合並 VB 合批。

骨骼動畫是一種常見但類型特殊的動畫,我們提供了 預烘焙骨骼動畫 和 實時計算骨骼動畫 兩套系統,針對不同方向的需求,分別優化。
這兩套系統的唯一開關就是 SkeletalAnimation 上的 useBakedAnimation 開關,啟用時會使用預烘焙骨骼動畫系統,禁用後會使用實時計算骨骼動畫系統,運行時也可以無縫切換。

目前所有模型資源在導入後,prefab 中全部默認使用預烘焙系統,以達到最佳性能。我們建議只在明顯感到預烘焙系統的表現力無法達標的情況下,再使用實時計算系統。雖然兩套系統可以在運行時無縫切換,但盡量不要高頻執行,因為每次切換都涉及底層渲染數據的重建。

基於預烘焙系統的框架設計,蒙皮模型的 instancing 也成為了觸手可及的功能,但要保證正確性還需要收集一些比較底層的信息。

這里的根本問題是,同一個 drawcall 內的各個模型使用的骨骼貼圖必須是同一張,如果不是同一張,顯示效果會完全錯亂。所以如何將動畫數據分配到每張骨骼貼圖上,就成為了一個需要用戶自定義的信息,對應在編輯器項目設置的 骨骼貼圖布局面板 進行配置。

注意

目前底層上傳 GPU 的骨骼紋理已做到全局自動合批復用,上層數據目前可以通過使用 批量蒙皮模型組件(BatchedSkinnedMeshRenderer)將同一個骨骼動畫組件控制的所有子蒙皮模型合並:

閱讀全文

與點數據的熱點分析怎麼渲染相關的資料

熱點內容
返利網站怎麼開通 瀏覽:223
有沒有附近人一起去看電影 瀏覽:987
老電影在哪裡看 瀏覽:163
文件加密方法有哪些 瀏覽:119
現代交換原理與通信網路技術pdf 瀏覽:533
word文件保存為pdf 瀏覽:919
如何給文件增加標記這個屬性 瀏覽:685
90版本巨宗傳說 瀏覽:330
上海推進大數據研究與發展三年行動計劃 瀏覽:520
冰凍人 歐美電影在線播放 瀏覽:895
大數據時代的數據 瀏覽:403
微信使用空間過大但是找不到文件 瀏覽:178
紅洋公司女演員 瀏覽:510
異地數據如何同步進行 瀏覽:772
哪裡可以找到日本資源 瀏覽:78
linuxorg 瀏覽:303
js動態改變元素的內容 瀏覽:900
如何關掉瀏覽跟蹤數據 瀏覽:699
搜布app哪裡能下載 瀏覽:926
discuz搭建網站 瀏覽:112

友情鏈接