WebGL のブラウザ間での互換性
WebGL ビルドのデバッグとトラブルシューティング

WebGL プロジェクトの作成と実行

WebGL プロジェクトを 作成する と、以下のファイルが含まれるフォルダーが Unity によって作成されます。

  • ブラウザからのコンテンツの読み込みをサポートする index.htmlファイル
  • DevelopmentRelease フォルダーに生成したビルド出力ファイルが入ります(Development Build に設定しているかどうかでフォルダー名は変わります)。
  • TemplateData フォルダー。(少なくともデフォルトテンプレートとビルドする場合に)ローディングバーや他のテンプレートアセットが入ります。詳細は WebGL テンプレート のマニュアルページを参照してください。

DevelopmentRelease フォルダーは以下のファイルを中に含みます(MyProject は自身のプロジェクト名と置き換えてください)。リリースビルドを作成した場合、このフォルダーのファイルは圧縮され、拡張子は gz になります。ディストリビューションのサイズのコメントを参照してください。

  • プレイヤー用のコードが含まれた MyProject.js JavaScript ファイル。
  • プレイヤー用のヒープメモリーを初期化するためのバイナリー画像を含んだ MyProject.js.mem ファイル。
  • アセットデータとシーンの含まれる MyProject.data ファイル。
  • UnityLoader.js ファイルは Unity コンテンツを Web ページで読み込むのに必要なコードを中に含んでいます。

index.html ファイルを開くだけで、多くのブラウザーで直接 WebGL プレイヤーを表示できます。セキュリティ上の理由により、Chrome ではローカルの file: URL から開いたスクリプトに対して制限を設けているため、この方法は使えません。Unity の Build & Run コマンド(menu: File > Build & Run )を使っていれば、ファイルは一時的にローカルのウェブサーバーにホストされ、localhost URL から開かれます(これによりセキュリティ上の制限を回避することができます。)。また、Chrome を --disable-web-security オプション付きで起動することで file: の URL で開くことができるようになります。

サーバーでは、 “.mem” と “.data” 拡張子のファイルにアクセスできるよう許可する必要があります。許可してサーバーはクライアントに対象のファイルを提供できるようにしなければいけません。

Build Player Options (ビルドプレイヤーのオプション)

WebGL では、Build Player ウィンドウで Optimization レベルを選択することができます。これらのレベルは Emscripten コンパイラーにパスされる最適化フラグ(-O1 ~ -O3)にそれぞれ呼応しています。基本的には、“Slow” にすると最適化されていないビルドになりますが、ビルド時間は他の選択肢に比べて格段に短くなるため、コードの問題修正の為に何度もビルド作成する場合に便利です。“Fast” では最適化されたビルドになります。“Fastest” だといくつかの追加の最適化項目が加わり、ビルドの完成にかかる時間が長くなります。(したがって、“Fastest” の使用は最終版のリリース時だけにした方がよいかもしれません。)

“Development Build” のチェックボックスをチェックすると、開発(development)ビルドが生成されます。(これは他のプラットフォームの場合と同様、Profiler に対応し、エラー用の開発コンソールを備えたものです。)また、Development ビルドは縮小( minify )されておらず、生成された JavaScript は人間によって読解可能で関数名が保存されたものであるため、エラーの出た際には実際に役立つスタックのトレースが可能ですが、サイズが非常に大きくなります。

“Autoconnect Profiler” のチェックボックスには、Unity WebGL のコンテンツをプロファイルしたい場合は必ずチェックを入れる必要があります。他のプラットフォームのように実行中のビルドに Profiler を繋げることはできません。WebGL ではプロファイラーの接続は WebSockets を使って処理されますが、ブラウザはコンテンツから出て行く接続しか扱えないので、WebGL で Profiler を使用する唯一の方法は “Autoconnect Profiler” にチェックマークを入れてコンテンツがエディターに接続されるようにすることです。

Player Settings (プレイヤー設定)

WebGL では、プレイヤー設定(menu: Edit > Project Settings > Player ) でいくつかの追加オプションが選択可能です。

Other Settings の中の Strip Engine Code のオプションで、WebGL 用のコードの除去が可能になります。Stripping (除去)を有効にすると、使用しないクラスのコードが Unity によって除外されます。したがって、例えば物理コンポーネントや物理メソッドを一切使用しない場合には、物理エンジンが丸ごとビルドから除去されます。詳細は、このページの下部にあるストリッピングについての項目を参照してください。

Publishing SettingsWebGL memory size フィールドでは、コンテンツがそのヒープに対して割り当てるメモリーの大きさを指定できます(単位は MB)。値が小さすぎると、ロードされたコンテンツやシーンが使用可能なメモリーサイズ内に収まらない ‘out of memory’ エラーが頻繁に出てしまいます。逆に値が大きすぎると、一部のブラウザーやマシンでコンテンツがロードできなくなる可能性があります。要求されたヒープサイズに割り当てるための十分なメモリーをブラウザのほうで持ち合わせていない、という事態が起き得るためです。この値は、生成される HTML に “TOTAL_MEMORY” として書き出されています。この値を調整したい場合は、毎回プロジェクトを再ビルドせずに HTML ファイルを直接編集すると楽になります。

