哈比人體驗

透過 Mobile WebGL 創造中土世界的景象

Daniel Isaksson
Daniel Isaksson

在行動裝置與平板電腦上,提供以網頁為主的互動式多媒體體驗一直是個難題。主要限制在於效能、API 可用性、裝置上的 HTML5 音訊限制,以及無法順暢播放內嵌影片。

今年稍早,我們與 Google 和 Warner Bros. 的好友一起發起一項專案,希望為新推出的 Hobbit 電影《哈比人:荒野大地》打造以行動裝置為主的網路體驗。為行動裝置設計 Chrome 實驗功能,是一項充滿啟發性與挑戰性的行動裝置實驗。

新款 Nexus 裝置現在支援 WebGL 和網路音訊,因此可提供最佳的 Android 版 Chrome 體驗。不過,多半使用者可以透過硬體加速合成和 CSS 動畫,在非 WebGL 裝置和瀏覽器上存取。

整個體驗是根據中土世界地圖、哈比人電影中的地點和角色而打造。有了 WebGL,我們就能以戲劇化的方式,探索哈比人三部曲的豐富世界,並讓使用者自行控制體驗。

WebGL 在行動裝置上的挑戰

第一,「行動裝置」一詞的含意非常廣泛,裝置的規格大不相同。因此,開發人員必須決定要支援更多功能較不複雜的裝置,或是像我們一樣,將支援的裝置限制為能夠顯示出真實 3D 世界的裝置。「中土大陸冒險之旅」的重點是 Nexus 裝置和五款熱門 Android 智慧型手機。

在實驗中,我們使用 three.js 和之前的一些 WebGL 專案一樣。我們首先開發了可在 Nexus 10 平板電腦上運作的 Trollshaw 遊戲初始版本。對裝置進行初步測試後,我們整理出一份最佳化清單,內容與一般低規格的筆電類似:

  • 使用低多邊形模型
  • 使用低解析度紋理
  • 合併幾何圖形,盡可能減少繪製呼叫次數
  • 簡化材質和照明
  • 移除貼文特效並關閉消除鋸齒功能
  • 最佳化 JavaScript 效能
  • 以一半尺寸算繪 WebGL 畫布,並透過 CSS 放大

將這些最佳化功能應用到遊戲的第一個粗略版本後,我們獲得穩定的 30 FPS 影格速率。屆時,我們的目標是在不影響畫面更新率的情況下,改善視覺效果。我們試過許多小技巧:有些結果確實對成效產生了影響,有些效果不如預期。

使用低多邊形模型

先從模型談起使用低多邊形模型也有助於縮短下載時間和初始化場景所需的時間。我們發現,我們可以大幅提高複雜度,且不影響效能。我們在此遊戲中使用的食人頭模型約有 5,000 個臉孔,這個場景約有 4 萬張臉孔,可以正常運作。

Trollshaw 森林的陷阱之一
Trollshaw 森林的陷阱之一

我們發現,只要使用這項服務中的另一個 (尚未發布) 地點,就能減少多邊形造成的成效影響。在此情況下,我們載入了針對行動裝置載入的多邊形物件,而不是我們為電腦載入的物件。建立不同的 3D 模型組合需要額外進行一些工作,而且並非萬無一失。真正取決於模型一開始的複雜程度。

處理含有大量物體的大型場景時,我們試著有策略地劃分幾何形狀,因此我們可以快速開啟或關閉較不重要的網格,以便找出適用於所有行動裝置的設定。接著,我們可以選擇在執行階段將 JavaScript 中的幾何圖形合併,以便進行動態最佳化,或是在正式生產前合併這些幾何圖形以儲存要求。

使用低解析度紋理

