Asm.js + WebGL for Unity and Unreal Engine
Unity and Epic’s Unreal Engine, the popular middleware tools frequently used by game developers, are not limited to creating compiled applications that run as an executable. With the advent of WebGL and asm.js, developers can now harness much of the power of their computing device from within the browser and access markets previously unavailable. In this tutorial, I’ll show you a slice of “how”.
Unity previously had a web player, which was a downloadable plugin that used ActiveX. Chrome killed support for NPAP (Netscape Plugin API), but announced it over one year ago. In April, with the release of Chrome 42 stable, they finally put the axe to it. There are a number of reasons as to why, but most notably they stated “hangs, crashes, security incidents, and code complexity. Google suggests using web standards instead, such as WebGL, which I will explain below.
Microsoft is following suit and deprecating ActiveX, VBScript, attachEvent, and other legacy technologies in favor of web standards. The need for ActiveX controls has been significantly reduced by HTML5-era capabilities, which also produces interoperable code across browsers.
How is this code turned into WebGL?
Unity recently did some performance benchmarks of their software running on WebGL as well.
Having code cross-compiled (often called transpiling as well) is not without its pitfalls, however. Common performance-enhancing techniques found in statically typed languages, such as multi-threading (JS is single threaded) and SIMD (Single Instruction Multiple Data) are not available yet.
Mozilla, along with several other leading tech companies, have been working on SIMD.js though, so increased performance and reduced power usage could be something of the near future. Read more about it here. Instead of those performance tweaks above, Unity is relying on their new scripting runtime, IL2CPP (In Line 2 C++). That’s a story for a different post, but Unity has been doing a fantastic web series every few weeks to illustrate how IL2CPP works.
IL2CPP has two distinct parts:
- An ahead-of-time (AOT) compiler
- A runtime library to support the virtual machine (VM)
The Intermediate Language (IL) from .NET compilers is compiled to C++ source code via the AOT compiler. Services and abstractions such as platform-independent access to threads and files as well as a garbage collector are some of the benefits the runtime library provides.
Look at it this way:
Image courtesy of Unity
When you run an .exe on a Windows machine, it is not actually byte code (0s and 1s) at that point. It is still in a binary that the VM reads at runtime, which is then turned into bytecode. The DotNet CLI on a Windows machine is an example of a Virtual Machine which may read this binary. The CPU cannot comprehend anything other than binary, therefore this additional step is needed to take place.
Still confused? This post explains more about the difference between machine code, byte code, and VMs.
How does asm.js fit into the picture?
On the backend, Clang uses LLVM, which is a library for constructing, optimizing and producing intermediate and/or binary machine code (those 0s and 1s again). LLVM can be used as a compiler framework, where you provide the “front end” (parser and lexer such as Clang) and the “back end” (code that converts LLVM representation to actual machine code)
Further reading: Alon Zakai of Mozilla has a fantastic slide deck which goes into further detail about how this all works.
So how cool is asm.js? Well it has its own Twitter account, @asmjs. While the asm site is a bit sparse, it does cover the W3C spec, in addition to having a thorough FAQ. Even better, Mozilla coordinated the Humble Mozilla Bundle in 2014, which allowed you to buy a bunch of gamest that took advantage of asm.js.
To better understand this, it is important to comprehend why asm.js offers a performance benefit at all; or why statically-typed languages perform better than dynamically-typed ones. One reason is “run-time type checking takes time,” and a more thought out answer would include the enhanced feasibility of optimizing statically-typed code. A final perk of going from a statically typed language such as C is the fact that the compiler knows the type of each object when it is being compiled.
What is WebGL Doing?
- Performance: Utilizing hardware acceleration (the GPU built into your device), WebGL is a great fit for games or complex visualizations.
- Shaders: Complex visual effects can be produced with small programs known as “shaders”. This may be as simple as producing a sepia coloring effect, or more complex simulations such as water or flames. Visit Shadertoy for a showcase of some examples which really highlight this.
When you build a WebGL project, Unity will create a folder with the following files:
- an index.html file that embeds your content in a web page.
- a .mem file containing a binary image to initialize the heap memory for your player.
- a .data file containing the asset data and scenes.
You can also customize the style of the page to better suite your game, although taking advantage of the Fullscreen API is recommended to get a more immersive experience.
Interested in learning WebGL? Look into WebGL Academy for a complete course.
What’s missing from WebGL?
WebGL is a subset of the OpenGL ES spec. This is the graphics API you frequently see on mobile devices, such as Android and iOS devices. That ES (Embedded Systems) spec is actually a subset of OpenGL, the graphics API available to desktop machines and consoles, such as PlayStation and Wii. Because WebGL is not a direct 1-to-1 match with OpenGL, some features will be missing.
Here’s a short list of missing features not currently available to WebGL versions of Unity games. Expect this to change over time.
- Runtime generation of Substance textures
- Networking other than WWW class (a WebSockets plug-in is available)
- Support for WebCam and Microphone access
- Hardware cursor support
- Most of the non-basic audio features
- Script debugging
- Any .NET features requiring dynamic code generation
What about browser support?
This is where things get crazy. You can try out two of their WebGL demos right here. You need to use a browser which supports asm.js. As of this writing (July 2015), asm.js support is as follows:
It’s important to note that the asm.js spec is not implemented 100% in all of the browsers though, so results will vary. Unfortunately, asm.js is not listed on the popular feature-checking site CanIUse.com, so it’s difficult to get a clear understanding of how well it is supported in each browser. This will not work on mobile browsers as they currently do not support asm.js, although several support WebGL. I wrote a piece about the current state of WebGL on mobile devices in November of 2014.
What about performance?
- In almost all benchmarks, Firefox with asm.js is faster than both Chrome and Safari, and is currently the best browser to run Unity WebGL content.
- When you are mostly GPU-bound, you can expect WebGL to perform very similar to native code.
- In some areas, WebGL will actually outperform native code significantly. This is the case for tests which rely a lot on script performance (Mandelbrot and CryptoHash, which both implement their algorithms in C#), as IL2Cpp can produce more optimized code (More info in this post).
So, what does this mean for you, as the developer? Naturally there are some areas where WebGL is significantly slower than native code, such as areas which make use of multi-threading, but WebGL performance is decent and only improving by the day.
Why would anyone want to do this?
This is a pretty common question. The one I hear most though is “who would want to download a 60mb website? And you’re right — 60mb for a website is massive! But I suppose the same people who are downloading gigabytes worth of video content from YouTube and Netflix each day are those same people. If you look at it as a website, then sure, it’s huge. If you look at it as a game though, 60mb is small! The case study below illustrates that well.
Furthermore, as a developer you can now circumvent the restrictions of the app store. Want to update your application? No problem, push a new build to your website. Don’t want to wait out the one-week approval process of the iOS App Store (that is, IF it gets approved)? Perfect, push to your own site.
You could, of course, always sell it behind a paywall, too; or require some sort of authorization to play the title. Additionally, you do not need to pay the annual licensing fees for the app stores, nor do you need to prepare images for their stores, icons for their desktops, etc. Now things are starting to look appealing, and we’ve only just touched the surface.
Take a look at what the team at Illyriad games has done with their space combat title, Age of Ascent. They initially stream only a small bit of data, just enough to get you going, before sending the additional bits to you. I believe during our last conversation it started at 50mb. You can hear more about it during the podcast I did with them. Users can hop in and play immediately. No massive client to download, and instantly lowers the barrier to entry. Teenage-me would have loved this during my Everquest years.
In contrast, traditional titles send everything to you at once before you can start playing. Granted, consoles have just started to use “chunking”, which breaks up a title into smaller pieces and starts the download with the parts you need to play almost immediately.
Jonas Echterhoff pointed out that in Unity, streaming assets is already possibly by using AssetBundles. Alternatively, you can try this Asset Store package, which repackages the WebGL build data, so that scenes in your build are split across multiple files, and your content can start once the first scene is loaded:
In keeping with the space sim theme, I looked at Star Citizen, which is looking to come in at around 100gb. Do you honestly believe that you will ever experience all 100gb of that content?
An Offline Experience
Just because you are pointing to an HTML5 site doesn’t mean you can’t have an offline experience. Don’t believe me? Take a look at this video from Syd Lawrence one of the creators of Snowbuddy. Syd runs We Make Awesome Sh and during his talk he showcases some incredible apps made with PhoneGap and his top 7 tips for making high performance PhoneGap apps at PhoneGap Day EU 2015, but specifically highlights how to create an offline experience.
It would be wise to have a mix of local and remote content for your app. Technologies like IndexedDB, localStorage and AppCache, which are supported by Microsoft Edge, allow for this. A local page can be kept in your app package that can still provide a basic offline experience.
Case Study: Owlchemy Labs’ Aaaaa! converted to asm.js from Unity
Aaaaa! Has over 200 levels with more than 300 assets that can be spawned at runtime, in addition to 38 full-length songs. On PC/mac they were looking at a 388mb uncompressed file, so as you can imagine, having to download all of this each time someone wanted to play the game would be a bit of trouble.
One of their biggest size savers was Unity’s AudioClip streaming solution, which could stream music at runtime on demand. When completed, their final compressed WebGL build size, which includes all loaded assets as well as the Unity engine itself, ended up wat 68.8 MB. The compressed standalone PC build was almost 3x that size, at 192 MB.
There were certainly some UX changes that needed to be made, including rebinding the escape key, which in many games would display a pause menu, but inside the browser would exit full screen mode release mouse lock. Additionally, because browser’s security model forces these games to be sandboxed, saving large chunks of data to disk or loading custom audio from a user’s hard drive could prove problematic.
Finally, it would be important to consider some sort of cloud sync feature, as gamers often will not play web based games on only one machine. It would be far more convenient for a consumer to load into their profile from any machine and have their settings / saves just appear.
Are any other middleware tools taking advantage of this?
Epic’s Unreal Engine 4 exports to WebGL and takes advantage of asm.js as well. You can find step-by-step instructions here.Their process is nearly identical to that of Unity’s minus that first C# step, as the code you write in Unreal Engine is already in C++.
Epic’s current showcase piece is Tappy Chicken, a Tappy Bird type game which is also available on iOS and Android. They first illustrated UE 4 working within Firefox at GDC 2014:
At GDC the year before that, Mozilla and Epic surprised everyone at one of their talks when they revealed that UDK (Unreal Engine 3) was working within the browser after only one week of work with their Epic Citadel demo.
Monster Madness from NomNom Games, was the first commercial Unreal Engine 3 game published on the Web, using asm.js.
What does the future hold?
WebGL isn’t limited to games. Application could easily take advantage of this technology as well.
Get a glimpse of the Unreal Paris 1.2 demo, where users can walk through a meticulously designed apartment. (Download link)
Imagine working as an architect or designer and trying to pitch this to a client. You can run it on the fly, inside of the browser. Even better, the user does not need to download the entire application.
Look at something like Age of Ascent. Download 54 Mb and you can start playing the app because it only streams what you need right then can cache it locally using a technology such as IndexedDB , so you do not need to download it again. Users can be up and running in seconds. I interviewed the team at Ilyriad games in December to get a better understanding of how they put their technology together.
On the other end of the Spectrum, we have Star Citizen, which starts at 70Gb.That’s a huge barrier to entry to many folks, especially in places where they may not have quick broadband.
Are there other alternatives?
But of course! PlayCanvas is a fantastic WebGL based framework which uses asm.js for physics. Even better, it has excellent documentation and tutorials, on top of a browser-based editor.
For tools such as this, you’d need to use a wrapper of some sort (such as Cordova or PhoneGap) to port this to an app store such as Google Play, the App Store, or Windows Marketplace. ManifoldJS.
ManifoldJS aims to make the life of a mobile developer easier than ever, by utilizing Web App Manifests, which allowing websites to declare app-like properties. ManifoldJS uses that standard for those platforms that support it, but falls back to Cordova for those who don’t.
Cordova is great, but the W3C also considers work done at Mozilla (Firefox Open Web Apps), Google (Chrome Hosted Apps) and Microsoft has done (Windows 8 had local web apps, Windows 10 extends over to hosted web apps). With this, we can now wrap websites and creating hybrid applications which can be deployed in the various app stores, while still taking advantage of many native aspects for each device (contacts, calendar, file storage, gyro, GPS, etc.)
Jeff Burtoft explains hosted web apps very well at http://www.thishereweb.com/hosted-web-apps-explained/
When we combine the two, we can create applications at native speed which can be deployed in a number of app stores, and utilizing largely one code base. There is no silver bullet for mobile development, but this certain makes the process easier.
Unity outlines the process of exporting your title to their WebGL player in their docs. Browser support for both WebGL and asm.js is constantly improving, and Firefox was even showcasing features of WebGL 2.0 at the Game Developers Conference in San Francisco earlier this year. WebGL 2.0 comes with a number of improvements, including the ability to render up to 32 textures at one time, as opposed to the current standard of 8, in addition to developer access to antialiasing and multiple render targets.
The advantages of porting a Unity game to WebGL are numerous:
- Distribution through sources other than curated app stores
- Often a smaller package size
- Easily demo or share projects
Developers have already proven that the model works, as illustrated by the Aaaaa! Case study and Mozilla Humble Bundle, so it’s an opportune time to take advantage of what the browser can finally offer and have additional exposure for your work.
We encourage you to test across browsers and devices including Microsoft Edge – the default browser for Windows 10 – with free tools on dev.modern.IE:
- Scan your site for out-of-date libraries, layout issues, and accessibility
- Use virtual machines for Mac, Linux, and Windows
- Remotely test for Microsoft Edge on your own device
- Coding Lab on GitHub: Cross-browser testing and best practices
In-depth tech learning on Microsoft Edge and the Web Platform from our engineers and evangelists:
- Woah, I can test Edge & IE on a Mac & Linux! (from Rey Bango)
- The Edge Rendering Engine that makes the Web just work (from Jacob Rossi)
- Unleash 3D rendering with WebGL (from David Catuhe including the vorlon.JS and babylonJS projects)
- Hosted web apps and web platform innovations (from Kevin Hill and Kiril Seksenov including the manifold.JS project)
More free cross-platform tools & resources for the Web Platform: