この投稿では、Surreal Engine ゲーム エンジンを WebAssembly に移植する方法について説明します。
https://demensdeum.com/demos/SurrealEngine/”
超現実的なエンジン – Unreal Engine 1 の機能のほとんどを実装するゲーム エンジン、このエンジン上の有名なゲーム -アンリアル トーナメント 99、アンリアル、デウス エクス、アンダイング。これは、主にシングルスレッド実行環境で動作する古典的なエンジンを指します。
私はもともと、妥当な期間内に完了できないプロジェクトに挑戦して、Twitch のフォロワーに私にもできないプロジェクトがあることを示すという考えを持っていました。最初のストリーム中に、Emscripten を使用して Surreal Engine C++ を WebAssembly に移植するタスクが実行可能であることに突然気づきました。
1 か月後、WebAssembly でフォークとエンジンのアセンブリをデモンストレーションできるようになります。
https://demensdeum.com/demos/SurrealEngine/
オリジナルと同様に、コントロールはキーボードの矢印を使用して実行されます。次に、これをモバイル コントロール (タチ) に適応させ、Unreal Championship 99 レンダリングの正しいライティングやその他のグラフィック機能を追加する予定です。
どこから始めればよいですか?
まず最初に言いたいのは、Emscripten を使用すればどんなプロジェクトでも C++ から WebAssembly に移植できるということですが、唯一の問題は機能がどの程度完成するかということです。ライブラリ ポートがすでに Emscripten で使用できるプロジェクトを選択します。 Surreal Engine の場合は、エンジンが SDL 2、OpenAL – を使用しているため、非常に幸運です。図書館。どちらも Emscripten に移植されています。ただし、Vulkan はグラフィックス API として使用されており、現在 HTML5 では利用できません。WebGPU の実装作業は進行中ですが、これもドラフト段階であり、完全に標準化された後、Vulkan から WebGPU へのさらなる移植がどれほど簡単になるかも不明です。したがって、Surreal Engine 用に独自の基本的な OpenGL-ES / WebGL レンダラーを作成する必要がありました。
プロジェクトのビルド
Surreal Engine でシステムを構築 – CMake は、Emscripten がネイティブ ビルダーを提供するため、移植も簡素化します。えむけ、えむけ。
Surreal Engine の移植は、Death-Mask と呼ばれる WebGL/OpenGL ES および C++ で作成した最新ゲームのコードに基づいていました。そのため、開発ははるかに簡単で、必要なビルド フラグとコード サンプルがすべて揃っていました。
CMakeLists.txt の最も重要なポイントの 1 つは Emscripten のビルド フラグです。以下はプロジェクト ファイルの例です。
set(CMAKE_CXX_FLAGS "-s MIN_WEBGL_VERSION=2
-s MAX_WEBGL_VERSION=2
-s EXCEPTION_DEBUG
-fexceptions
--preload-file UnrealTournament/
--preload-file SurrealEngine.pk3
--bind
--use-preload-plugins
-Wall
-Wextra
-Werror=return-type
-s USE_SDL=2
-s ASSERTIONS=1
-w
-g4
-s DISABLE_EXCEPTION_CATCHING=0
-O3
--no-heap-copy
-s ALLOW_MEMORY_GROWTH=1
-s EXIT_RUNTIME=1")
ビルド スクリプト自体:
clear
emmake make -j 16
cp SurrealEngine.data /srv/http/SurrealEngine/SurrealEngine.data
cp SurrealEngine.js /srv/http/SurrealEngine/SurrealEngine.js
cp SurrealEngine.wasm /srv/http/SurrealEngine/SurrealEngine.wasm
cp ../buildScripts/Emscripten/index.html /srv/http/SurrealEngine/index.html

次に、プロジェクト ファイル システム プリローダーを含む index.html を準備しましょう。 Web にアップロードするために、Unreal Championship Demo バージョン 338 を使用しました。CMake ファイルからわかるように、解凍されたゲーム フォルダーがビルド ディレクトリに追加され、Emscripten のプリロード ファイルとしてリンクされています。
メインコードの変更
次に、ゲームのゲーム ループを変更する必要がありました。無限ループを実行することはできません。これによりブラウザがフリーズします。代わりに、emscripten_set_main_loop を使用する必要があります。この機能については、2017 年のメモ「SDL C++ ゲームの HTML5 (Emscripten) への移植」
while ループを終了するコードを if に変更し、ゲーム ループを含むゲーム エンジンのメイン クラスをグローバル スコープに表示し、グローバル オブジェクトからゲーム ループ ステップを呼び出すグローバル関数を作成します。
#if __EMSCRIPTEN__
#include <emscripten.h>
Engine *EMSCRIPTEN_GLOBAL_GAME_ENGINE = nullptr;
void emscripten_game_loop_step() {
EMSCRIPTEN_GLOBAL_GAME_ENGINE->Run();
}
#endif
この後、アプリケーションにバックグラウンド スレッドがないことを確認する必要があります。存在する場合は、シングルスレッド実行用に書き直す準備をするか、Emscripten の phtread ライブラリを使用します。
Surreal Engine のバックグラウンド スレッドは音楽の再生に使用され、データは現在のトラック、音楽の再生の必要性、または音楽の不在に関するメイン エンジン スレッドから取得され、バックグラウンド スレッドはミューテックス経由で新しい状態を受け取り、新しい音楽の再生を開始するか一時停止します。バックグラウンド スレッドは、再生中に音楽をバッファリングするためにも使用されます。
pthread を使用して Emscripten 用の Surreal Engine を構築する試みは失敗しました。SDL2 ポートと OpenAL ポートは pthread サポートなしで構築されており、音楽のために再構築したくなかったためです。そこで、BGM ストリームの機能をループを使用したシングルスレッド実行に移行しました。 C++ コードから pthread 呼び出しを削除することで、バッファリングと音楽再生をメイン スレッドに移動し、遅延がないよう、バッファを数秒増やしました。
次に、グラフィックとサウンドの具体的な実装について説明します。
Vulkan はサポートされていません!
はい、Vulkan は HTML5 ではサポートされていませんが、すべてのマーケティング パンフレットでは Vulkan の主な利点としてクロスプラットフォームおよび広範なプラットフォームのサポートが紹介されています。このため、簡素化された OpenGL タイプの基本的なグラフィックス レンダラーを独自に作成する必要がありました。 ES はモバイル デバイスで使用され、最新の OpenGL のファッショナブルな機能が含まれていない場合もありますが、WebGL に非常によく移植されており、まさに Emscripten が実装しているものです。基本的なタイル レンダリング、最も単純な GUI 表示用の bsp レンダリング、およびモデルとマップのレンダリングの作成は 2 週間で完了しました。おそらくこれがこのプロジェクトで最も困難な部分でした。 Surreal Engine レンダリングの全機能を実装するには、まだ多くの作業が必要です。そのため、読者からのコードやプル リクエストの形での支援を歓迎します。
OpenAL がサポートされています!
幸運なことに、Surreal Engine はオーディオ出力に OpenAL を使用していることです。 OpenAL で単純な Hello World を作成し、Emscripten を使用して WebAssembly で組み立てたので、すべてがいかに単純であるかが明らかになり、サウンドの移植に着手しました。
数時間のデバッグ後、Emscripten の OpenAL 実装にはいくつかのバグがあることが明らかになりました。たとえば、モノラル チャネル数の読み取りを初期化するときにメソッドが無限数を返し、無限サイズのベクトルを初期化しようとすると、C++ が例外 Vector::length_error でクラッシュします。
モノラル チャンネルの数を 2048 にハードコーディングすることで、この問題を回避することができました。
alcGetIntegerv(alDevice, ALC_MONO_SOURCES, 1, &monoSources);
alcGetIntegerv(alDevice, ALC_STEREO_SOURCES, 1, &stereoSources);
#if __EMSCRIPTEN__
monoSources = 2048; // for some reason Emscripten's OpenAL gives infinite monoSources count, bug?
#endif
ネットワークはありますか?
Surreal Engine は現在オンライン プレイをサポートしていませんが、ボットでのプレイはサポートされていますが、これらのボット用の AI を作成する人が必要です。理論的には、Websocket を使用して WebAssembly/Emscripten 上にネットワーク ゲームを実装できます。
結論
結論として、Emscripten ポートが存在するライブラリの使用と、Emscripten 上の WebAssembly 用に C++ でゲームを実装した過去の経験のおかげで、Surreal Engine の移植は非常にスムーズに完了したと言えます。以下は、このトピックに関する知識源とリポジトリへのリンクです。
も、も、も、モンスターを倒せ!
また、できれば WebGL/OpenGL ES レンダリング コードでプロジェクトを支援したい場合は、Telegram で私に書いてください:
https://t.me/demenscave
リンク
https://demensdeum.com/demos/SurrealEngine/
Leave a Reply