ブラウザ用 3D の驚くべき機能にスポットライトを当て、ゲームユーザーとデベロッパーの双方を魅了する Slow Roads

手続きによって生成される無限のシーンで WebGL が秘める可能性を体験できるカジュアル ドライビング ゲーム。

Slow Roads は、手続きによって無限に生成されるシーンに重点を置いたカジュアルなドライビング ゲームで、すべてが WebGL アプリケーションとしてブラウザでホストされています。多くの人にとって、このような集中的なエクスペリエンスは、ブラウザの限られたコンテキストでは意味がないと思われるかもしれません。実際、そのような姿勢を改善することが、このプロジェクトにおける私の目標の一つです。この記事では、これまで見過ごされがちなウェブの 3D の可能性を浮き彫りにすることをミッションに、パフォーマンスの課題を解決するために私が使用したテクニックを紹介します。

ブラウザでの 3D 開発

Slow Roads をリリースした後、フィードバックに「これがブラウザでできるとは知りませんでした」というコメントが繰り返し見られました。2022 年の State of JS の調査によると、80% のデベロッパーがまだ WebGL を試していないことがわかります。特にブラウザベースのゲームでは 多くの可能性を見逃してしまうのは残念なことですSlow Roads で WebGL の存在感をさらに高め、「高パフォーマンスの JavaScript ゲームエンジン」という言葉に躊躇するデベロッパーの数を減らすことを願っています。

多くの人にとって、WebGL は謎に満ち、複雑に思えるかもしれませんが、近年では、その開発エコシステムは高度に高機能で便利なツールやライブラリへと大きく成熟しています。コンピュータ グラフィックスの経験がなくても、フロントエンド デベロッパーはこれまでになく簡単に 3D UX を作業に組み込むことができます。主要な WebGL ライブラリである Three.js は、3D コンポーネントを React フレームワークに組み込む react-three-fiber など、多くの拡張の基盤となっています。また、使い慣れたインターフェースと統合ツールチェーンを備えた包括的なウェブベースのゲームエディタ(Babylon.jsPlayCanvas など)も利用できるようになりました。

しかし、こうしたライブラリの有用性は高いにもかかわらず、意欲的なプロジェクトは最終的に技術的制約に縛られます。ブラウザベースのゲームに懐疑的な人は、JavaScript がシングルスレッドでリソースに制約があるように思われるかもしれません。しかし、こうした制約を乗り越えれば、隠れた価値が見えてきます。ブラウザが実現する即時のアクセシビリティと大規模な互換性を他のプラットフォームは実現していません。ブラウザ対応システムであれば、ユーザーがアプリをインストールしたり、サービスにログインしたりすることなく、ワンクリックで再生を開始できます。言うまでもなく、デベロッパーは、UI の構築やマルチプレーヤー モードのネットワーク処理に使用できる堅牢なフロントエンド フレームワークを利用できるという、エレガントな利便性を享受できます。私は、これらの値が、プレーヤーとデベロッパーの両方にとってブラウザが非常に優れたプラットフォームになると考えています。また、Slow Roads で実証されているように、多くの場合、技術的な制限は設計上の問題を軽減できる可能性があります。

速度が遅い道路でスムーズなパフォーマンスを実現

Slow Roads のコア要素は、高速モーションと高価な風景の生成を含むため、スムーズなパフォーマンスの必要性が、あらゆる設計上の決定を下しました。私の主な戦略は、エンジンのアーキテクチャ内でコンテキストに応じたショートカットを使えるように、ゲームプレイの設計を簡潔にすることでした。この方法の欠点は、ミニマリズムを追求するために、あると良い機能をトレードオフ化することを意味しますが、さまざまなブラウザやデバイスで適切に機能する、高度に最適化されたオーダーメイドのシステムになります。

ここでは、スローロードをスリムにしている主な要素の内訳を示します。

ゲームプレイを取り巻く環境エンジンを形成する

