Babylon.jsを使用したクロスプラットフォームWebGLゲームの構築
公開: 2022-03-10ここにあなたにとっての挑戦があります:週末に3Dゲームを構築するのはどうですか? Babylon.jsは、 HTML5、WebGL、およびWebオーディオを使用して3Dゲームを構築するためのJavaScriptフレームワークであり、あなたとBabylon.jsチームによって構築されています。 ライブラリの新しいバージョン2.3を祝うために、「Sponza」という名前の新しいデモを作成して、今日の優れたゲームの作成に関してWebGLエンジンとHTML5で何ができるかを強調することにしました。
アイデアは、WebGLがサポートするすべてのプラットフォームで一貫性のある、類似した、または同一ではないエクスペリエンスを作成し、ネイティブアプリの機能に到達しようとすることでした。 この記事では、すべてがどのように連携するかを、私たちが直面したさまざまな課題と、それを構築する際に学んだ教訓とともに説明します。
SmashingMagの詳細:
- Babylon.jsを使用したシェーダーの構築
- WebゲームでのゲームパッドAPIの使用
- ポリゴンモデリングとThree.jsの紹介
- レスポンシブな8ビットドラムマシンを作成する方法
この目標を達成するために、Sponzaは、WebGL、Webオーディオ、ポインターイベント(jQuery PEPポリフィルのおかげで現在広くサポートされています)、Gamepad API、IndexedDB、HTML5 AppCache、CSS3トランジション/アニメーション、フレックスボックス、フルスクリーンなどのHTML5機能を多数使用しています。 API。 Sponzaデモは、デスクトップ、モバイル、またはXboxOneでテストできます。
デモの発見
まず、シーンを作成した人にクレジットを与える自動アニメーションシーケンスから始めます。 チームのメンバーのほとんどはデモシーンから来ています。 これが3D開発者の文化の重要な部分であることがわかります。 私の側では、David CatuheがAmigaにいる間、私はAtariにいました。これは、信じられないかもしれませんが、私たちの間の定期的な紛争の原因です。 私は少しコーディングしていましたが、主にデモグループの音楽を作曲していました。 私はFutureCrewの大ファンであり、より具体的には、私のお気に入りのデモシーン作曲家であるPurpleMotionの大ファンでした。 しかし、トピックから逸脱しないようにしましょう。
Sponzaの場合、寄稿者は次のとおりです。
- ミシェル・ルソー、別名「ミッチ」は、3Dアーティストとして、優れたビジュアルアニメーションとレンダリングの最適化を行ってきました。 CrytekがWebサイトで無料で提供しているSponzaモデルを使用し、3DSMaxエクスポーターを使用して表示内容を生成しました。
- David Catuhe 、別名「deltakosh」と私は、Babylon.jsエンジンのコア部分と、デモのすべてのコード(カスタムローダー、フェードトゥブラック後処理を使用したデモモードの特殊効果など)を実行しました。すべてのタイプの入力を一般的な方法で処理する「 UniversalCamera 」という名前の新しいタイプのカメラ。
- RenoiseとEastWestSymphonicOrchestraサウンドバンクを使用して音楽を作曲しました。 興味のある方は、RenoiseトラッカーとEast WestVSTプラグインを使用したWorldMonger Windows8ゲームの音楽の作成に関する記事でワークフローとプロセスをすでに共有しています。
- Julien Moreau-Mathisは、3Dアーティストがモデリングツール(3DS Max、Blender)と最終結果の間で作業を完了するのに役立つ新しいツールを構築することで私たちを助けてくれました。 たとえば、Michelはこれを使用して、さまざまなアニメーションカメラをテストおよび調整し、シーンにパーティクルを注入しました。
自動シーケンスが終了して「エピックフィニッシュ」になるまで待つと、自動的にインタラクティブモードに切り替わります。 デモモードをバイパスする場合は、カメラアイコンをクリックするか、ゲームパッドA
を押します。
インタラクティブモードでは、MacまたはPCを使用している場合、FPSゲームのようにキーボード/マウスを使用してシーン内を移動できます。 スマートフォンを使用している場合は、ワンタッチで移動できます(カメラを回転させるには2
)。 最後に、Xbox Oneでは、ゲームパッド(またはゲームパッドを接続している場合はデスクトップ)を使用できます。 おもしろい事実:Windows touch PCでは、3種類の入力を同時に使用できる可能性があります。
インタラクティブモードでは雰囲気が違います。 3D環境にランダムに配置された3つのストームオーディオソースがあり、各コーナーに風が吹き、火が割れます。 サポートされているブラウザ(Chrome、Firefox、Opera、Safari)では、専用のアイコンをクリックすることで、通常のスピーカーモードとヘッドフォンモードを切り替えることもできます。 次に、Web Audioのバイノーラルオーディオレンダリングを使用して、より現実的なオーディオシミュレーションを行います—ヘッドフォンで聞いている場合。
完全なアプリのようなエクスペリエンスを実現するために、すべてのプラットフォーム用のアイコンとタイルを生成しました。 これは、たとえば、Windows 8⁄10では、Webアプリを[スタート]メニューに固定できることを意味します。 複数のサイズもご利用いただけます。
最初にオフライン!
デモが完全に読み込まれたら、携帯電話を機内モードに切り替えて接続を切断し、Sponzaアイコンをクリックできます。 Webアプリは、WebGLレンダリング、3D Webオーディオ、およびタッチサポートの完全なエクスペリエンスを引き続き提供します。 フルスクリーンに切り替えると、文字通り、デモとネイティブアプリのエクスペリエンスの違いを感じることができなくなります。
そのために、Babylon.js内でネイティブに利用可能なIndexedDBレイヤーを使用しています。 シーン(JSON形式)とリソース(JPG / PNGテクスチャ、および音楽とサウンドのMP3)はIDBに保存されます。 IDBレイヤーとHTML5アプリケーションキャッシュを組み合わせることで、オフラインエクスペリエンスが提供されます。 この部分の詳細と、同様の結果を得るためにゲームを構成する方法については、IndexedDBを使用した3D WebGLアセットの処理に関する記事を読むことができます:Babylon.JSのフィードバックとヒントの共有およびBabylon.jsのIndexedDBのリソースのキャッシング
XboxOneはショーを楽しんでいます
最後になりましたが、XboxOneのMSEdgeでもまったく同じデモが問題なく機能します。
A
を押してインタラクティブモードに切り替えます。 Xbox Oneは、3Dシーン内でゲームパッドを使用して移動できるようになったことを通知します。
それでは、簡単に要約しましょう。
まったく同じコードベースが、Mac、Linux、MS Edge上のWindows、Chrome、Firefox、Opera、Safari、iPhone / iPad、ChromeまたはFirefoxを搭載したAndroidデバイス、Firefox OS、XboxOneで機能します。 かっこいいじゃないですか。 Webサーバーから直接、本格的なネイティブのようなエクスペリエンスで非常に多くのデバイスをターゲットにできるでしょうか。
ウェブ上の以前の記事で、テクノロジーの可能性についての興奮をすでに共有しました。次のゲームのフロンティアですか?
デバッグレイヤーでシーンをハックする
ミシェルが3Dモデリングの魔法をどのように習得しているかを理解したい場合は、Babylon.jsデバッグレイヤーツールを使用してシーンをハックできます。 キーボードを備えたマシンで有効にするには、 CMD/CTRL + SHIFT + D
を押し、PCまたはXboxでゲームパッドを使用している場合は、 Y
を押します。 デバッグレイヤーの表示は、レンダリングエンジンが実行する必要のある合成ジョブのため、パフォーマンスが少し低下することに注意してください。 したがって、表示されるFPSは、デバッグレイヤーが表示されていない実際のFPSよりも少し重要ではありません。
たとえば、PCでテストしてみましょう。
ライオンの頭の近くに移動し、シェーダーのパイプラインからバンプチャネルを切り取ります。
頭があまり現実的ではなくなっていることがわかります。 他のチャンネルで遊んで、何が起こっているかを確認してください。
ダイナミックライトニングエンジンをカットしたり、衝突エンジンを無効にして壁を飛んだり移動したりすることもできます。 たとえば、「衝突」チェックボックスを無効にして、1階に飛んでください。 カメラを赤い旗の前に置きます。 あなたはそれらがわずかに動いているのを見ることができます。 ミシェルは、Babylon.jsのボーン/スケルトンサポートを使用してそれらを移動しました。 ここで、「スケルトン」オプションを無効にすると、移動が停止するはずです。
最後に、右上隅にメッシュツリーを表示できます。 それらを有効または無効にして、Michelが行った作業を完全に中断することができます。
ジオメトリ、シェーダーのチャネル、またはエンジンの一部のオプションを削除すると、特定のデバイスでのパフォーマンスのトラブルシューティングを行って、現在コストがかかりすぎているものを確認するのに役立ちます。 また、CPUが制限されているかGPUが制限されているかを確認することもできますが、ほとんどの場合、JavaScriptのモノスレッドの性質により、WebGLではCPUが制限されます。 最後に、このツールは、3Dアーティストによってシーンがどのように作成されたかを学習するのにも非常に役立ちます。
ちなみに、XboxOneでもかなりうまく機能します。
課題
その過程で、デモを作成するための多くの問題と課題に直面しました。 それらのいくつかを詳しく調べてみましょう。
WebGLのパフォーマンスとクロスプラットフォームの互換性
プログラミング側は、Babylon.jsエンジン自体によって完全に処理されるため、おそらく最も簡単に取り組むことができました。 さまざまなフォールバックを使用して、現在のブラウザー/ GPUで利用可能な最適なシェーダーを見つけようとすることで、プラットフォームに適応するカスタムシェーダーのアーキテクチャを使用しています。 アイデアは、画面上に意味のあるものを表示できるようになるまで、レンダリングエンジンの品質と複雑さを下げることです。
Babylon.jsは主にWebGL1.0に基づいており、その上に構築された3Dエクスペリエンスがほぼすべての場所で実行されることを保証します。 Web哲学を念頭に置いて構築されているため、シェーダーのコンパイルプロセスを段階的に強化しています。 これは、これらの複雑さにほとんど対処したくない3Dアーティストにとっては完全に透過的です。
それでも、3Dアーティストはパフォーマンスの最適化において非常に重要な役割を果たします。 彼女は、ターゲットにしているプラットフォーム、サポートされている機能、および制限を知っている必要があります。 ハイエンドGPUおよびDirectX12用に作成されたAAAゲームからのアセットを取得して、それらをWebGLエンジンで実行されるゲームに統合することはできません。 今日のWebGLのターゲティングは、モバイルデバイスでのエクスペリエンスを最適化するために行う必要のある作業と非常に似ていますが、高度にモノスレッド化する必要のあるJavaScriptが少し追加されています。
Mitchは、テクスチャの最適化、稲妻を事前に計算してテクスチャに焼き付ける、描画呼び出しの数を可能な限り減らすなど、非常に優れています。彼は長年の経験があり、さまざまな世代のデモを実現するのに本当に役立った3Dハードウェアとエンジン(PowerVR / 3DFXから今日のGPUまで)。
彼は、リアルタイム3Dに関する記事で、これらの基本事項の一部をすでに共有しています。WebGLの目的-基本事項のデモを作成し、小さな統合GPUで高性能を使用して、Web上で非常に魅力的なビジュアルエクスペリエンスを作成できることを何度か証明しました。マンション、ヒルバレー、またはエスピリットのデモシーン。 興味のある方は、NGF2014 –モバイルワールドとウェブ用の3Dアセットの作成、彼の経験を共有した3Dデザイナーの視点、ヒルバレーシーンを最適化する方法についての彼の講演をご覧ください。 1fps未満から60fps。
Sponzaの最初の目標は、2つのシーンを作成することでした。 1つはデスクトップ用で、もう1つはモバイル用で、複雑さが少なく、テクスチャが小さく、メッシュとジオメトリが単純です。 しかし、テスト中に、iPhone6sまたはAndroidOnePlus2で最大60fpsを実行できるため、デスクトップバージョンもモバイルでかなり正常に実行されていることが最終的にわかりました。その後、より単純なモバイルバージョンでの作業を継続しないことにしました。
しかし、繰り返しになりますが、Sponzaでクリーンなモバイルファーストのアプローチを採用して、多くのモバイルデバイスで30 fps以上に到達し、次にハイエンドのモバイルとデスクトップのシーンを強化したほうがよいでしょう。 それでも、Twitterでこれまでに受け取ったフィードバックのほとんどは、最終結果がほとんどのデバイスで非常にうまく機能していることを示しているようです。 確かに、SponzaはHD4000 GPU(Intel Core i5統合)で最適化されています。これは、実際のハイエンドモバイルのGPUとほぼ同等です。
何とか達成できたパフォーマンスには非常に満足していました。 Sponzaは、アンビエント、ディフューズ、バンプ、スペキュラー、リフレクションを有効にしたシェーダーを使用しています。 インタラクティブモードを使用して移動しているときの、各コーナーでの小さな火、赤い旗のアニメーションボーン、3D配置サウンド、および衝突をシミュレートするためのパーティクルがいくつかあります。
技術的に言えば、シーンで使用されるメッシュは98個あり、最大377781個の頂点、16個のアクティブなボーン、最大36個の描画呼び出しを生成できる60個以上のパーティクルを生成します。 私たちは何を学びましたか? 確かなことの1つは、描画呼び出しを少なくすることが最適なパフォーマンスの鍵であり、Webではさらに重要です。
ローダー
Sponzaの場合、BabylonJS Webサイトで使用しているデフォルトのローダーとは異なる新しいローダーを作成して、クリーンで洗練されたWebアプリを作成したいと考えました。 それから私はミシェルに何か新しいことを提案するように頼んだ。
彼は最初に次の画面を私に送信しました。
確かに、最初に見たときの画面はとてもきれいに見えます。 しかし、それなら、本当にレスポンシブな方法で、すべてのデバイスでどのように機能させるのか疑問に思うかもしれません。 それを理解しましょう。
まず背景についてお話しましょう。 ミシェルによって作成されたぼやけた効果は素晴らしいものでしたが、すべてのウィンドウサイズと解像度でうまく機能せず、モアレが発生していました。 次に、シーンの「クラシック」スクリーンショットに置き換えました。 ただし、黒いバーがなく、画像を引き伸ばして比率を壊さずに、背景を画面全体に表示したかったのです。
解決策は主にCSS background-size: cover
+画像をX軸とY軸の中央に配置します。 その結果、使用されている画面の比率に関係なく、私が探していた経験が得られます。
他の部分は、古き良きパーセンテージベースのCSSポジショニングを使用しています。 さて、それを並べ替えたら、タイポグラフィをどのように処理しますか?フォントサイズはビューポートのサイズに基づく必要があります。 もちろん、そのためにビューポートユニットを使用できます。 vw
とvh
(1vwはビューポート幅の1%、1vhはビューポート高さの1%)は、ブラウザー全体、特にすべてのWebGL互換ブラウザーでかなりよくサポートされています。 (SmashingMagazineのViewportSized Typographyに関する記事もあり、読むことを強くお勧めします。)
最後に、背景画像のopacity
プロパティを操作して、現在のダウンロードプロセスが0から100%に移動することに基づいて、背景画像を0
から1
に移動します。
ちなみに、テキストアニメーションは、CSSトランジションまたはフレックスボックスレイアウトと組み合わせたアニメーションを使用して簡単に実行され、中央または各コーナーに表示するためのシンプルで効率的な方法があります。
すべての入力を透過的に処理する
私たちのWebGLエンジンは、すべてのプラットフォームでビジュアルを正しく表示するために、レンダリング側ですべての作業を行っています。 しかし、入力タイプが何であれ、ユーザーがシーン内を移動できることをどのように保証できますか?
以前のバージョンのBabylon.jsでは、キーボード/マウス、タッチ、仮想タッチジョイスティック、ゲームパッド、デバイスオリエンテーションVR(カードボード用)、WebVRなど、すべてのタイプの入力とユーザーの操作をそれぞれ専用カメラ経由でサポートしていました。 それらについてもう少し学ぶために私たちのドキュメントを読むことができます。
タッチは、jQuery PEPポリフィルを介してすべてのプラットフォームに伝達されるポインターイベント仕様で普遍的に管理されています(必要に応じてアプリのタッチイベントを生成します)。 ポインターイベントの詳細については、タッチとマウスの統合について読むことができます。ポインターイベントによってブラウザー間のタッチサポートが簡単になる方法
その後、デモに戻ります。 Sponzaのアイデアは、デスクトップ、モバイル、コンソールのすべてのユーザーのシナリオを一度に処理する独自のカメラを持つことでした。
最終的にUniversalCameraを作成しました。 正直なところ、作成するのは非常に明白で簡単だったので、なぜ以前に作成しなかったのかまだわかりません。 UniversalCameraは、多かれ少なかれ、FreeCameraを拡張するTouchCameraを拡張するゲームパッドカメラです。
FreeCameraはキーボード/マウスロジックを提供しています。 TouchCameraはタッチロジックを提供し、最後の拡張はゲームパッドロジックを提供します。
UniversalCameraは、デフォルトでBabylon.jsで使用されるようになりました。 デモを閲覧している場合は、すべてのデモでマウス、タッチ、ゲームパッドを使用してシーン内を移動できます。 繰り返しになりますが、コードを調べて、それがどのように正確に行われているかを確認できます。
トランジションを音楽と同期させる
さて、この部分は私たちが自分自身にほとんどの質問をしたところです。 紹介シーケンスが音楽プレイトラックの特定の領域と同期していることに気付いたかもしれません。 最初の行は、いくつかのドラムがキックインしたときに表示され、最後の終了シーケンスは、使用しているホーン楽器の各ノートで1つのカメラから別のカメラにすばやく切り替わります。
オーディオとWebGLレンダリングループの同期は簡単ではありません。 繰り返しますが、これはJavaScriptのモノスレッドの性質であり、この複雑さを生み出します。 HTML5 Webワーカーの概要に関する記事:JavaScriptマルチスレッドアプローチは、その背後にあるいくつかの洞察を共有しています。 私たちが直面している地球規模の問題を理解するために問題を理解することは本当に重要ですが、ここで詳細に立ち入ることはこの記事の範囲外です。
通常、デモシーン(およびビデオゲーム)では、ビジュアルをサウンド/音楽と同期させたい場合は、オーディオスタックによって駆動されます。 2つのアプローチがよく使用されます。
- オーディオファイルに挿入されるメタデータを生成し、その特定の部分に到達したときにいくつかのイベントを「呼び出す」ことができます。
- FFTまたは同様のテクノロジーを介したオーディオストリームのリアルタイム分析により、ビジュアルエンジンのイベントを再度生成する興味深いピークまたはBPMの変化を検出します。
これらのアプローチは、C ++のようなマルチスレッド環境で特にうまく機能します。 しかし、JavaScriptでは、Web Audioを使用すると、2つの問題が発生します。
- JavaScriptはモノスレッドであり、残念ながら、ほとんどの場合、Webワーカーは実際には役に立ちません。
- Web Audioには、Web Audioがブラウザによって別のスレッドで処理されている場合でも、UIスレッドに送り返される可能性のあるイベントはありません。
Web Audioには、JavaScriptよりもはるかに正確なタイマーがあります。 別のスレッドでこの別のタイマーを使用して、イベントをUIスレッドに戻すことができれば素晴らしいと思います。 しかし、今日、あなたはそれをすることができません(まだ?)。
一方、WebGLとrequestAnimationFrame
メソッドを使用してシーンをレンダリングしています。 これは、「最良の場合」には、16ミリ秒のウィンドウ時間枠があることを意味します。 欠落している場合は、サウンドの同期を反映するために次のフレームで動作できるようになるまで(たとえば、「フェードトゥブラック」エフェクトを起動するために)最大16ミリ秒待つ必要があります。
次に、同期ロジックをrequestAnimationFrame
ループに挿入することを考えていました。 シーケンスの開始から費やした時間を調査し、オーディオイベントに反応するようにビジュアルを調整するオプションを検討しました。 良いニュースは、WebオーディオがメインUIスレッドで何が起こっているかに関係なくサウンドをレンダリングすることです。 たとえば、GPUがシーンのレンダリングに苦労している場合でも、音楽の12秒のタイムスタンプが音楽の再生開始から正確に12秒後に到着することを確認できます。
結局、私たちはついにこれまででおそらく最も単純な解決策を選択しました: setTimeout()
呼び出しを使用する! はい、知っています。 上でリンクした記事を含め、そこにあるほとんどの記事を調べると、非常に信頼性が低いことがわかります。 しかし、私たちの場合、シーンをレンダリングする準備ができたら、すべてのリソース(テクスチャとサウンド)をダウンロードし、シェーダーをコンパイルしたことがわかります。 UIスレッドを飽和させる予期しないイベントに煩わされすぎないようにする必要があります。 GCは問題になる可能性がありますが、エンジンでのGCとの戦いにも多くの時間を費やしました。InternetExplorer11のF12開発者バーを使用してガベージコレクターへの圧力を軽減します。
それでも、このソリューションが理想的とはほど遠いことはわかっています。 別のタブに切り替えるか、電話をロックして数秒後にロックを解除すると、デモの同期部分で問題が発生する可能性があります。 これらの問題は、Page Visibility APIを使用することで修正できます。たとえば、レンダリングループ、さまざまなサウンドを一時停止し、 setTimeout()
呼び出しの次の時間枠を再計算します。
しかし、おそらく私たちは何かを逃したのを見逃しました。 多分、そしておそらく、この問題を処理するためのより良いアプローチがありました。 同じ問題を解決するためのより良い方法があると思われる場合は、コメントセクションであなたの考えや提案を聞いてみたいと思います。
iOSでのWebオーディオの処理
私があなたと共有したい最後の課題は、iPhoneとiPad上のiOSによってWebオーディオが処理される方法です。 「ウェブオーディオ+ iOS」に関する記事を探していると、iOSでサウンドを再生するのに苦労している人がたくさんいます。 さて、そこで何が起こっているのですか?
iOSは、バイノーラルオーディオモードでさえも、Webオーディオを驚くほどサポートしています。 しかし、Appleは、特定のユーザーの操作なしでは、Webページはデフォルトでサウンドを再生できないと判断しました。 この決定は、迷惑な音を再生することによってユーザーを邪魔する広告やその他のものを避けるために行われた可能性があります。
Web開発者にとってそれはどういう意味ですか? さて、ユーザーがタッチした後、サウンドを再生する前に、まずiOSのWebオーディオコンテキストのロックを解除する必要があります。 そうしないと、Webアプリケーションは必死にミュートされたままになります。
残念ながら、このチェックを行う唯一の方法は、機能検出の方法が見つからなかったため、ユーザープラットフォームのスニッフィングアプローチを実行することでした。 それは恐ろしい、防弾技術にほかなりませんが、問題を解決する他の解決策を見つけることができませんでした。 コード? どうぞ!
iPad / iPhone / iPodを使用していない場合は、オーディオコンテキストをすぐに使用できます。 それ以外の場合は、タッチエンドイベントでコード生成された空のサウンドを再生することにより、iOSのオーディオコンテキストのロックを解除します。 ゲームを起動する前にonAudioUnlockedイベントを待ちたい場合は、 onAudioUnlockedイベントに登録できます。 したがって、iPhone / iPadでSponzaを起動する場合は、読み込みシーケンスの最後に次の最終画面が表示されます。
画面の任意の場所をタッチすると、iOSのオーディオスタックのロックが解除され、「ショー」が起動します。
だからここに行きます! デモの開発の背後にあるいくつかの洞察を楽しんでいただけたと思います。 詳細については、GitHubでこのデモの完全なソースコードをお読みください。 明らかに、すべてがオープンソースであり、GitHubでメインファイル(index.jsとbabylon.demo.ts)を見つけることができます。
最後になりますが、Webが間違いなくゲームに最適なプラットフォームであると、さらに確信していただけると幸いです。 現時点で新しいデモに取り組んでいるので、しばらくお待ちください。それらも非常に印象的なものになることを願っています。
この記事は、実用的なJavaScript学習、オープンソースプロジェクト、およびMicrosoftEdgeブラウザーを含む相互運用性のベストプラクティスに関するマイクロソフトの技術エバンジェリストおよびエンジニアによるWeb開発シリーズの一部です。dev.microsoftedge.comの無料ツール(F12開発者ツールを含む)を使用して、Microsoft Edge(Windows 10のデフォルトブラウザー)を含むブラウザーとデバイス間でテストすることをお勧めします。デバッグ、テスト、およびWebページを高速化します。 また、Edgeブログにアクセスして、Microsoftの開発者や専門家から最新情報を入手してください。