モバイル WebGL で中つ国を再現
これまで、モバイルとタブレットにインタラクティブなウェブベースのマルチメディア重視のエクスペリエンスを提供することは、課題でした。主な制約は、パフォーマンス、API の可用性、デバイス上の HTML5 音声の制限、インライン動画のシームレスな再生の欠如です。
Google とワーナー ブラザースの仲間と今年初めに、新しいホビット映画 ホビット 竜のゆくえ向けのモバイル ファースト ウェブ エクスペリエンスのプロジェクトを開始しました。マルチメディアを多用したモバイル Chrome 試験運用版の構築は、非常に刺激的でやりがいのあるタスクでした。
このエクスペリエンスは、WebGL と Web Audio を利用できる新しい Nexus デバイスの Chrome for Android 向けに最適化されています。ただし、ハードウェア アクセラレーションによる合成と CSS アニメーションにより、WebGL 以外のデバイスやブラウザでもエクスペリエンスの大部分を利用できます。
ゲーム全体は、中つ国の地図と、ホビット映画に登場する場所やキャラクターに基づいています。WebGL を使用することで、ホビット トリロジーの世界をドラマチックに表現し、ユーザーがその世界を探索できるようにしました。
モバイル デバイスでの WebGL の課題
まず、「モバイル デバイス」という用語は非常に広範です。デバイスの仕様は大きく異なります。そのため、デベロッパーは、複雑さの少ないエクスペリエンスでより多くのデバイスをサポートするか、このケースのように、よりリアルな 3D 世界を表示できるデバイスにサポートを限定するかを判断する必要があります。「Journey through Middle-earth」では、Nexus デバイスと 5 つの人気 Android スマートフォンを対象としました。
このテストでは、以前の WebGL プロジェクトで使用した three.js を使用しました。実装は、Nexus 10 タブレットで快適に動作する Trollshaw ゲームの初期バージョンを構築することから始めました。デバイスで初期テストを行った後、低スペックのノートパソコンで通常使用するような最適化のリストができました。
- ローポリモデルを使用する
- 低解像度テクスチャを使用する
- ジオメトリを統合して、ドローコールの数をできるだけ減らす
- 素材と照明をシンプルにする
- ポストエフェクトを削除し、アンチエイリアスをオフにする
- JavaScript のパフォーマンスを最適化する
- WebGL キャンバスを半分のサイズでレンダリングし、CSS で拡大する
これらの最適化をゲームの最初のラフ バージョンに適用した結果、安定した 30 FPS のフレームレートが得られ、満足のいく結果となりました。当時の目標は、フレームレートに悪影響を及ぼすことなくビジュアルを改善することでした。さまざまな方法を試しました。パフォーマンスに大きな影響を与えたものもあれば、期待したほどの効果がなかったものもありました。
ローポリモデルを使用する
まずはモデルから見ていきましょう。ローポリモデルを使用すると、ダウンロード時間とシーンの初期化時間の短縮に役立ちます。パフォーマンスに大きな影響を与えることなく、複雑さを大幅に増やすことができるとわかりました。このゲームで使用しているトロルのモデルは約 5,000 面で、シーンは約 40,000 面ですが、問題なく動作しています。

別の(まだリリースされていない)場所では、ポリゴンの削減によるパフォーマンスへの影響が大きくなりました。その場合、パソコン用に読み込んだオブジェクトよりも、モバイル デバイス用に読み込んだオブジェクトのポリゴン数が少なくなっています。異なる 3D モデルのセットを作成するには、追加の作業が必要になります。必ずしも必要な作業ではありません。モデルの複雑さによって異なります。
オブジェクトの多い大きなシーンでは、ジオメトリを分割する方法に戦略的に取り組みました。これにより、重要度の低いメッシュをすばやくオン / オフに切り替えて、すべてのモバイル デバイスで機能する設定を見つけることができました。次に、動的最適化のために実行時に JavaScript でジオメトリを統合するか、リクエストを節約するために本番前環境で統合するかを選択できます。
低解像度テクスチャを使用する
モバイル デバイスでの読み込み時間を短縮するため、パソコン用テクスチャの半分のサイズの異なるテクスチャを読み込むことにしました。すべてのデバイスは最大 2,048x2,048 ピクセルのテクスチャサイズを処理でき、ほとんどのデバイスは 4,096x4,096 ピクセルを処理できます。個々のテクスチャのテクスチャ ルックアップは、GPU にアップロードされた後で問題にならないようです。テクスチャの合計サイズが GPU メモリに収まるようにする必要があります。これにより、テクスチャのアップロードとダウンロードが頻繁に行われるのを防ぐことができます。ただし、ほとんどのウェブ エクスペリエンスでは、これは大きな問題ではないと思われます。ただし、ドローコールの数を減らすには、テクスチャをできるだけ少ないスプライトシートにまとめることが重要です。これは、モバイル デバイスのパフォーマンスに大きな影響を与えます。