ゲームの重要なコンポーネントとして、環境生成エンジンは必然的に高価であり、当然のことながら、メモリとコンピューティングの予算の大部分を占めます。ここで使われるコツは、パフォーマンスの急増でフレームレートを中断しないように、負荷の高い計算をスケジュールして一定期間にわたって分散することです。

環境はジオメトリのタイルで構成されており、カメラにどの程度近づくかに応じてサイズと解像度(「詳細レベル」または LoD に分類されます)が異なります。フリーローミング カメラを使用する一般的なゲームでは、プレーヤーがどこにいても周囲の状況を詳しく把握するために、さまざまな LoD の読み込みとアンロードを常に行う必要があります。これは特に、環境自体が動的に生成される場合、コストが高く無駄の多い処理になります。幸いにも、ユーザーは道路から外れないように期待するため、「Slow Roads」ではこの規則が完全に覆されてしまう可能性があります。代わりに、ルートに隣接する狭い通路用に高詳細ジオメトリを予約できます。

道路をはるかに事前に生成することで、環境生成のプロアクティブなスケジューリングとキャッシュ保存がどのように可能になるかを示す図。
ワイヤフレームとしてレンダリングされた「スローロード」の環境ジオメトリのビュー。道路に隣接する高解像度のジオメトリの回廊を示しています。近くから見えない遠く離れた部分は、はるかに低い解像度でレンダリングされます。

道路自体の中線は、プレーヤーが到着するかなり前に生成され、環境の詳細が必要になる正確なタイミングと場所を正確に予測できます。その結果、コストの高い作業を事前にスケジューリングし、各時点で必要な最小限の作業のみを生成して、見えない詳細情報に無駄な労力を費やすことなく、無駄のないシステムが実現します。この手法を可能にできるのは、道路が単一で分岐しない経路(アーキテクチャ上のショートカットに対応するゲームプレイのトレードオフを行う良い例)であるからです。

道路をはるかに事前に生成することで、環境生成のプロアクティブなスケジューリングとキャッシュ保存がどのように可能になるかを示す図。
道路に沿って一定の距離を監視することで、環境のチャンクを先取りし、必要になる直前に段階的に生成できます。また、不要な再生成を避けるために、近い将来に再アクセスされるチャンクを特定してキャッシュに保存することもできます。

物理法則を厳しく扱う

環境エンジンの計算需要の 2 つ目は、物理シミュレーションです。Slow Roads は、あらゆるショートカットを駆使する最小限のカスタム物理エンジンを採用しています。

ここでの大きな節約は、そもそも多くのオブジェクトをシミュレートしないようにすることです。動的衝突や破壊可能なオブジェクトなどを除外して、最小限の Z 系のコンテキストに頼ることです。車両が道路上に残るという仮定は、オフロードの物体との衝突を合理的に無視できることを意味します。さらに、道路をスパースな中線としてエンコードすることで、道路の中心までの距離チェックに基づいて、路面やガードレールとの衝突をすばやく検出するための洗練された手法が可能になります。オフロード運転のコストは高くなりますが、これはゲームプレイのコンテキストに適したフェア トレードオフのもう 1 つの例です。

メモリ使用量の管理

ブラウザの制約を受けるもう 1 つのリソースとして、JavaScript はガベージ コレクションの対象であるにもかかわらず、メモリを慎重に管理することが重要です。見落とされがちですが、ゲームループ内で新しいメモリをわずかに宣言しても、60 Hz で実行すると、重大な問題が発生する可能性があります。大規模なガベージ コレクションは、ユーザーがマルチタスクを行う可能性が高い状況でユーザーのリソースを消費するだけでなく、完了までに数フレームかかることがあり、顕著なスタッタリングを引き起こす可能性があります。これを回避するために、初期化時にループメモリをクラス変数に事前に割り当て、各フレームでリサイクルできます。

