Search Unity

Unity WebGL ビルドターゲットの出力形式をWebAssembly(Wasm)に切り替える計画を本ブログで発表してから、かなりの年月が経ちました。この変更が Unity 2018.2 で実装されます。そこで本記事では、これまでの経緯と、この変更がインタラクティブウェブコンテンツを制作する皆様にとって何を意味するのかをご説明したいと思います。

Wasm 導入に至った経緯

WebAssembly への対応は Unity 5.6 で試験的に実装されました。これは WebAssembly が主要な 4 種のデスクトップブラウザーで利用可能になったのとほぼ同時期です。以来 Unity およびこれらのブラウザーに各種改良とバグ修正が加えられると同時に、これを導入するユーザーが増加し、多くの肯定的なフィードバックが寄せられました。これを受け、次のステップとして、満を持して正式対応に踏み切ることになりました ― Unity 2018.1 では WebAssembly は実験的な機能ではなくなり、Wasm 単独でのビルド作成機能が実装されました。

そしてバージョン 2018.2 でついにデフォルトの Linker Target が asm.js から Wasm に切り替わりました。

したがって、Unity 2018 で Unity WebGL ビルドターゲット用にパブリッシュする場合の LTS ストリームのデフォルトは Wasm となります。

これは、Unity が長期にわたって目標として来た重要なマイルストーンです。これを行うに当たっては、いくつかの条件を満たす必要がありました。具体的には Unity の実装とブラウザー対応を安定させることと、内部でのテストカバレッジに Wasm を含めることで、そのためには Emscripten のアップグレードとコード中のいくつかの問題の修正も必要でした。

今日では Wasm のバリエーションがすべてのテストスイート用に揃っているので、メインラインにマージされる変更に関してはすべて WebAssembly に対するテストが行われています。

(注)asm.js テストスイートも引き続き維持および実行されますが、メインラインに反映されるすべての変更は Wasm に対してテストされるようになっています。

WebAssembly と asm.js

ここで、WebAssembly に関する詳細と、asm.js との主な相違点を見ていきましょう。

asm.js と比較すると Wasm のほうが速く、サイズが小さく、メモリ効率が高くなります。これらはすべて Unity WebGL エクスポートにおいて課題となる要素です。Wasm で既知の問題がすべて解決されるとは限りませんが、プラットフォームを全面的に向上させることは確かです。ただし、パフォーマンスはブラウザーの実装によって変わりますのでご注意ください。主要なブラウザーのベンダーがすべて、WebAssembly への対応と改善を計画していることは、朗報だと思われます。

Wasm ファイルを開くと、これが(テキストである asm.js とは異なり)バイナリファイルであることがすぐ分かるでしょう。コードの配信方法としては、こちらのほうがよりコンパクトである一方、デバッグ用に読み出したり変更を加えたりすることは不可能となります。

Wasm が独自の命令セットを持つのに対し、asm.js は「高度に最適化可能な」JavaScript のサブセットです。WebAssembly は、開発ビルドではより精密な算術演算のエラー検知を提供し、ゼロ除算や大きな浮動小数点数から整数への四捨五入などの例外を投げることができます。開発ビルドでない場合、このような算術エラーの検知はマスクされるので、ユーザー体験には影響を及ぼしません。

コードサイズ

Unity では WebAssembly の生成用に(IL2CPPemscriptenbinaryen に基づく)複雑なツールチェインを提供しており、これが C/C++ および C# コードを WebAssembly に変換します。これによりバイナリファイル(< ビルド名>.wasm.code.unityweb)が作成され、結果としてコードサイズが asm.js より小さくなります。

これに対し、開発ビルドの場合、コードサイズは数十 MB 小さくなり、開発ビルドでない場合は数百 KB 小さくなります。大まかな基準としては、空のプロジェクトのコードサイズは最大 12%(3D 物理演算が含まれる場合は最大 18%)小さくなります。

(注)これは、不要なパッケージやシェーダー内でビルドされた要素をすべて除いて、圧縮形式は Brotli を用いて計測されています。

すべての改良(パフォーマンス、メモリ、ロード時間)について言えることですが、効果の度合いはプロジェクトによって異なります。

メモリ

asm.js を使用した場合に生じる制約のひとつは、Unity ヒープ のサイズ制限でした。Unity ヒープのサイズはビルド時に指定する必要があり、変更は不可能でした。WebAssembly では Unity ヒープのサイズがランタイムで増加可能であるため、Unity コンテンツの使用メモリが、開始時に指定されたヒープサイズを超過できます。

