熱門
《行尸走肉:行軍作戰》移動端優化經驗
來自Disruptor Beam的圖形和客戶端架構師Jason Booth,擁有超過25年創作游戲的豐富經驗。本文將分享他參與開發《行尸走肉:行軍作戰》所積累的,一些讓大型游戲在低端移動設備上也能擁有優秀運行體驗的經驗技巧。
如果需要《行尸走肉:行軍作戰》這款游戲高品質的運行,需要移動設備支持OpenGLES 2.0且RAM至少1GB,這樣的配置約占所有Android設備的40%。這款游戲中有細節豐富的美術資源、完整的晝夜和天氣循環,還有上千個對象,但它的容量卻不到100MB。這是如何達到的呢?
游戲介紹
《行尸走肉:行軍作戰》是一款緊張刺激的多人策略移動游戲,游戲背景設定是基于Robert Kirkman的長期連載漫畫系列《行尸走肉》。該游戲能支持5萬玩家夠同時在線游玩。游戲發生于弗吉尼亞州和華盛頓特區,是一個龐大、復雜且可自由探索的世界,成千上萬個喪尸、僵尸橫行于此,到處都會傳來爆炸聲。
世界由多個區域組成,載入和渲染大小為32x64,游戲平鋪大小為2048x1024,單位為米。在給定時間內,每次會渲染4~6個區域。游戲中的地圖是通過結合手動放置內容和程序化內容來創建的。
手動放置內容和程序化系統都在地圖編譯器(Map Compiler)中進行編譯。每塊32x64區域都會生成程序化內容,然后使用手動放置的數據來生成布爾值。地圖編譯器還會編譯地形數據和AI系統的導航信息。將完整的結果保存為預制件流格式,這是工作室自己的預制件系統。最后,所有內容都會通過Asset Bundle資源包流式傳輸給用戶。
大型空間節省工具:自定義預制件流
Disruptor Beam的自定義預制件解決方案或稱為預制件流,在設計和運行時使用,并支持嵌套。它存儲InstanceEntry的數組,用于構建和傳輸。
在編輯時,預制件流的額外代碼支持隨機處理等操作。對于特定部分,預制件流可以隨機生成多個元素,并在這些元素上創建簡單的變體。例如:房子和車子這類物品是從小型部件組成的,這些部件可以互相組合并匹配,從而在同樣的對象上產生不同變體。
在編譯時,預制件流會分為三個細節層級(LOD):對象可以被指定為高、中、低三個層級,以便可以在低端設備上刪除某些對象。當所有內容都編譯好后,會進行扁平化處理,所以在傳輸給用戶的時候不存在任何層次結構。
在運行時,預制件流的功能類似圖形引擎的底層繪圖列表,它會指定要用什么材質在哪個位置繪制哪些網格,以及存放Transform位置的列表,該列表指定要放置特定預制件的位置。
預制件流會打包Transform,由于現在部件大小已知,約占160平方米,它可以將Transform打包為七個部分:三個用于存儲位置,三個用于存儲旋轉,還有一個存儲縮放。
這會減小流式傳輸給用戶的場景數據大小。如果一塊區域被保存為場景,它的大小約為3.6 MB;如果被保存為預制件,大小約為2.1 MB,而如果是預制件流,則只有41KB。
使用網格圖像序列為角色制作動畫
《行尸走肉:行軍作戰》中的角色不會被近距離觀察。它們僅有60像素高,動畫設置有限。團隊必須對角色批量處理,因為低端設備上的繪圖調用效果不好。正常的處理流程是將角色放入紋理中,在頂點著色器采樣,然后在著色器中處理所有動畫。但由于OpenGLES 2.0不支持在頂點著色器上采樣,所以需要另一種解決方案。
于是,他們將動畫轉換為網格圖像序列(Mesh Flipbook)。載入時,圖像序列接收每個動畫,然后將所有幀都烘焙為獨特的網格,其中1幀 = 1個網格。然后在每個角色上交換網格,制作動畫。不過這個方法需要大量內存。
緊密打包的導航系統
導航數據通過地圖編譯器計算得出。該系統會把光線投射用于確定范圍內角色將要進入的開放空間。它會考慮像天橋這類對象,因此角色可以在它們下面行走。
最終結果是每個區域有64x64位數據,數據都被緊密地打包起來,因此整個世界大約有1MB的數據。
類似粒子系統的架構更新循環
為了編寫出快速而緊湊的更新循環代碼,請避免使用Update()、虛函數和面向對象的開銷。實際上,你也許想通過內嵌大量函數來減少開銷。這就像模仿粒子系統來編寫或構造代碼。
在粒子系統中有粒子數組,你可以通過數組壓縮粒子,一次更新所有內容。通常如果你將要擁有數千個對象,例如:僵尸。這正是正確的代碼塑造方式。
善待緩存
CPU很擅長通過內存按線性順序來壓縮并處理數據。所以可以設置一個大型區域,合理安排里面的對象,給它們運行相同的例程,這樣的做法類似著色器:著色器會接收并處理一整塊像素。如果你在設計時盡可能保持較小的數據量,這些數據會被高效地緩存,從而盡可能縮短CPU處理時間。
在《行尸走肉:行軍作戰》中,64x64位數據網格上的光線投射幾乎是沒有任何消耗的,因為這些數據都在緩存中,并且整個導航數據區域小于1KB。
慎用線程
不管是通過多處理器還是單處理器進行處理,慢代碼還是慢代碼。如果不確保數據結構盡可能緊湊,你只需將低效結構復制到多處理器中。
請考慮使用攤銷,因為這個方法比線程處理更簡單。然而,如果確實需要用線程處理代碼,代碼高效且能夠攤銷處理,該過程可以變得更簡單。
如何獲得漂亮的地形
為了在游戲中展現漂亮的地形,該團隊使用JPEG中的yCbCR顏色空間。在JPEG壓縮格式中,這種顏色空間提供了高分辨率亮度值和低分辨率色度(CbCR)值。
他們將四個亮度紋理壓縮到一個紋理中,從而得到四種通用地形類型,可以根據其顏色生成多個地形。例如:棕色使地形看起來像泥土,綠色像草地。
他們通過頂點RGBA顏色通道(RGBA)添加Splat權重遮罩。通過將亮度通道用于高度映射和基于高度的混合效果,從而產生漂亮的過渡效果。最后將低分辨率色度層應用于亮度高度圖,實現出美觀的地形效果。
總體結果是一個用于亮度數據的1024x1024紋理,整個世界和所有Splat映射一共使用了3.1MB數據。
重用地形網格制作水的網格
水的網格是克隆地形網格得到的。沒有使用深度圖,而是選擇通過移動頂點到水面高度(vertexHeight=waterHeight)得到了“免費的”深度緩沖區。
處理結果的差異是讓高度變成了深度。這樣做大大節省了資源,只用了一個紋理采樣/地形繪圖調用和一個紋理采樣/水繪圖調用就制作出了水的效果。
快速光照解決方案
對移動設備來說,渲染完整的PBR消耗的資源太多,所以他們使用了一種名為球面光照近似處理(Spherical Lighting Approximation)的方法。
通過這種方法將完整的PBR光照環境渲染為球面映射紋理,用于漫反射和鏡面反射效果。對于后續的mip等級,將平滑度數值的1/2存儲為之前的mip等級,然后使用對數空間編碼來實現4x強度的HDR。
然后在運行時,可以選擇一個mip等級并在紋理中查看。而不是進行光照計算。通過使用text2Dlod以適當的光滑度等級對光照紋理進行采樣。
該方法的優點是可以使用任意數量的光線,只需要照亮球面并渲染即可。這樣能夠得到任意復雜的光照環境,里面帶有無數的光線、天空盒等。這是一個定制的完整PBR工作流程,比標準PBR工作流程快20%。
陰影
針對高性能陰影,該團隊提出了一種解決方案,他們將陰影從上到下進行渲染,高度在陰影平面之上。這樣會高效地創建距離場并支持基于高度的模糊效果,用于制作柔和陰影和自身陰影。
此外,由于存儲了對象的高度,因此它們可以將數值固定到接近陰影平面的位置,使陰影模糊,從而創造出適當的環境遮蔽近似效果。
多分辨率渲染
通過使用多分辨率渲染功能,使UI保持在高分辨率,同時讓3D世界從降低的填充率獲益。他們通過使用DPI來在多種設備尺寸上得到一致的效果,根據目標DPI,范圍從200 DPI到400 DPI)來設置分辨率。
關于Asset Bundle資源包自定義構建的一些小技巧:
1、只標記要從代碼載入資源包的數據
2、解析依賴關系
將大型資源(如紋理和音效)放入指定資源包中
將共享資源放入指定資源包中
獨特的資源包含在父資源包之中
通過路徑命名資源包
3、不要使用資源包變體
為每個變體級別構建唯一的清單
用Perforce檢查,預處理所有紋理和音效,構建資源包,用Perforce恢復。
電話:010-50951355 傳真:010-50951352 郵箱:sales@www.gentlemenlisten.com ;點擊查看區域負責人電話
手機:13811546370 / 13720091697 / 13720096040 / 13811548270 /
13811981522 / 18600440988 /13810279720 /13581546145