News

Create a unique mobile 3D UI and navigation

In part one of this tutorial we show you how to build an augmented menu that hooks into the mobile’s device orientation controls to create a bespoke browsing experience with three.js

3DUI

In part one of this tutorial we show you how to build an augmented menu that hooks into the mobile’s device orientation controls to create a bespoke browsing experience with three.js

3DUI

Creating compelling web experiences for mobile devices has come a long way, there are a whole raft of phone functions that designers can plug in to and access without the need for packaging up the mobile site as an app.. In this tutorial what is being achieved with the native mobile web would have been pretty hard to conceive as an app going back just a few years, but now this is running purely as a mobile optimised website.

The site itself will be in 3D and rendered by three.js but instead of this being rendered with the WebGL renderer, the scene will be rendered using the CSS3 renderer, giving us maximum compatibility with devices. Having 3D as part of the design is going to be an important part of the interface. In order to browse around the interface the user will need to rotate their phone and the display will update, placing them in the centre of an augmented interface. Moving the phone around becomes like moving a camera in the interface to explore the links that are on offer to the user. This is made possible through the ‘Device Orientation Controls’ that come bundled with three.js and can turn our phone into something similar to an Oculus Rift.

This is part one of a two-part tutorial, creating the interface and get the device orientation working, we will focus on the interaction with the menu in issue 243.


GET THE CODE FOR THIS TUTORIAL

1. Link the libraries

Open the ‘start’ folder in a code editor such as Brackets. In the body of the document, add the following code to link up the libraries. This uses the three.js library available from threejs.org. Following this is an opening script tag with some global variables that are needed in the project.

<script src="js/three.min.js"></script>
<script src="js/DeviceOrientationControls.js"></script>
<script src="js/CSS3DRenderer.js"></script>
<script>
var camera, scene, renderer;
var circle1, circle2;

2. Set the scene

The code now adds the init function, used to initialise the scene. A camera is created, the control system is initiated to run on the device orientation controls. The scene is created now that the camera and control system can work with. The final code starts an array and this contains an object.

function init() {
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1000 );
controls = new THREE.DeviceOrientationControls( camera );
scene = new THREE.Scene();
var sides = [{
url: 'img/scene-right.jpg',
position: [ -512, 0, 0 ],
rotation: [ 0, Math.PI / 2, 0 ]
},{

3. Create the background

To create the background for the 3D scene a skybox will be created, which is a large cube placed on the outside of all other objects. The code here is holding a reference to each of the sides, their individual position and rotation within the 3D scene in order to view the box correctly.

url: 'img/scene-left.jpg',
position: [ 512, 0, 0 ],
rotation: [ 0, -Math.PI / 2, 0 ]
},{
url: 'img/scene-top.jpg',
position: [ 0, 512, 0 ],
rotation: [ Math.PI / 2, 0, Math.PI ]
},{

4. Add each side

Each side has to be added so in total there will be six sides for this. If you wanted to create your own background, an image with a 90-degree field of view horizontally and vertically has to be taken that points at all six sides. It’s easier to create this with a 3D application as the rotation and field of view can be exact.

url: 'img/scene-base.jpg',
position: [ 0, -512, 0 ],
rotation: [ – Math.PI / 2, 0, Math.PI ]
},{
url: 'img/scene-front.jpg',
position: [ 0, 0, 512 ],
rotation: [ 0, Math.PI, 0 ]
},{

5. Set up the cube

Now as all six sides have been referenced in the array, a cube is created by making a new 3D object and this is added into the scene. A for loop is created to iterate through each position in the array and this will be used to display the images in the scene as a box.

url: 'img/scene-back.jpg',
position: [ 0, 0, -512 ],
rotation: [ 0, 0, 0 ]
}];
var cube = new THREE.Object3D();
scene.add( cube );
for ( var i = 0; i < sides.length; i ++ ) {

6. Set each side

Information from each array position is stored in the variable side. A new image element is created and given a specific width. A CSS3DObject is created and added.

var side = sides[ i ];
var element = document.createElement( 'img' );
element.width = 1026;
element.src = side.url;
var object = new THREE.CSS3DObject( element );
object.position.fromArray( side.position );
object.rotation.fromArray
( side.rotation );
cube.add( object ); }

7. Icon images

Now that the background is in place, our attention will turn to creating icons that will sit in front of that. Another array is created, but this time round there is much less information than before and that’s because the image needs to be stored for each of the icons that will be placed on the screen.

8. Iterate the icons

Again a for loop is created to iterate through the images. A div element is created to hold each image within. The image is added using the JavaScript innerHTML command to create content inside of it. The image is given a unique id and the class of ‘pic’ that is used to style it later in the CSS. The source image is also added for the icon.

