AR.js — The Simplest Way to get Cross-Browser Augmented Reality on the Web
How to deliver Augmented Reality contents on the web, in an open-source, easy and cross-browser way.
Also available in Italian.
This is the first part of a series of articles about AR.js. The following is the list of the articles written so far:
Just another AR library?
Amongst its most interesting characteristics:
- Performance, ~60 FPS on my two-year-old phone (!)
- Compatibility, it is cross-browser, it works on every phone browser (and obviously desktop) supporting webgl and webrtc (so basically every Android phone and iPhones above iOS 11)
- Simplicity, it is a wrapper of different frameworks that makes web AR developing very easy. It is built on top of a-frame and three.js.
So we don’t need Hololens, Cardboard or expensive phones; we just have to reach an AR.js webapp and then we can experience AR.
How is that possible? Well, it turns out AR.js works with markers (not always, but if we wanna be cross-browser, we have to use markers).
Markers are a sort of simplified qr-codes. On AR.js we define specific 3D scenes for specific markers, so when the camera recognizes a marker, the web-app shows the 3D model on top of it. Also, markers may contain qr-codes.
An important feature of AR.js is the possibility to use custom markers, the default type is ‘pattern’. I did some research on pattern markers’ limitations, on their size and shape. I learned that:
- The maximum resolution of a marker is 16x16 pixels
- They must be square in shape
- They cannot have white/transparent areas, only light grey (e.g. #F0F0F0)
- They cannot contain colors, only black and light grey
- They have to contain simple text, like one letter, a number, or a symbol.
You may use this online tool to generate your custom markers. If you analyze the “.patt” output file, you will find out that the given image is described with a set of characters. So, for good results, it’s better to use dissimilar images for different markers, avoid too complex images or images containing words.
Another important aspect to remember is to have an high contrast between the ‘background’ of the marker and the surrounding environment; for example, if the marker has light grey symbols on black background, the camera will have difficulties on recognize the marker if it is printed and placed on a black desk or displayed on a black screen.
Markers can also be barcodes. They represent a number as a symbol, created with calculus on a matrix. It is suggested to generate markers based on a matrix with an high “hamming distance” (see this table), so the camera can recognize them better. A matrix defines also the maximum number of possible markers (for example the “AR_MATRIX_CODE_3x3_PARITY65” matrix can generate 32 different barcode markers).
Keep in mind that it is better to avoid, if possible, white/transparent color in barcode markers too (this is not confirmed on barcode markers but it is based on empirics).
This is the online generator of barcode markers I used for the following example.
I am showing you some basic code from AR.js documentation and blog, and also a few workarounds, since currently there are some open issues regarding custom markers.
In this simple HTML, we:
- Import libraries
- Tell AR.js to recognize barcode patterns that are generated with a 3x3 matrix (line 12)
- Define two <a-marker> tags, each one identified by two different barcode values (18 and 22)
- Define a static camera entity (line 30).
To avoid problems, please use specific tags and attributes as shown above. At the time of this writing (April 2018) this example works and it’s based on the newest release of AR.js (version 1.5.5). It is also required to use remote urls for pattern resources, instead of relative urls.
If you want to use custom markers instead of barcode markers, you can generate them with the previously linked tool, and instead of using
<a-marker type="barcode" value="6" (...)
you can use
<a-marker type="pattern" preset="custom" url="...." (...)
where “url” is the remote absolute URL of your “.patt “ file, located remotely somehwere (for instance, in the same repository of the HTML file).
Patterns in detail
To simplify the detection of markers by the camera, it’s useful to keep in mind some simple rules for create barcode/pattern markers.
For example, the patterns generated for ‘blue’ image and ‘red’ image are very similar (you can check them on the following images); this will make detection very hard.
If the image is very complex, the detection may fail too, because the output will look like a set of random characters. From my little experience in playing with markers, I found out that barcode markers are recognizable as much as pattern markers. With the latter it is possible to have more customization, but it is also easier to create a set of similar markers that can confuse the camera, or fall into using complex images as markers.
So, is AR.js worth it?
I answer “absolutely”. Its simplicity is stunning. An approach based on markers is not a real limitation, but rather a paradigm that suits well for an incredible range of use cases. Markers can be showed on mobile and desktop displays or printed and hanged up on walls or boards.
As AR.js shows us, it’s not necessary to have another device over a mobile phone to experience AR, nor to download a third party app (that a common user will surely uninstall soon after, or that probably they won’t download at all). Delivering augmented reality on the web, and make it easily suitable for everyone (literally!) is the key to make this technology pervasive.
Edit (March 2019): I updated AR.js version and a-frame versions. Actually, no big thing has changed.