為了降低行動裝置的載入時間,我們選擇載入不同紋理,但大小只是桌機紋理的一半。結果說明所有裝置都能處理高達 2048x2048 像素的紋理大小,且多數裝置都能處理 4096x4096 像素。個別紋理的紋理查詢上傳至 GPU 後似乎有問題。紋理的總大小必須放入 GPU 記憶體中,以免紋理不斷更新和下載,但對大多數網路體驗來說,這應該不會造成太大問題。不過,為了減少繪製呼叫的數量,關鍵就在於盡量將紋理合併至少量 Sprite 工作表,因為這會對行動裝置效能產生重大影響。

Trollshaw 森林之一的紋理
Trollshaw 樹林之一的樹叢
(原始大小 512 x 512 像素)

簡化材質和照明

選用的材質也可能會影響成效,因此必須在行動裝置上妥善管理。將 MeshLambertMaterial (每個頂點光計算) 使用 3.js 而非 MeshPhongMaterial (每個紋素光源計算) 有助於達到最佳效能。基本上,我們盡可能使用簡單的著色器,只計算亮度。

如要查看您使用的材料如何影響場景的表現,可以使用 MeshBasicMaterial 覆寫場景的材質。這樣比較容易瞭解兩者的比較結果。

scene.overrideMaterial = new THREE.MeshBasicMaterial({color:0x333333, wireframe:true});

最佳化 JavaScript 效能

針對行動裝置建構遊戲時,GPU 不一定能解決最大的阻礙。多數時間都花在 CPU 上,特別是物理和骨骼動畫。許多情況下,根據模擬結果都很有幫助,其中一項做法是只對其他影格執行這些昂貴的計算。您也可以在物件集區、垃圾收集和建立物件等方面,使用可用的 JavaScript 最佳化技術。

為避免在遊戲過程中產生垃圾收集,而以迴圈方式更新預先分配的物件,而不是建立新物件,相當重要。

舉例來說,請考慮以下程式碼:

var currentPos = new THREE.Vector3();

function gameLoop() {
  currentPos = new THREE.Vector3(0+offsetX,100,0);
}

這個迴圈的改善版本可避免建立必須進行垃圾收集的新物件:

var originPos = new THREE.Vector3(0,100,0);
var currentPos = new THREE.Vector3();
function gameLoop() {
  currentPos.copy(originPos).x += offsetX;
  //or
  currentPos.set(originPos.x+offsetX,originPos.y,originPos.z);
}

事件處理常式應盡可能只更新屬性,並讓 requestAnimationFrame 轉譯迴圈處理更新階段。

另一個訣竅是最佳化及/或預先計算光線投射作業。舉例來說,如果您需要在靜態路徑移動期間將物件附加至網格,可以在單一迴圈「記錄」這些迴圈的位置,然後讀取這項資料,而不是對網格進行光線投射。或是正如我們在 Rivendell 體驗所述,進行光線投放功能時,會使用較簡單的低聚型網格,來尋找滑鼠互動情形。搜尋高折線網格的衝突速度非常慢,一般來說應避免在遊戲迴圈中。

以一半尺寸算繪 WebGL 畫布,並透過 CSS 放大

WebGL 畫布的大小可能是最有效的單一參數,您可以調整這些參數來提高效能。3D 場景的畫布越大,每個畫面繪製的像素就越多。當然,這會影響效能。Nexus 10 搭載高密度 2560x1600 像素的螢幕,其像素數量必須達到低密度平板電腦的 4 倍。針對行動裝置,我們使用 trick 將畫布設定為一半的尺寸 (50%),然後透過硬體加速的 CSS 3D 轉換,將畫布放大至預期大小 (100%)。這種做法的缺點是,圖片過細的線條可能會引發問題,但在高解析度的螢幕上,效果並不會造成負面影響。成效絕對值得一試。

在 Nexus 10 (16FPS) 上,沒有畫布縮放的同一場景,比例調整為 50% (33 FPS)
在 Nexus 10 (16 FPS) 上,同一場景並未將畫布縮放至 50% (33 FPS)。

將物件做為構成要素