(元のサイズ 512x512 ピクセル)
素材と照明をシンプルにする
素材の選択もパフォーマンスに大きく影響する可能性があるため、モバイルでは慎重に管理する必要があります。パフォーマンスを最適化するために、three.js で MeshPhongMaterial
(テキセルごとのライト計算)ではなく MeshLambertMaterial
(頂点ごとのライト計算)を使用しました。基本的には、照明計算をできるだけ少なくして、シンプルなシェーダーを使用するようにしました。
使用するマテリアルがシーンのパフォーマンスに与える影響を確認するには、MeshBasicMaterial
を使用してシーンのマテリアルをオーバーライドします。これにより、比較が容易になります。
scene.overrideMaterial = new THREE.MeshBasicMaterial({color:0x333333, wireframe:true});
JavaScript のパフォーマンスを最適化する
モバイル向けゲームを構築する際、GPU が最大の障害になるとは限りません。CPU に多くの時間が費やされます(特に物理とスケルトン アニメーション)。シミュレーションによっては、これらの負荷の高い計算を 2 フレームごとに 1 回だけ実行すると、パフォーマンスが向上することがあります。オブジェクト プーリング、ガベージ コレクション、オブジェクトの作成に関しては、利用可能な 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
レンダリング ループに任せる必要があります。
別のヒントとして、レイキャスト オペレーションを最適化または事前計算することもできます。たとえば、静的なパスの移動中にオブジェクトをメッシュにアタッチする必要がある場合は、1 回のループで位置を「記録」し、メッシュに対してレイキャストを行う代わりに、このデータから読み取ることができます。または、Rivendell エクスペリエンスのように、レイキャストを使用して、シンプルな低ポリゴンの目に見えないメッシュでマウス操作を探します。高ポリメッシュでの衝突の検索は非常に遅いため、通常はゲームループで避けるべきです。
WebGL キャンバスを半分のサイズでレンダリングし、CSS で拡大する
パフォーマンスを最適化するために調整できるパラメータの中で、最も効果的なのは WebGL キャンバスのサイズです。3D シーンの描画に使用するキャンバスが大きいほど、フレームごとに描画するピクセル数が増えます。これは当然、パフォーマンスに影響します。高密度 2,560 x 1,600 ピクセルのディスプレイを搭載した Nexus 10 は、低密度のタブレットの 4 倍のピクセル数を処理する必要があります。これをモバイル向けに最適化するために、キャンバスを半分のサイズ(50%)に設定し、ハードウェア アクセラレーションによる CSS 3D 変換で目的のサイズ(100%)に拡大するという手法を使用します。ただし、細い線が問題になるほど画像が粗くなるというデメリットがあります。高解像度の画面では、この効果はそれほど悪くありません。パフォーマンスの向上は確実に得られます。

オブジェクトをビルディング ブロックとして使用
ドル グルドゥ城の大きな迷路と果てしないリンドール谷を作成できるように、再利用できる一連のビルディング ブロック 3D モデルを作成しました。オブジェクトを再利用することで、エクスペリエンスの途中ではなく、開始時にオブジェクトがインスタンス化され、アップロードされるようになります。