Publishing SettingsEnable Exceptions は、WebGL での例外処理を有効/無効にするための機能です。例外処理のサポートが必要ない場合は、“None” に設定してください。None にすることで最小ビルドとなり、ベストパフォーマンスになります。例外が発生した場合は、そのエラーの箇所でゲームコンテンツが停止してしまいます。例外処理を行いたいときは、以下のような設定をしてみてください。

  • Explicitly Thrown Exceptions Only (デフォルト)は、“throw” ステートメントを明示的にスローすることで例外を取得し、“finally” ブロックを書くことで、その中で書いたコードを動かすようにします(try-catch-finally)。これにより、スクリプトから大きく遅い JavaScript コードが生成されてしまいますが、元々スクリプトがボトルネックとなっていないようなコードであれば、さほど問題はないでしょう。
  • Full : 上記に加え、こちらも Null 参照や、“Array Index Out of Bounds” の例外を生成します。これは生成コードへの参照に対するすべてのアクセスにチェックを埋め込むことで生成されるので、コードサイズの増加やスローダウンをもたらします。また、例外に対しマネージドのスタックトレースを付加します。このモードは、コードの問題をデバッグする必要がある時にのみ使用することをお奨めします。

Publishing SettingsData caching チェックボックスは、プレイヤーデータを自動的にローカルへキャッシュするかどうかを設定するためのものです。有効にした場合、アセットはブラウザの IndexedDB のローカルキャッシュとして保存されます。なので初回以降、ゲームコンテンツを再ダウンロードする必要はありません。別のブラウザを使用した時は、そのブラウザのルールに則った IndexedDB なので、ブラウザによってはデータを保存するための許可をユーザーに求めるかもしれませんし、保存できるデータのサイズ制限が違うかもしれません。

ディストリビューションのサイズ

WebGL 用にパブリッシュする際には、コンテンツがスタートする前のダウンロード時間が長くなり過ぎないように、ビルドのサイズを小さく抑えることが大切です。アセットサイズを抑えるための一般的なヒントは、ファイルサイズの削減を参照してください。以下、WebGL に関する追記事項です。

  • 圧縮されたテクスチャはすべて Texture Importer で “Crunch” テクスチャ圧縮フォーマットを指定してください
  • Development Build で書き出さないでください。圧縮や Minified 処理がされないため、サイズが大きくなってしまいます。
  • Optimization Level (最適化レベル) “Fastest” にする。
  • ビルドで例外を必要としない場合は、Player Settings の “Enable Exceptions” を “None” に設定する。
  • Player Settings で “Strip Engine Code” を有効にしましょう。
  • 多くの依存関係や著しく大きなコードサイズとなってしまうようなサードパーティーのマネージド DLL を使用しているときは注意してください。

リリースビルドを行うと、Unity は gzip 圧縮を使用して成果物を出力します。Web サーバーが正しく設定されていると、圧縮されたファイルはダウンロード時にブラウザ側で回答されます。ですが、この処理をブラウザ側が行うにはサーバー側から圧縮されたファイルであるとブラウザ側に伝えなければいけません。もし Apache のウェブサーバーでファイルをホストしている場合は、Unity がビルド リザルトフォルダーに .htaccess ファイルから、転送を圧縮するように Apache に命令するので、正常に機能するはずです。その他のウェブサーバーを使用している場合は、そのサーバーのマニュアルを確認してください。

Web サーバーが Http レベルで gzip 圧縮されたファイルを扱うように設定されていない場合、 Unity 5.3 を起動するのと並行して JavaScript で読み込み時にデータを解凍します。そのため圧縮ファイルを使用することはできますが、データ解凍のために起動時間がわずかながら遅れます。ブラウザの JavaScript コンソールで以下のようなメッセージが表示されている場合、この現象が起きています。

Decompressed Release/build.asm.jsgz in 82ms. You can remove this delay if you configure your web server to host files using gzip compression.

アセットバンドル

すべてのアセットデータはコンテンツが始まる前に事前ダウンロードしておく必要があります。そのため、アセットを主要なデータファイルから切り離し、 アセットバンドル に入れることを検討するべきです。そのほうが素早く読み込める小規模なローダーシーンを作り、コンテンツの進み方に応じて動的にアセットを読み込む、ということができます。また、アセットバンドルは アセットデータメモリ 管理の観点でも有効です。アセットデータをメモリからアンロードすることができるため、AssetBundle.Unload を呼び出す必要はありません。