9. Handle the interaction

A click handler is added for the picture and at the moment this simply returns the value of the id to the console log. In the second part of the tutorial, we will learn how this calls the correct content to load for each of the icons. The image is then added to a CSS3DObject for placing in the scene. Then the position of the icon is calculated around the camera.

pic.addEventListener( 'click', function ( event ) {
console.log(event.target.id);
}, false );
var object = new THREE.CSS3DObject( pic );
var phi = (Math.PI*2) / menu.length;
phi = phi * i;

10. Position the icon

Using the code from the previous section each icon is positioned at equal positions around the camera. The 350 relates to the radius of the circle or how far from the camera the icons will appear. Once in position each icon is rotated to face the camera in the centre of the scene.

11. Add to the scene

The final step is to tell the object to look at the vector position setup, then the icon is added into the scene. The closing bracket will now finish off the for loop. This will mean that all of the code that is inside of the for loop is applied to each image icon so that they are all positioned to orbit the camera.

object.lookAt( vector );
scene.add( object );
}

12. Interactive map

This next block of code is to add an interactive Google Map to the page. Visit Google Maps and find a location you’d like to show, then click the menu button and from the slide-out panel, click the ‘share’ button. In the popup grab the embed code and paste the iframe into the third line of code shown here.

element = document.createElement( 'div' );
element.className = 'mapped';
element.innerHTML = ‘embed code here’;
var elementWidth = 600;
var elementHeight = 600;

13. Position the map

There is a large red square on the floor of the 3D scene, which is part of the background images added earlier on. We are positioning the map to be 600 by 600 pixels so, in the embed code added from Google, change the width and height to 600 for both. The map is positioned further down away from the camera and then rotated toward the camera.

element.style.width = elementWidth + "px";
element.style.height = elementHeight + "px";
var cssObject = new THREE.CSS3DObject( element );
cssObject.position.y = -400;
cssObject.rotation.x = -Math.PI/2;
scene.add(cssObject);

14. Add animated elements

The next element that is being added is a transparent PNG image with circular lines on it. This is added into the 3D scene and positioned above the camera while being rotated towards the camera. This will be animated to spin later on to provide some animation within the scene.

15. A second circle

Another circle is added and you will notice the pattern that a div element is created, inside here an image is placed. The div needs to be added as a CSS3DObject, this can be positioned and rotated to display correctly. Finally add the object to the scene to be displayed.

16. Display the 3D scene

The way the scene is to be updated is now set. Normally with three.js scenes this is the WebGL renderer but in this tutorial the CSS3D renderer is being used, for maximum compatibility. An event handler is registered to call the onWindowResize function if the screen changes and the animate function is used to update the screen.

renderer = new THREE.CSS3DRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
window.addEventListener( 'resize', onWindowResize, false );
animate();
}

17. Update the screen display

If the phone or tablet device is rotated from portrait to landscape or vice versa, the browser changes dimensions. In order to capture this, the onWindowResize function updates the aspect ratio of both the camera and the renderer so this will work on any size device with any size display.

18. Animate the scene

The animate function updates the screen’s display using the browser’s requestAnimationFrame command to update the screen at 60 frames per second, or as fast as the device can render it. The circles are rotated on the screen, the controls update and the scene is rendered or updated to display the view.

function animate() {
requestAnimationFrame( animate );
circle1.rotation.z += 0.001;
circle2.rotation.z -= 0.002;
controls.update();
renderer.render( scene, camera );
}

19. Set it all up

As we come to the end of the JavaScript code, the init() function is called which sets the scene up, placing everything in there and calling the scene to start rendering. After this the script tag is closed. Save this page now as all of theJavaScript code is added in here.

init();
</script>

20. CSS Body

Open the project.css file from the css folder on FileSilo. This is empty of all code, so add the code shown here for the body tag styling. This sets the background colour to white and sets the margins to zero, so that the scene fills the full browser display. The overflow is hidden and the font set to Helvetica or Arial.

body {
background-color: #ffffff;
margin: 0;
cursor: move;
overflow: hidden;
font-family: helvetica, arial, sans-serif;
}

21. The menu items

The next CSS rule sets the image icons that are displaying as the menu. This just sets the cursor to a pointer if the user has a cursor on rollover. This won’t be necessary for the majority of browsers as mobile and tablets don’t usually have mouse pointers!

22. Finish and save

The size of the pictures is set here using the width and height properties. Without this the image icons are just too big on the screen, but it’s useful to have the images a little bigger as most mobiles and tablets have high-pixel resolution screens. Save the file and place on a server then connect with your mobile device.

COME BACK FOR PART TWO NEXT WEEK

×