Slow Roads コードベースの最適化中のメモリ プロファイルの前後の比較。大幅な費用削減とガベージ コレクション レートの削減を示しています。
全体的なメモリ使用率はほとんど変化しませんが、ループメモリを事前に割り当ててリサイクルすることで、高コストなガベージ コレクションの影響を大幅に軽減できます。

また、ジオメトリやそれに関連付けられたデータ バッファなどのより重いデータ構造を経済的に管理することも非常に重要です。Slow Roads のような無限に生成されるゲームでは、ジオメトリのほとんどはトレッドミルのようなものです。古いピースが遠くに落ちると、そのデータ構造を保存し、次の世界に再利用できます。これは、オブジェクト プーリングと呼ばれる設計パターンです。

これらの手法は、コードの簡素化を犠牲にして、無駄のない実行を優先するのに役立ちます。高パフォーマンスのコンテキストでは、デベロッパーに便宜を図るために、便利な機能がクライアントからどのように借用するかに留意することが重要です。たとえば、Object.keys()Array.map() などのメソッドは非常に便利ですが、それぞれ戻り値に対して新しい配列を作成することは見落とされがちです。このようなブラックボックスの内部の仕組みを理解することで、コードを厳格化し、ひどいパフォーマンス ヒットを回避できます。

手続きによって生成されるアセットで読み込み時間を短縮する

ゲーム デベロッパーは実行時のパフォーマンスを第一に考えるべきですが、ウェブページの最初の読み込み時間に関する通常の公理は変わりません。負荷の高いコンテンツに自発的にアクセスする場合、ユーザーは寛容になる可能性がありますが、読み込み時間が長いと、ユーザー維持率が低下した場合、エクスペリエンスに悪影響を及ぼす可能性があります。ゲームでは、テクスチャ、サウンド、3D モデルなどの大きなアセットが必要になることが多く、少なくとも、ディテールを犠牲にできる場所では慎重に圧縮する必要があります。

あるいは、クライアントで手続き的にアセットを生成することで、そもそも時間のかかる転送を回避できます。これは、接続速度が遅いユーザーにとって大きなメリットであり、デベロッパーは最初の読み込みステップだけでなく、さまざまな品質設定に合わせて詳細レベルを調整する場合にも、ゲームの構成をより直接的に制御できます。

「Slow Roads」で、手続きによって生成されるジオメトリの品質をユーザーのパフォーマンス ニーズに動的に対応させる方法を示す比較。

「Slow Roads」のジオメトリのほとんどは手続きに基づいて生成され、シンプルであり、カスタム シェーダーで複数のテクスチャを組み合わせてディテールを表現しています。 欠点は、こうしたテクスチャが重いアセットになる可能性があることです。ただし、確率的テクスチャなどの手法により、小さなソース テクスチャからより細かいディテールを得られるという、さらなる節約の余地があります。また、極端な話ですが、texgen.js などのツールを使って、クライアント上で完全にテクスチャを生成することもできます。これはオーディオについても同様です。Web Audio API ではオーディオ ノードによる音声生成が可能です。

手続き型アセットを活用すると、初期環境の生成に平均でわずか 3.2 秒しかかかりません。最初に表示されるダウンロード サイズが小さくなるメリットを最大限に活かすため、シンプルなスプラッシュ画面で新規の訪問者を迎え、肯定的なボタンが押されるまで、コストの高いシーンの初期化を延期します。これは、バウンスされたセッションの便利なバッファとしても機能し、動的に読み込まれるアセットの無駄な転送を最小限に抑えることができます。

読み込み時間のヒストグラム。最初の 3 秒間に 60% 以上のユーザーが大きなピークを占め、その後急速に減少している。ヒストグラムを見ると、97% 以上のユーザーが読み込み時間が 10 秒未満であることがわかります。

最適化の遅延に対するアジャイルなアプローチの採用

