Unity 場景分頁插件 World Streamer 支持無限大地圖的解決方案(一)

翻譯官方文檔加上自己的一些理解。

參考:WorldStreamer官方文檔。
目標:將我自己的WorldManager與WorldStreamer結合,讓WorldStreamer支持開放世界建築系統。

一、原理
創建虛擬grid,將大世界分成小塊管理。設置一個“參照點”(通常是Player,如果是RTS,則是Camera),當參照點足夠接近某個虛擬格子,或碰到碰撞體時,將其異步加載進來。

塊加載是可以分層處理的,分層的目的是爲不同的物件提供不同的Grid粒度。比如地形,房屋,和房屋裏的傢俱,等是需要不同的粒度的,放屋裏的傢俱只有玩家裏的足夠近纔有必要加載,而地形則需要在玩家能看到的時候,就加載,甚至如光照,聲音,特效這些虛頭巴腦的東西,也可以分層。這個系統也可以作爲LOD來使用,當玩家離得足夠遠時,可以用簡單的Mesh替代地形。這樣做非常省CPU和內存,因爲Unity的地形非常耗。分層使得分工合作成爲可能,當然做獨立遊戲的時候就老子一個人,這個就懶得寫了。

WorldStreamer牛逼的地方是在Build版本中,在Editor中使用WorldStreamer會導致一些烘焙,批處理操作轉移到運行時,簡單說就是很耗,可以臨時關掉Unity的靜態批次(static batching)解決這個問題,在Editor中DrawCall會增加,但是發佈版本不會有問題。

二:準備
Work場景:拆分前的大世界
物件分類:分類。
GamePlay場景:存放各種不需要流處理的物件:Player,Camera,DirectionalLight,各種自定義的Managers。
注意點擊Streamer.cs 面板上的Add Scenes To Build Scenes 否則,這些Grid場景是不會被加載的。

三、組件
·SceneSplitter:從你的場景對象創建虛擬Grid和層。他也可以從虛擬Grid元素產生場景。在場景生成過程中,SceneSplitter也會產出SceneCollection
並以“SC_Prefix”.scenc命名。每個層都會有一個SceneColliction
·SceneCollections:保存場景信息,如Grid元素大小,世界大小等細節。不需要手動填寫,這些數據在生成場景時,由sceneSplitter或者LocalAreaUpdater填寫。
·SceneObjects:與ScencCollenction連接,他們在生成場景時,由sceneSplitter或者LocalAreaUpdater生成或者刷新。
·StreamerPrefabns(Major,Minor):持有並使用“SC+Prefix”在你的GameplayScene中。你的第一個Streamer應該是Major。他負責:場景,大物件(如果你不使用Terrains,所有的物件如果你只有一個層)所有其他的Streamer必須是Minor。
·ColliderStreamers:他們持有當某些collider被碰觸後需要讀取的場景。
·Collider_Stream_Manager:這是一個Prefab。賦予你流式讀取場景物件通過ColliderStreamers。他也使你能夠通過隱藏在Grid元素中的碰撞體,載入場景。他也可以讓你產生“俄羅斯套娃”那樣的場景管理,流式場景裏面讀取流式場景。(估計我用不到)
·LocalAreaUpdater:場景融合,讀取局部場景,刷新,修改,移除已經分離的世界。允許多人同時編輯同一區域。
·StreamerGUI:場景讀取,傳送,重生,時候用到的讀取頁面。
·WorldMover。使用了“浮點數修復系統”重定位世界座標。同時保存真實座標與局部座標的關聯。這對已經spawn的對象和服務器通訊是很有用的。
·PlayerMover。這個腳本用於移動Player到安全地帶,直到初始化數據和讀取/傳送完成。
·PlayerTeleport。這個對象負責管理傳送點,重生點,可以爲動態物件
·ObjectgToMove:這個腳本在浮點修復系統重置位置時,持有非流式物件和角色之間的關聯。
·TerrainNeighbour:負責混合Terrain的邊緣,Terrain必須有同步的LOD,否則,Terrain邊緣將會有小洞。這玩意必須被放到遊戲場景中。
·TerrainCullingSystem:性能優化。
PhysicCullingSystem:物理優化。
ObjectParent:當拆分過程中需要分類時,這個腳本需要被附加到Hierarchy父節點上。