WebGL プラットフォームでアセットバンドルを使用する場合に考慮すべきことは以下のとおりです。

  • メインビルドで使用されていないクラスをアセットバンドル内で使用する場合、 Unity が該当するクラスをビルドから取り除いてしまう可能性があります。これによりアセットバンドルからアセットを読み込むのに失敗するかもしれません。この問題の解決については以下の ストリッピング セクションを参照してください。

  • WebGL はスレッドをサポートしておらず、 Http ダウンロードが終わってから利用可能になるため Unity WebGL ビルドはダウンロードが終わってからアセットバンドルのデータをメインスレッド上で解凍する必要があり、メインスレッドをブロックすることになります。これを避けるためには、アセットバンドルでデフォルトで設定されている LZMA フォーマットを使用せず、 LZ4 を使用して圧縮することです。そうすると要求に応じてとても効果的に解凍できます。 LZ4 でより圧縮ファイルのサイズを抑えたい場合、 Web サーバーに Http プロトコルレベルで(LZ4圧縮で一番圧縮率の高い) gzip 圧縮をファイルに行うよう設定できます。

  • WWW.LoadFromCacheOrDownload を使用するアセットバンドルキャッシュは WebGL でサポートされています。WebGL はユーザーのコンピューターでキャッシュを実行するためにブラウザから IndexedDB API を使用します。ブラウザによっては IndexedDB の サポート が制限されている可能性もあるので注意してください。また、制限されているブラウザを使用する場合、ディスクにデータを保存する権限をユーザーに求めるかもしれません。

ストリッピング

初期設定では、 Unity はビルドでコードストリッピングを行います。この設定は Other SettingsStrip Engine Code オプションから行えます。コードストリッピングは UnityObject を継承するクラスが使用するものすべてに対して(スクリプトコードで参照しているもの、各シーンでシリアライズされているデータもまとめて)スキャンを行い、クラスがビルドで使用されていないすべての Unity サブシステムを取り除きます。これによりビルドのコード量は削減され、その結果ダウンロード量、その後のコード変換量も減ります(コードの変換が高速になり、メモリ使用量が減るということです)。そのため、一般的には Strip Engine Code は常に有効にしてビルドするのが賢明です。

しかし、コードストリッピングがプロジェクトや必要なストリップコードで問題を引き起こすことがあります。これはメインビルドに含まれていないクラスを使用している AssetBundle を実行時に読み込んでしまい、それらがプロジェクトから取り除かれているために起こります。そのような事態が起こった場合、ブラウザの JavaScript コンソールに以下のようなエラーが表示されていると思われます(潜在的にもっとエラーが起こっているかもしれません)。

Could not produce class with ID XXX
  • どのクラスがインスタンスを作成しようとしているかを表す Class ID ReferenceXXX と表示されるかもしれません。その場合 Unity に対して該当クラスのコードをビルドに含めるよう強制することができます。その方法とはスクリプトやシーンからクラスに対して参照を持つようにすることと、プロジェクトの link.xml ファイルを追加することです。以下は Collider クラス(とそれに伴う物理モジュール)をプロジェクトに含めさせる例です。以下の xml コードを link.xml と名付け、そのファイルを Assets フォルダーに配置してください。
<linker>
    <assembly fullname="UnityEngine">
        <type fullname="UnityEngine.Collider" preserve="all"/>
    </assembly>
</linker>

ストリッピングがビルドで問題になっているのではないか疑問に思った場合、テストのために Strip Engine Code オプションを無効にすることはいつでもできます。

Unity には今のところどのモジュールとクラスがビルドに含まれているのかを知り、ストリップを効率的に行ってプロジェクトを最適化できる便利な方法はありません。その情報を提供できるよう作業を行っていますが、提供できるまではビルド後に作成される Temp/StagingArea/Data/il2cppOutput/UnityClassRegistration.cpp を見るようにしてください。そちらからビルドに含まれているクラスとモジュールの概要を見られます。

Strip Engine Code オプションは Unity エンジンコードにのみ影響することに注意してください。 IL2CPP は常に管理された DLL とスクリプトから生成されるバイトコードを取り除きます。これによってコードからの静的参照ではなくリフレクションを使って管理された型を動的に参照したい場合に問題になるかもしれません。リフレクションを使って型にアクセスする必要があれば、それらの型を保護するために link.xml ファイルを設定する必要もあるかもしれません。 link.xml ファイルについてより情報が必要であれば iOS Build size optimization のドキュメントを参照してください。

ビルド出力ファイルの移動

出力ファイルの index.html ファイルからの相対位置を変更したい場合、 dataUrl, codeUrl, memUrl フィールドと index.html ファイルの UnityLoader.js スクリプトタグを編集してください。 CDN でファイルを扱いたい場合、外部サーバーの URL を指定してください。その場合は動作させるためにホスティングサーバーの CORS を確実に有効にする必要があります。CORS についてより情報が知りたければ WebGL ネットワーキング のマニュアルを参照してください。

WebGL のブラウザ間での互換性
WebGL ビルドのデバッグとトラブルシューティング