つまり、以前は不可能だった「小さなヒープ(例えば 32MB)でコンテンツを開始し、必要に応じてサイズを増加させる」ということが可能となりました。

memorySize の値が、コンテンツ開始時の初期サイズであると考えてください。これはバージョン 2018.2 で搭載された機能ですので現在利用可能です。ただし asm.js もターゲットにしている場合は、ヒープのサイズを変更できないため、このアプローチは不可能です。

ヒープのサイズが増加し過ぎるとブラウザーがメモリ不足になる可能性があることにご注意ください。この限界はブラウザーによって異なります。すべてのブラウザーで挙動を一貫させるには、Unity ヒープの最大サイズを設定してください。これは、エディタースクリプト内で Emscripten に引数 “-s WASM_MEM_MAX=< メモリサイズの値>” を設定することで行えます(以下の例をご覧ください)。

最大メモリサイズは 2032 で、これを超えるとブラウザーでランタイムエラーが発生します。

また、ロード時のメモリ効率は Wasm のほうが高くなります。したがって、多くのユーザーが asm.js で(特に 32 ビットブラウザーで)直面するメモリ不足の問題が削減されます。

Unity WebGL でメモリが機能する仕組みについてはこちらのブログ記事をご覧ください。

パフォーマンス

Wasm と asm.js のパフォーマンスの差はブラウザーによって異なります。バイナリ形式である Wasm は、JavaScript テキストファイルとして解析される asm.js より格段に速く読み込みを行える可能性を持っています。

これに加え、すでにコンパイル済の wasm コードモジュールは IndexedDB キャッシュ内に保管することができるので、同じコンテンツをリロードする場合は、起動が非常に速くなります。Wasm キャッシングを利用するには、Data Caching のオプションを有効にしてください。

起動後の実行速度は、JavaScript エンジン内ですでに asm.js スタイルのコード用に最適化してあるブラウザー上で asm.js を実行した場合に匹敵します。これまで asm.js を認識していなかったブラウザー上で Wasm を実行する場合は格段に速度が上がるはずです。

コードによっては、64 ビット整数演算などの(asm.js が固有の命令を持たない)一部の命令は、Wasm のほうが速くなる場合があります。

マルチスレッディング

WebAssembly マルチスレッディングへの対応は、恐らく最も待ち望まれていた機能であり、パフォーマンスを最も向上させるものです。これは今年、より早い段階でブラウザーに提供される予定でしたが、この実現に必要な要素のひとつである SharedArrayBuffer への対応を(Spectre と Meltdown に起因した安全性に関わる懸念のために)無効化する必要がありました。ありがたいことに、SAB の再有効化を可能にするためのブラウザーの安全対策がこの数か月間で整いつつあり、将来のバージョンでは提供できる兆しが見えています。