Rivendell には、ユーザーのジャーニーの進行に応じて Z 深度を常に再配置する地面セクションがいくつかあります。ユーザーがセクションを通過すると、セクションは遠く離れた場所に再配置されます。
Dol Guldur 城では、ゲームごとに迷路を再生成したいと考えました。そのために、迷路を再生成するスクリプトを作成しました。
最初から構造全体を 1 つの大きなメッシュに統合すると、シーンが非常に大きくなり、パフォーマンスが低下します。この問題に対処するため、ビルディング ブロックがビュー内にあるかどうかに応じて、ビルディング ブロックを非表示または表示することにしました。最初から 2D レイキャスター スクリプトを使用することを考えていました。しかし、最終的には 組み込みの three.js フリューストラム カリングを使用しました。レイキャスター スクリプトを再利用して、プレイヤーが直面している「危険」をズームインしました。
次に処理する大きな要素はユーザー操作です。パソコンではマウスとキーボードによる入力が可能です。モバイル デバイスでは、タップ、スワイプ、ピンチ、デバイスの向きなどを使用して操作します。
モバイルウェブ エクスペリエンスでタップ操作を使用する
タップ操作のサポートを追加するのは難しくありません。このトピックに関する優れた記事があります。ただし、複雑になる可能性のある小さな要素もあります。
タップとマウスの両方を使用できます。Chromebook Pixel などのタッチ対応ノートパソコンは、マウスとタッチの両方をサポートしています。よくある間違いの 1 つは、デバイスがタッチ対応かどうかを確認し、タッチイベント リスナーのみを追加し、マウス用にリスナーを追加しないことです。
イベント リスナーでレンダリングを更新しないでください。代わりに、タッチイベントを変数に保存し、requestAnimationFrame レンダリング ループでそれらに対応します。これによりパフォーマンスが向上し、競合するイベントが統合されます。イベント リスナーで新しいオブジェクトを作成するのではなく、オブジェクトを再利用する。
マルチタッチであることに注意してください。event.touches は、すべてのタッチの配列です。場合によっては、event.targetTouches または event.changedTouches を調べて、関心のあるタップだけに反応するほうが便利です。タップとスワイプを区別するために、タップが移動した(スワイプ)のか、まだ動いていない(タップ)かをチェックする前に遅延を使用します。ピンチを取得するには、2 つの最初のタップ間の距離と、その距離の経時的な変化を測定します。
3D 世界では、マウス操作とスワイプ操作に対してカメラがどのように反応するかを決める必要があります。カメラの動きを追加する一般的な方法の一つは、マウスの動きに合わせてカメラを動かすことです。これは、マウスの位置を使用して直接制御するか、デルタ移動(位置の変更)を使用して行うことができます。モバイル デバイスでパソコンのブラウザと同じ動作をさせたいとは限りません。各バージョンに適したデザインを決定するために、広範囲にわたってテストを実施しました。
小さい画面やタッチスクリーンでは、ユーザーの指や UI 操作のグラフィックが、表示したい内容の邪魔になることがあります。これは、ネイティブ アプリの設計ではよくあることですが、ウェブ エクスペリエンスではこれまであまり考慮する必要がありませんでした。これは、デザイナーや UX デザイナーにとって大きな課題です。
概要
このプロジェクトの全体的な経験から、モバイル版 WebGL は、特に新しいハイエンド デバイスで非常によく動作することがわかりました。パフォーマンスに関しては、ダウンロードと初期化の時間がポリゴン数とテクスチャサイズに大きく影響し、モバイル パフォーマンスを最適化するために最も重要な部分はマテリアル、シェーダー、WebGL キャンバスのサイズであるようです。ただし、パフォーマンスに影響するのは、これらの要素の合計であるため、カウントを最適化するためにできることはすべて行ってください。
モバイル デバイスをターゲットとする場合、タップ操作について考える必要があります。これは、ピクセルサイズだけでなく、画面の物理サイズについても考える必要があります。場合によっては、3D カメラを近づけて、実際に何が起こっているのかを確認する必要がありました。
テストは開始され、素晴らしい成果を上げています。ぜひお楽しみください。
お試しになる場合は、中つ国への旅に出かけましょう。