私は常に Slow Roads のコードベースは試験運用版であると考えており、開発において非常にアジャイルなアプローチを取ってきました。急速に進化する複雑なシステム アーキテクチャでは、重要なボトルネックが発生する場所を予測することが困難な場合があります。焦点は、必要な機能をきれいに実装するのではなく、迅速に実装し、それから遡って実際に重要なところにシステムを最適化することです。このステップでは Chrome DevTools のパフォーマンス プロファイラは非常に貴重で、以前のバージョンのゲームに関するいくつかの主要な問題を診断するのに役立ちました。デベロッパーに費やす時間は貴重であるため、重要でない問題や冗長な問題を検討するために時間を費やさないようにしてください。

ユーザー エクスペリエンスのモニタリング

これらすべての手法を実装する際に、実際の環境でゲームが期待どおりに動作するかどうかを確認することが重要です。幅広いハードウェア機能に対応することは、ゲーム開発の重要な要素ですが、ウェブゲームは、ハイエンドのデスクトップと 10 年前のモバイル デバイスの両方を含むはるかに幅広い対象を同時にターゲットに設定できます。これを実現する最も簡単な方法は、プロファイラによって明らかになった、コードベースの最も可能性の高いボトルネック(GPU と CPU 負荷の高いタスクの両方)に適応するための設定を提供することです。

ただし、独自のマシンでのプロファイリングでカバーできる範囲は限られているため、なんらかの方法でユーザーとのフィードバック ループを閉じることが重要です。「スローロード」では、画面解像度などのコンテキスト要素とともにパフォーマンスを報告する簡単な分析を実行しました。 この分析は、ユーザーがゲーム内フォームを介して送信した書面によるフィードバックとともに、socket.io を使用して基本的な Node バックエンドに送信されます。初期のこれらの分析では、UX の簡単な変更で軽減できる多くの重要な問題を検出できました。たとえば、常に低い FPS が検出された場合に、設定メニューをハイライト表示したり、パフォーマンスが著しく低い場合はハードウェア アクセラレーションを有効にする必要があると警告したりするなどが挙げられます。

この先にはスローな道路

これらの対策をすべて行っても、プレーヤー ベースの大部分は、低い設定(主に GPU のない軽量デバイスを使用しているデバイス)で再生しなければならない部分があります。使用可能な品質設定の範囲によってパフォーマンスの分布はほぼ均等になりますが、55 FPS 以上を達成しているプレーヤーは 52% にすぎません。

視聴距離設定と詳細設定で定義されたマトリックスで、さまざまなペア設定で達成された 1 秒あたりの平均フレーム数を示します。分布は 45 ~ 60 でほぼ均等に分散しており、60 が優れたパフォーマンスの目標となっています。設定が低いと、高い設定よりも FPS が小さくなる傾向があり、クライアント ハードウェアの機能の違いが明らかになっています。
このデータは、ハードウェア アクセラレーションを無効にした状態でブラウザを実行しているユーザーによって多少の偏りがあり、多くの場合、人為的にパフォーマンスが低下します。

幸い、パフォーマンスを節約できる余地はまだたくさんあります。GPU の需要を減らすためのレンダリング トリックを追加すると同時に、近い将来、ウェブ ワーカーで環境の生成と並行してテストし、最終的には WASM または WebGPU をコードベースに組み込む必要性が生じるかもしれない。空き容量を増やせば、より豊かで多様な環境を実現でき、それがプロジェクトの残りの期間における永続的な目標となります。

趣味のプロジェクトが進む中、Slow Roads は、驚くほど精巧でパフォーマンスが高く、人気のブラウザゲームがいかに魅力的であるかを示す、圧倒的に充実した方法となっています。私が WebGL に興味を持った方なら、技術的に Slow Roads という機能は、その全機能を網羅している、かなり浅い道路の例です。Three.js ショーケースをぜひご参照ください。特にウェブゲーム開発に関心のある方は、webgamedev.com のコミュニティにぜひご参加ください。