Unity 側ではその時に備えて準備を整えておきたいので Wasm マルチスレッディング対応に積極的に取り組んでいます。これは、まずこの数か月のうちに試験的機能として内部的なネイティブスレッド(C# スレッドは未対応)限定で公開されます。「内部的な」というのは、スキニング、アニメーション、カリング、AI 経路探索やその他のサブシステム用のジョブスレッドのことを意味しています。これらは最初のうちはすべて有効にはならないかもしれませんが、長期的には、出来る限りマルチスレッディングの利点を活用することを目標としています。

デバッグ

デバッグは常に asm.js の課題でした。残念なことに、これは WebAssembly でもまだ改善されていません。各種ブラウザーはデベロッパーツールスイートで WebAssembly デバッグの提供を開始していますが、それらのデバッガーはまだ Unity3D のコンテンツのサイズにうまく適合しません。幸い、Wasm は「オープンでデバッグ可能な」形に設計されているため、将来的には各種ブラウザーから、これを可能にするより良いツールが提供されることが期待できます。差し当たっては、他のデバッギング技術をご使用ください(以下参照)。

  • 往々にして、Unity WebGL ビルドの問題は、ビルドされたゲームがブラウザー API とインタラクトするレイヤー内に発生します。このインタラクションサーフェスは UnityLoader.js と < ビルド名>.asm/wasm.framework.unityweb の中にあります。ここには、容易に読み出し可能でブラウザー内蔵のデベロッパーツールで直ちにデバッグできる JavaScript コードが含まれています。
  • C# コードのデバッグ用には Debug.Log() が唯一の選択肢であることが多いので、可能な場合は他のプラットフォームでデバッグを行うことを強くお勧めします。
  • 高度なデバッグの場合は、生成された asm.js コンテンツを console.log() でアノテートできるようにするために、asm.js へのエクスポートをお試しください。

また、バージョン 2018.2 では IL2CPP によるマネージドコードデバッグへの対応が追加されました。WebAssembly マルチスレッディングの対応が実装され次第、このテストを開始する予定です。

今後の予定

ブラウザーのベンダーは WebAssembly への対応をより強化していく計画です。各ベンダーは MVP(実用最小限の製品・Minimum Viable Product) の公開以来、起動時間とパフォーマンスを向上させる新機能の開発と最適化に取り組んできました。以下はそのいくつかの例です。

  • Wasm の非同期インスタンス化(Unity で対応済み)
  • 基準と階層コンパイル ― インスタンス化を高速化します(Unity コンテンツの実行時に自動的に対応)
  • ストリーミングによるインスタンス化 ― Wasm コードをダウンロード中にコンパイルします。(Unity での対応を検討中)
  • マルチスレッディング(Unity で対応のための作業中)

(注)ブラウザーによっては上記の機能の一部はすでに実装済みです。将来実装予定の各機能とその現状はこちらのページ(英語)でご確認いただけます。

私達は WebAssembly を非常に信頼していますので、デベロッパーの皆様には WebAssembly をデフォルトとして使用されることをお勧めします。必要であれば古いブラウザー用に asm.js をラインタイムのフォールバックとして保持することも可能です。これを行うには WebGL のプレイヤー設定で WebGLLinkerTarget.Both を選択してください。

asm.js はバージョン 2018.3 をもって廃止する予定となっています。したがって今後 asm.js には、Wasm 向けの改良(マルチスレッディング、SIMD など)は一切追加されません。ただし、バージョン 2018 の 長期サポート(LTS)ストリーム では引き続き利用可能です。これは今年末のリリース日から 2 年間正式対応となります。

特定のブラウザーが WebAssembly に対応しているかどうかを確認したい場合はこちらをご覧ください。

次回のブログ記事では、様々な側面から各種ブラウザーを比較していきます。本記事に関する皆様からのフィードバックもお待ちしております。

31 コメント

コメントの配信登録

コメント受付を終了しました。

  1. Nice post. I learn more to the post. I like it. Thanks for this post……………
    https://www.scora.in/

  2. A great step further for games in the browser! Bravo Unity!
    I have been impressed by another game engine like Playcanvas, as there are zero build time and very lightweight projects, making it possible to run even on old mobile phones. Problem with it is that it is nowhere close to Unity in terms of functionalities :(.
    What would it take for Unity to get there ? Will that happen in a close future ? Would Unity have to get a “mobile first” version ? (Sorry for the uneducated questions).
    A big Unity/Web fan

    1. WebGL Mobile support on IOS

      9月 14, 2018 3:35 pm

      Exactly great steps from Unity, I had also looked at Playcanvas as they make it possible to build games for WebGL on mobile (both on IOS & Android) with great loading times. But love Unity too much <3 :) are you guys working on supporting WebGL on mobile devices? (mainly IOS because with some workarounds Android seem to work most of the times) Maybe only for a Lightweight 2D game? with Lightweight Render Pipeline? Love to hear from you guys!

  3. You state that unity’s implementation uses c#. Does that mean Blazor or your own custom implementation?

    1. Marco Trivellato

      8月 21, 2018 9:59 pm

      The toolchain is based on IL2CPP (https://docs.unity3d.com/Manual/IL2CPP.html), which is a tool we developed to convert Intermediate Language to native code. Then, to convert from native code to WebAssembly we use Emscripten+Binaryen. This is all done at Unity project build-time.
      If you are interested in more information about IL2CPP, check this blog post: https://blogs.unity3d.com/2015/05/06/an-introduction-to-ilcpp-internals/

  4. Are you looking at other build pipelines e.g. mono to wasm?

    1. Marco Trivellato

      8月 21, 2018 10:01 pm

      Not at this time.

  5. Keng-Yuan Chang

    8月 18, 2018 7:54 am

    Web gaming is back, maybe even rich web applications are back

  6. PNACL was so much faster than both of these, used way less ram supported multi-threading ran very fast on old single-threaded Linux computers… let alone Windows and Mac. Wish PNACL was designed to be cross-browser.

  7. Will ECS and the Jobs system be able to take advantage of Multi-threading?

    Are there any improvements planned for the build system e.g. improved build times, reduced cpu load?

    Have you considered working with browser/wasm developers to enable burst compiling for WebAssembly?

    1. Marco Trivellato

      8月 17, 2018 5:51 pm

      We certainly hope to take advantage of multi-threading with ECS and the Job System.
      As far as improving build times, we may be able to take advantage of dynamic linking in the future so that if you only change a script, iteration times will be much faster.

  8. Bringing multi-threading support and dynamically sized heap alone are great improvements!

  9. Peter Steinberger

    8月 16, 2018 8:26 am

    We‘ve seen quite mixed results, and asm.js still overall being faster for certain browsers in the WebAssembly benchmark we built: http://iswebassemblyfastyet.com

    Interested to compare notes.

    1. Marco Trivellato

      8月 17, 2018 5:46 pm

      That’s interesting. If you don’t mind, let’s discuss it in the Unity WebGL forum: https://forum.unity.com/forums/webgl.84/

  10. Santiago Machad

    8月 16, 2018 3:30 am

    Great step! each time more nearly to produce game for FB-InstantGame, (?) =D Tell me yes please!

    1. Marco Trivellato

      8月 16, 2018 10:29 am

      For Messaging Apps games you may want to wait for Unity for Small Things (https://unity.com/solutions/unity-for-small-things) which has been designed for that use-case.

  11. I assume Wasm implementation in 5.6.x is completely different (and obsolete) vs 2017 vs 2018? Or was it relatively stable and mostly dependant on browser vendors?

    We are stuck on 5.6.6 at the moment but would love to use Wasm. Recommendations on it’s evolution since it’s initial introduction?

    1. Marco Trivellato

      8月 16, 2018 10:10 am

      Hi Kamil, It’s not completely different and the number WebAssembly-specific bugs we received since we released 5.6 is relatively low. However, we did upgrade Emscripten and Binaryen in 2018.2 which come with a lot of bug fixes. In addition, in 5.6 we did not have Wasm caching and async instantiation support. Anyway, I would recommend you to try it on your project to see if you run into any issue.

      1. That’s good to hear. Thank you for taking the time to answer.

  12. Nice to see that WebAssembly is now in use. I was curious about getting around with 2 GB browser memory limit. Is there a function to get how much memory is in use during the gameplay? If that would be possible to determine, the game could stop downloading or generating content when current memory usage is getting close to 2 GB. Download or generation could be resumed once old content is unloaded and more memory is available. This could prevent “out of memory” crashes in any circumstances. Once again, is there a function to get current memory use while in WebGL runtime?

    1. Marco Trivellato

      8月 17, 2018 5:38 pm

      In https://blogs.unity3d.com/2016/12/05/unity-webgl-memory-the-unity-heap/ there is a plugin that shows you how to get information about memory usage. With 2018.2, GetTotalMemorySize() will now return the current size of the Heap, so if the Heap grows, it will return the new size. GetDynamicMemorySize() will give you the amount of memory used within the Heap. I believe this is what you need.
      In the future, I think we will make these functions built into the Unity WebGL target by default.

  13. So we’ll have FMOD support once browsers will support Multi-Threading?

    1. Marco Trivellato

      8月 15, 2018 10:02 pm

      That is a very good question. It’s should be possible to compile FMOD with Emscripten (like we do for for PhysX) but this is something we haven’t looked at yet.

  14. Hi,

    Just a small question : does it change anything about networking for webgl ? I mean feature or design wise not talking about performances.

    Thanks!

    1. Marco Trivellato

      8月 15, 2018 7:19 pm

      Hi David,
      at the moment nothing changes in terms of feature set.

  15. Now the WebGL exporter (or should I say Wasm exporter maybe?) is getting serious in Unity. Looking forward to see this tech evolving.

  16. So what about using Unity WebGL on mobile phones? currently it is not supported yet, it gives a warning that it is not officially supported.
    Will there be a time where this will be supported?
    It is always still more performant to make an iOS / Android build but for maybe a lightweight project it would be nice if it were supported.

    1. Marllon Vilano

      8月 15, 2018 5:33 pm

      In the “browsers supported” page, I see that “Chrome for Android version 67” is supported by WebAssembly. I’m curious to know if is it possible to run the Unity WebGL build in that version :)

    2. Marco Trivellato

      8月 15, 2018 8:02 pm

      Hi Kevin, success-rate on mobile browsers depends a lot on which browser/os/device as well as on the type of content. This is the main reason for not supporting mobile browsers yet. Having said that, there is nothing preventing you from running on mobile, apart from the warning which can be disabled.

  17. Francois Laberge

    8月 15, 2018 2:46 pm

    Is there a way to use this to generate WebXR experiences?

    1. Kevin Reynolds

      8月 15, 2018 11:38 pm

      Mozilla has released an asset store package for using Unity WebGL builds for WebVR