精選文章

SmallBurger Asset Home

  SmallBurger

2017年4月10日 星期一

在Unity下做巨量繪圖物件管理

結論:500*500個物件加五個射影機加一個Infinity ocean,fps從20到56~60。

在這邊先提一下space partition的觀念:

它是一個用來快速查尋物件清單的機制,比方我們的台灣地圖,若把它分成北、中、南三區,在找台北市的時候,當然在北部地圖這邊找。space partition的種類很多,QuadTree、Octree、 K-DTree、BSP-Tree、Grid、PVS…等,通常會依照專案的需求會採用不同的資料結構。

Space partition的用途很廣,除了在camera view frustum culling會用到之外,也蠻常用在 AI(快速查找鄰近單位,比方像RVO)、碰撞…等跟空間切割有關議題對效能優化有很大的幫助。 下面有一個相關的範例圖:


在這個範例可以發現先將整個場景切成九等份,然後把相關的物件擺放到格子中,若遇有交插兩個格子之間的物件,可以隨便決定由那一個格子統一管理(由上而下、由左而右都行)。在Camera開始拍射(畫圖)的時候,先判斷有那個大格子會被拍到,不會被拍到的,就不用管它,之後再拜訪所有會被拍到大格子裡的所有子物件,判斷是否會被拍到,會被拍到再送進GPU。

所謂的Camera拍不拍的到,指的是物件的包覆範圍(bounding volume,通常是AABB或sphere)跟Camera的視野範圍(由六個Plane所組成)是否有交集。利用space partition大包小的特性,就可以大幅降低跟物件的比較次數。

那Unity下有沒有使用space partition來管理物件呢?目前大概只有看到PVS這個東西,但是PVS的特性,比較適合應用在遮蔽物很多的情況下(比方地下城,迷宮…等)。至於有沒有用到其他開闊式場景管理的機制,就不清楚了。

在經過一些大量的測試之後,發現Unity有一個特性,就是物件的Layer ID就算不是Camera Culling mask裡的範圍,仍然會對它做View frustum culling處理,除非你把GameObject的active設成false或是Renderer Component的enable設成false。

證據是我在場景放了500*500個物件(材質不相同,所以沒有batching在一起),在只有一個Main Camera的情況下,效能在還可以維持在50~60左右,當放了自己設計的Infinity ocean時(有額外四個射影機),就發現效能降到20左右,就算把所有的物件layer都設成所有的射影機看不到的layer ID也沒用,因此推論Unity底層應該是沒有用到QuadTree、Octree…等開闊式場景管理的機制。

然而Unity在camera view frustum culling本身也是封死在底層,完全沒辦法碰到,就算自己有十八般武藝也拿它沒輒,目前只能對它的GameObject或RenderComponent開刀,之前常常聽到google大神說動態切換GameObject的ative會影響效能,所以就走設定Render enable flag的路。

後來自己導入了一個簡單的grid base的space partition的機制,效能果然從20 fps提升到56左右,目前用的測試機器是紅米note3(GPU是Adreno 510),相關的測試影片如下…

Partition View的除錯資訊,綠線是指沒看到的Grid,紅線是指看到的Grid,白格是指看到的物件




下面是實際GameView看到的狀況:



Dream continues in...

1 則留言:

  1. 這讓我想起前公司專案巨獸浩劫的場景優化 (Unity 3.6) 也是這樣處理,
    我們自建一套 Occlusion culling,
    預先錄製好 Camera 在哪裡顯示什麼物件,
    OnPreCulling 階段來設定 Renderer disabled,
    減少 Drawcall 達到場景優化目的。

    回覆刪除