Augmented reality is a neat concept. We take a view of the world around us and supplement it with images, text, sound and video. Tech companies are starting to explore the possibilities of AR with devices such as the Meta Glasses, Microsoft HoloLens and Magic Leap. These very exciting AR headsets are not quite ready for consumer release yet, so it may be a little while before every household has a pair. However, there is another way of introducing the world to augmented reality using something they may have easier access to - the mobile browser.
I have previously covered other sorts of reality creation and manipulation using JavaScript and Three.js here at SitePoint in my articles on Bringing VR to the Web with Google Cardboard and Three.js and Filtering Reality with JavaScript and Google Cardboard. In this article, I'll show how you can use a JavaScript library called awe.js to create an augmented reality experience on the mobile web. We're going to create a 3D control board that opens on top of a paper marker. We can hook it up to do pretty much anything that can be enabled via a JavaScript HTTP request, so I've set it up to change the color of my LIFX lightbulb using IFTTT.
What You'll Need
For this demo, you'll currently need Google Chrome for Mobile. It may potentially work on Firefox for Mobile too, however I found click events didn't trigger for me when I tried it on my HTC One M9. It also works on some desktop browsers (Chrome and Opera worked quite nicely on my Mac) but definitely isn't quite the same experience as a smartphone with touch events. It could be neat on a tablet though.
You'll also need an IFTTT account and a knowledge of how to set up the the Maker Channel with rules that trigger on HTTP requests. If you're new to IFTTT, we previously went over the basics in the article on Connecting LIFX Light Bulbs to the IoT Using IFTTT. For those new to the Maker channel, we've also covered that in Connecting the IoT and Node.js to IFTTT.
Lastly, you'll need to print out a marker onto a piece of paper. The marker we'll be using is this one:
The code
If you'd prefer to get straight into the code and try it out, it is all available on GitHub.
Awe.js
Awe.js is a JavaScript library that uses Three.js, your device's camera and some pretty smart techniques to create augmented reality in the browser. You can download the library and some samples on the awe.js GitHub repo. It provides four different sorts of AR experiences, each with their own example in the repo:
geo_ar- Allows you to place objects at set compass points.grift_ar- Compatible with an Oculus Rift.leap_ar- Integrates with the Leap Motion controller.marker_ar- Allows you to create an experience that is positioned on Augmented Reality markers. This is the one we'll be working with in this demo.
Our Augmented Reality Demo Code
Our demo code is over 300 lines long, but a lot of it is repeated code for similar objects. I'd recommend downloading the demo code from the demo's GitHub repo and following along with the explanations provided here. Once you've got an idea of how it all works, try tinkering away and building something of your own.
Everything starts within the load event on our window. The very first thing we include is a variable to track whether our AR control panel (I've called it a "menu" for short here) is open or not. Initially, it is closed.
[code language="js"]
window.addEventListener('load', function() {
var menu_open = false;
// Our code continues here
});
[/code]
Then, we start to use the awe.js library. Everything we do is defined within the window.awe.init() function. We start with some global settings for our AR scene.
[code language="js"]
window.awe.init({
device_type: awe.AUTO_DETECT_DEVICE_TYPE,
settings: {
container_id: 'container',
fps: 30,
default_camera_position: { x:0, y:0, z:0 },
default_lights: [{
id: 'point_light',
type: 'point',
color: 0xFFFFFF
}]
},
[/code]
device_type- All of the examples set this toawe.AUTO_DETECT_DEVICE_TYPEwhich requests it to detect the device automatically. So far I haven't seen a need to change this.settings- Settings we may actually want to change live within here. These include:container_id- The ID of the element our whole experience is going to be generated inside.fps- Our desired frames per second (optional).default_camera_position- The default camera position that we will be viewing our scene from (we're starting it at (0,0,0)).default_lights- We can set up an array of different Three.js lights for our scene, giving each an ID, defining the type of light it is and its color. Our demo has only one white Three.js PointLight. There are a range of options available for the type of light, which correspond to different types of Three.js lights -'area','directional','hemisphere','point'and'spot'.
Once our settings are in place, we then define what to do when awe.js has initialised. Everything is wrapped within a awe.util.require() function which defines what browser capabilities it requires before loading additional JavaScript files we'll need. Be careful to only define the browser capabilities you do need for the demo, as you can unnecessarily prevent your AR app from working in some browsers if you define these incorrectly using capabilities listed in some of their other GitHub examples. For example, in order to have elements positioned based upon compass points you need access to the 'gyro' capability. That won't work on most desktop browsers. We don't need that in this demo, so we exclude it.
[code language="js"]
ready: function() {
awe.util.require([
{
capabilities: ['gum','webgl'],
[/code]
The files that are defined pull in specific functionality for awe.js - lib/awe-standard-dependencies.js, lib/awe-standard.js and lib/awe-standard-window_resized.js each are pretty common, defining the standard bits and pieces for awe.js and handling window resizing. Our demo uses markers, which requires the other two files listed below those.
[code language="js"]
files: [
['lib/awe-standard-dependencies.js', 'lib/awe-standard.js'],
'lib/awe-standard-window_resized.js',
'lib/awe-standard-object_clicked.js',
'lib/awe-jsartoolkit-dependencies.js',
'lib/awe.marker_ar.js'
],
[/code]
Once we've got all of those files successfully loaded, we run the aptly named success() awe.js function. The first function you'll always run when you're ready to start displaying elements sets up the awe.js scene.
[code language="js"]
success: function() {
window.awe.setup_scene();
[/code]
All elements in awe.js are positioned within "Points of Interest" (POI). These are specific points in the scene marked via coordinates that objects can be positioned inside of. You can move POIs around within awe.js as well as elements themselves. We create a single POI which will be placed wherever a specific paper marker is seen. To create a POI, we use the awe.js function of awe.pois.add().
I've given it an ID of 'marker' but you could call it anything you'd like, as long as you are consistent throughout other references to this POI in the code. We set its initial position to be (0,0,10000), which positions it off into the distance a bit until we're ready to use it. We also set it to be invisible until we spot the marker.
[code language="js"]
awe.pois.add({id: 'marker', position: {x: 0, y: 0, z: 10000}, visible: false});
[/code]
Elements we add into our POIs are called "projections" within awe.js. The first projection we add into our scene I've called 'wormhole', as this is a flat black square where our menu items will magically appear out of. Just as the ID of the POI, you could name yours absolutely anything, as long as you keep it consistent with other references to it in your code. We add it into our POI using the function awe.projections.add().
[code language="js"]
awe.projections.add({
id: 'wormhole',
geometry: {shape: 'plane', height: 400, width: 400},
position: {x: 0, y: 0, z: 0},
rotation: {x: 90, z: 45},
material: {
type: 'phong',
color: 0x000000
}
}, {poi_id: 'marker'});
[/code]
There are quite a few options for the objects we can add as projections, so I'll explain them in more detail. Take note - all x, y and z values here for positioning and rotating are in relation to its POI. That POI is defined at the very end by its ID as {poi_id: 'marker'}.
geometry- This refers to the projection's Three.js geometry options. The options required for each type of geometry match those provided in awe.js. For example, SphereGeometry in Three.js would be represented as{shape: 'sphere', radius: 10}in awe.js. One thing to note for those using the latest Three.js, in the currently available version of awe.js, BoxGeometry is still using CubeGeometry. So, to create boxes, we use the format{shape: 'cube', x: 20, y: 30, z: 5}(despite the name, it does not need to be a "cube").position- You can adjust the item's x, y and z axis in relation to its POI.rotation- You can rotate the item by its x, y and z axis in relation to its POI. I rotate the wormhole 90 degrees on its x axis so that it sits flat on the table and 45 degrees by its z axis as I thought that looked more natural (it doesn't quite line up exactly with the marker at all times, so having it on a diagonal makes this less obvious).material- This defines the projection's Three.js material. I've stuck to using'phong'(MeshPhongMaterialin Three.js), however it looks like'lambert','shader','sprite'and'sprite_canvas'are also potentially available as options. We can also define its color in hex.texture- This is not used in the demo but I wanted to include it in this article for completeness. To define a texture, you can includetexture: {path: 'yourtexturefilename.png'}.
In the demo, I add seven different boxes/cubes to the scene, each one is 30 pixels high and placed 31 pixels lower on the y axis so that it is originally hidden by the wormhole. They're all slightly different widths to make them look a bit like a lightbulb.
Continue reading %Augmented Reality in the Browser with Awe.js%
by Patrick Catanzariti via SitePoint