為了建立 Dol Guldur 城堡的大型迷宮,以及 Rivendell 的不結束河谷,我們製作了一組可重複使用的構成元素 3D 模型。重複使用物件,可確保在體驗一開始 (而非中間) 將物件例項化與上傳。

在 Dol Guldur 迷宮中的 3D 物件構成元素。
在 Dol Guldur 迷宮中使用的 3D 物件構成元素。

在 Rivendell 中,我們有多個地面區域,會隨著使用者的歷程進度,不斷地調整 Z 軸方向。當使用者瀏覽區段時,這些項目都會以遠距離重新放置。

對 Dol Guldur 城堡而言,我們希望每場遊戲都能重新產生迷宮。為此,我們建立了可重新產生迷宮的指令碼。

一開始就將整個結構合併到一個大網格中,會使場景非常大,效能也不佳。為解決這個問題,我們決定根據街景服務的影像來隱藏並顯示構成元素。我們從一開始就有個想法,就是想使用 2D 光柵指令碼,但最後我們使用了內建的三.js 視錐線處理。我們重複使用光柵指令碼,放大玩家面對的「危險」。

接下來要處理的事情就是使用者互動。電腦支援滑鼠和鍵盤輸入功能;在行動裝置上,使用者可以使用觸控、滑動、雙指撥動、螢幕方向等操作。

在行動網路體驗中使用觸控互動

新增觸控支援並不容易,有許多優質文章可協助您閱讀這個主題。但有些微小事可能會變得更加複雜。

您可以「同時」使用觸控功能和滑鼠。Chromebook Pixel 和其他支援觸控功能的筆電同時支援滑鼠和觸控操作。常見的錯誤是檢查裝置是否已啟用,然後只新增觸控事件監聽器,不會新增滑鼠。

請勿更新事件監聽器中的算繪。請改為將觸控事件儲存至變數,並在 requestAnimationFrame 轉譯迴圈中回應。這不但可以提升效能,同時也讓衝突的活動更加順暢。請務必重複使用物件,而不要在事件監聽器中建立新物件。

別忘了,這是多點觸控功能:event.touches 是各種接觸點。在某些情況下,建議您改為查看 event.targetTouches 或 event.changedTouches,並直接回應您有興趣的觸控動作。如要將輕觸手勢與滑動分隔開來,我們會先延遲一段時間,再確認觸控是否已移動 (滑動) 或圖示是否仍在 (輕觸)。為了方便起見,我們會測量兩次最初接觸之間的距離,以及兩者隨時間的變化情形。

在 3D 環境中,您必須決定攝影機回應滑鼠和滑動動作的方式。其中一個常見的新增攝影機動作方式是追蹤滑鼠移動。方法有兩種:直接控制滑鼠位置,或使用差異移動 (位置變更) 來完成。您不一定希望行動裝置的行為與電腦版瀏覽器完全相同。我們進行過廣泛測試,確認各版本適合哪些版本。

處理較小的螢幕和觸控螢幕時,使用者的手指和 UI 互動圖像通常都是您想要呈現的內容。這項技術是我們設計原生應用程式時使用的工具,但實際上沒有任何網路體驗需要思考。這對設計人員和使用者體驗設計人員來說是一大挑戰。

摘要

根據這個專案的整體經驗,Webb 在行動裝置上的運作效能十分優異,尤其是在較新的高階裝置上。提到效能,似乎主要會影響下載和初始化的時間,而材質、著色器和 WebGL 畫布的大小是最佳化行動裝置效能的最重要部分。然而,它是影響成效的各部分的總和,因此您可以採取的任何其他行動盡可能提升轉換次數。

指定行動裝置也代表您必須不時考量觸控互動,而這不只是像素大小,也就是螢幕的實際大小。在某些情況下,我們必須將 3D 相機拉近,才能實際查看事件。

進行實驗也很順利。希望您喜歡!

想試試嗎?展開自己的中土大陸之旅