Moving “VirtualWorld3d” from pure JavaScript to WebAssembly

Build your world. Invite your friends.

Moving “VirtualWorld3d” from pure JavaScript to WebAssembly

Introduction

The aim of “VirtualWorld3d” is simple – to make it easy for users in interact in a 3d environment on the web.  We want to make it easy for people to create their own 3d worlds using a simple block based interface (think “Lego” / “Minecraft”).  We want the worlds to be accessible from anywhere with just a web-browser.  Sharing worlds will be as simple as sharing a web address.

“VirtualWorld3d” is very much a hobby project but with big-ambitions, this is not our main job (maybe one-day) and we invest our own time and money to make it happen.

Early experiments were implemented in JavaScript using Three.js, the experiments were fruitful but a little disappointing in some areas:

  • Page Load times – The page load times were a limiting factor, on slower desktops and mobiles we were finding page load times in excess of 10 seconds. This was not good enough, we want the worlds to open as quickly as any other web page.
  • Web-page performance – There was an on-going problem that we couldn’t quite get the frame rates that we wanted, the effect was noticeable when simply navigating around the world but was especially noticeable when editing the world (which involves a significant number of calculations for every change). In order to improve this we had a complex “WebWorker” architecture in the JavaScript version.

Whilst looking for solutions to these problems we became aware of the incredible cross-browser developments in the area of WebAssembly. It rapidly became apparent that if this technology lived up to the “hype” then it could be the answer to all of our problems.

The “WebAssembly” version of “VirtualWorld3d” was born.

An early preview of the WebAssembly version of ‘VirtualWorld3d” can be found at VirtualWorld3d

The New Architecture

The decision (difficult) was made to create a new library from the ground-up with few external dependencies. The library would consist of a thin JavaScript layer which would simply make the WebGL calls to drive the Virtual World’s display and to implement the rest in C++ which we would compile to WebAssembly using “Emscripten”.  Luckily we already had significant WebGl and C++ experience, time however is limited.

The architecture was designed to minimize the number of times that C++ calls JavaScript functions and vice-versa; this was considered a slow interface (which seemed to be the case when we started but has improved since, needs further measurement).

The migration was a significant undertaking the trickiest areas of consideration were the move from JavaScript types to their STL / C++ equivalents and the move from a Garbage Collected architecture to a heap / reference counted model.

Improvements in Page Load Time

The new architecture gave us a double “win” in the area of page load times:

  • The move away from external libraries (e.g. Three.js) meant that we could focus on only the functionality that we needed and so the size of the libraries got much smaller. Which meant quicker download and compilation times – WIN 1.
  • The move to mostly WebAssembly libraries rather than Javascript means that the compilation time per megabyte of library is quicker because WASM is in theory easier for browsers to deal with – WIN 2. This benefit is continually improving as browsers are currently going through a phase of improving their behaviour with handling WebAssembly.

This means that in our latest version we can get a world up and running in a couple of seconds, even on slow devices.

Web-page performance

A significant amount of profiling was performed on our application and it was found that three aspects in particular were contributing to our performance issues:

  1. Game Physics – Even from the outset on our project we-wrote our own Physics engine in JavaScript, this was considered one of the “fun” aspects of the project that made us want to do it. The difficulty with game physics is that they need to be executed every frame and they involve a significant number of mathematical calculations, particularly to do the collision detection. The move to WebAssembly gave us a roughly 8x improvement in performance, partly due to the fact that we had more control of the types we are using. The behaviour also became more deterministic due to the move away from “Garbage Collection”.
  2. Lighting (Ambient Occlusion) – “VirtualWorld3d” uses an ambient occlusion style lighting algorithm, that is why things get darker when you are indoors or when there are a lot of objects around. This also needs a significant number of calculations, especially when changing the map (we seemed to get around a 6 times improvement in performance when we move to WebAssembly).
  3. Triangle Culling – The block style nature of “VirtualWorld3d” means that the whole thing revolves around triangle culling, if you place two bocks together then you can get rid of the triangles for the sides facing each other which cannot possibly visible. Without this algorithm, the number of triangle would be far too high to be workable by the graphics hardware.  This again involves a significant number of calculations, particularly when editing the map.  Again we saw a roughly 6 times improvement in this when we moved to WebAssembly.

Using these improvements we have been able to relatively easily achieve 30 frames per second event on modest hardware and without needing a complex “WebWorker” setup. We are really looking forward to the Threads API for WebAssembly becoming available cross-browser.

Conclusion

The move to WebAssembly from pure JavaScript was a significant undertaking but it has brought great benefits.  It is still early days but things are looking good for “VirtualWorld3d”. There is a working preview at:

VirtualWorld3d

 

Leave a Reply

Your email address will not be published. Required fields are marked *