四、應用
(4.1)SceneSplitter
強烈建議在拆分的時候建議將相關內容拷貝到一個新的場景“Work”Scene,而那些常規內容,比如DirectionalLight,Player等放在GamePlayScene中。

·至少需要一個Layer。
·太空遊戲,需要XYZ軸,RTS,RPG一般只需要XZ軸,但是如果玩家飛的很高的時候,需要把地面隱藏,也可以使用Y。
·Size不應該過大,這樣性能損失很高,也不能過小,這樣的話,大型建築就沒法劃分了。
·對於Unity的Terrain,XZsize必須和地形的Length與Width一致。
·分層是根據前綴進行的,如果沒有前綴,所有的物件會被扔到你一個層裏面(官方說這麼做是爲了留出Tag和Layer給開發者,用作其他用途,所以沒有用tag和Layer分層)
·最好去掉父子層次關係,但是不這麼做也沒什麼大問題。官方推薦這麼做是因爲,如果B是A的子物件,A在(1,1)區塊,但是B的軸心位置在(1,2)區塊,那麼B本應該分配到(1,2)卻因爲父子關係,被分到了(1,1),這樣加載的時候,看起來會有些奇怪。但是如果B和A的軸心都在(1,1)區塊,就沒有區別了。
·LayerOrder是有意義的,如果你把一個GameObjectgPrefix爲空的Layer放在第一位,他會把所有的GameObjec收納,但是如果你把他放在最後的位置,他就會起到“兜底兒”的作用。
BuildSettings標籤頁(圖:略過),這裏可以看到SceneCollections是一個被Split的Scene的管理集合,一個SceneCollection對應一個層。每個SceneCollection會被做成一個Prefab。

4.2 Streamer Objects/Prefabs和他們的設置
官方手冊截圖

SceneCollection:把4.1生成的Prefab拖過來。
LoadingRange:預讀取範圍,1=9宮格。2=25格。
Deloading range:卸載場景距離,首先檢查距離,然後檢查延遲時間,場景不是馬上卸載的,因爲玩家很有可能“剛邁出去一步,又被揍回來了。”如果你的場景是循環的,那麼卸載距離應該小於場景總距離的一半-1。deloading size <world size / 2 -1
Position check:距離檢測時間,不是每幀都檢測的,那樣太蛋疼了。
Destroy tile delay:玩家超過Deloading範圍後,刪除Tile的延遲時間。放置邊界處頻繁的刪除,加載場景。
Max Parallel Scene Loading:同時加載的場景數量,值越低,越順暢。但是遠處場景可能會看起來一個一個蹦出來的。
Scene Load Wait Frames:場景讀取等待時間,如果場景流水線讀取太慢,很有可能是你把這個值設的太高了。
Terrain Neighbours:放置到有TerrainNeighbours.cs腳本的Prefab,用於同步TerrainLOD
Looping:地圖是否循環讀取,用於創建無限世界。
Spawned Player:Stream需要等待Player創建完成後再開始讀取。如果這個選項被勾選,所有Player窗口應該留空

(4.3)傳送與復生
把_PlayerTeleport拖進場景。他的XYZ值將作爲傳送目的地的xyz座標。
(應該只用一個PlayerTeleport,然後依據目的地,動態調整他的位置,不然豈不是要搞一大堆_PlayerTeleport物件?反正你一次也只能傳送到一個位置。例如你在A城,有BC兩座目的地城堡,你在菜單中選中B城,先把PlayerTeleport設置到B城的某地,然後設置PlayerTeleport的位置爲改地點,在執行傳送函數即可。)
推測這玩意就是當你需要傳送時,將目標地點周圍的格子預加載,同時將你周圍的格子全部卸載的東西。參考魔獸世界,即便是開放世界,走傳送門的時候也需要讀條。

Ui Loading Streamer:讀取時UI界面,可以直接照着官方提供的例子改。
Streamer:要把所有的Streamers都拖進去。
WorldMover:如果要使用Floating Point Fix 系統,把WorldMover扔進去。
PlayerMover:如果使用安全放置系統,把含有對應腳本的物件扔進去。(官方提供的是_Safe_Place_Spawn_and_Teleport)

(4.4)讀取頁面設置
Streamers:這裏不得不說一句,官方,真他媽缺心眼,這裏又要把Streamers全都設置一遍。不能找個地方集中設置一下,其他模塊都從這個設置讀取嗎?
這個沒啥解釋的,設置這些,估計是爲了處理讀取的Progress。最後OnDone是一個回調,可以把額外的讀取結束處理函數放到這裏來。其他不講了,很簡單。

WaitTime:用於計算多少個Virtual Grid受影響的時間,通常設置2-3秒即可。

(4.5)Floating Point Fix system 浮點修正系統。
如果你的場景太大(這裏我特意郵件問了一下老外,大約10K*10K的,也就是100平方公里的世界,都不需要這個功能,所以一般情況下是用不到的,除非你要搞個魔獸世界那麼大的世界,一般也就MMO能用上吧……),或者循環,你需要浮點修正系統。如果你的場景過大,物理和其他依賴於對象位置的系統,將會在計算的時候失去精度。

WorldMover將會不斷的重置你的世界位置。但是這麼做會很耗,所以不要太頻繁。
此外這個系統不支持靜態批次和NavMesh。
使用Prefab:"_World_Mover"來獲得浮點修正功能。
XYZ Tile Range:如果設置(2,2,2)意味着每經過兩個虛擬格子,重置一次。控制粒度的參數。
然後,你大爺的,有需要填一遍Streamers
CurrentMove:Local Player Position - Current Move = PlayerRealPosition.常用於RPC中的位置修正。
注意如果物件需要跟隨Player,那麼需要爲其添加ObejctToMove腳本。
(我的獨立遊戲應該還沒大到需要這麼做)

(4.6)Looping,略掉,我用不上。

(4.7)Ring streaming idea
這玩意可以用來完成一些LOD的功能
原理,內圈讀 高清模組範圍,外圈讀低模模組,把內圈釦掉,相當於近處用清晰模組,遠處用低模。UnityTerrain本身不支持LOD,可以用這種方式實現類似LOD的效果。

(4.8)Physics Manager物理管理器
超過距離玩家指定距離,物理將會被Freeze。
使用Prefab“_PhysicCulling_Test”

(4.9)Terrain Cull System 地形裁剪系統
Terrain Culling System這個腳本應該被附加到每個地形塊上,當地形距離玩家過遠時,將被裁剪。

(4.10) Player in safe place during data loading 玩家安全位置
如果你希望把Player移動到安全地點,直到讀取或傳送結束,你需要使用“Safe_Place_Spawn_and_Teleport”Prefab.這個系統也支持已經生成完的Player。
Streamers:填寫影響SafePlace系統的Streamers。
SafePosition:Player將被移動到這個安全地點,直到讀取完成。
Player:如果之前的選項勾選了“Spwaned Player ”(Player沒有放到場景裏,而是Spwan出來的,並且帶有Player標籤的。),這裏需要留空。一旦Player被Spwan出來,他會在SafePlace等待遊戲開始。

(4.11) GI and Lighting manager(unity 5.5+)
菜單:WorldStreamer->LightingManger。 提供一個允許你批量設置多個場景的光照的途徑。直接把SceneCollection拖進去,即可。

發佈了54 篇原創文章 · 獲贊 50 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章