Creating WebGL animations within an Ionic application using ThreeJS

November 21, 2017, 9:00 am Categories:

Categories

Browser based 3D animation

Traditionally implementing 3D animation within a web/mobile application has always been challenging partly due to the impact on system resources, particularly memory consumption, but mostly as a result of lack of 3D support within the browser itself.

Proprietary solutions such as Flash and Silverlight were used by developers to help generate 3D animation (amongst other types of interactivity) for their projects as trying to accomplish such functionality with pure JavaScript was quite complex and fraught with difficulties - particularly when trying to normalise browser quirks in order for the project to render as platform-agnostic as possible.

With the introduction of new JavaScript API's, such as WebGL and Canvas, from browser vendors and their rapid adoption by developers previous barriers to generating complex animations, 3D environments and similar high-level interactive media were now beginning to fall.

Over the course of this tutorial I'm going to walk you through exploring WebGL by creating a very simple 3D animated cube - using the ThreeJS library - that is able to be rendered within an Ionic Framework application.

We'll explore certain API methods offered by the ThreeJS library (which is, quite simply, nothing short of brilliant) and, as a result, familiarise ourselves with adding 3D animation to an Ionic project.

As always the burning question with any technology that we are looking to use: what is the level of browser/device support available?

Choices & support

Even with modern browser support for technologies such as WebGL we, as developers, can never fully know what software our audience will be using to access our applications with (as even analytics tracking software isn't 100% accurate or reliable - particularly if the user has installed browser plugins to block features such as advertisements and/or JavaScript tracking).

This is why we always need to balance our choice of technologies with what level of software support exists. This way we can determine if our target audience is able to be reached with that choice of technology in place.

Currently browser support for WebGL stands as follows:

Browser Version
Internet Explorer 11
Edge 15+
Firefox 52+
Chrome 49+
Safari 10.1+
Opera 48+
iOS Safari 10.2+
Android 56+

As you can see support is relatively limited to the latest browser versions so bear this in mind when looking to use WebGL in your projects.

For the purposes of this demonstration and with an intended target audience of fellow developers we're in a pretty good position to justify using WebGL with Ionic.

What we'll be building

Our application, alluded to earlier, will simply consist of a single page application that displays an animated wireframe cube like so:

Nothing particularly earth-shattering as far as applications go but, nonetheless, a perfect introduction to implementing WebGL, via ThreeJS, within an Ionic project.

Now that we know what to expect let's start getting stuck into some development, starting with generating the project and installing the ThreeJS library.

Laying the foundation

Using your system CLI software navigate to a location on your computer where you want the project to be created before running the following commands (one after the other):

ionic start ionic-webgl blank
cd ./ionic-webgl
npm install three --save

Now that we've created our project and installed the ThreeJS library we're in position to begin coding the necessary logic to generate our animated 3D cube.

The logic

ThreeJS follows a set process when developing 3D animated projects which involves:

  • Defining a scene (which the object will be rendered within)
  • Choosing a particular camera type (to determine how the object will be presented to the viewer)
  • Define an object to be rendered to the scene
  • Configure and declare the object properties (I.e. shape, textures, animation features etc)
  • Adding the object to the scene

The documentation for the ThreeJS library is quite detailed and extensive in helping to guide you through the different steps and available options for the above process.

If you're new to 3D object generation/animation for the browser this can be quite a lot to take in, particularly if you're not familiar with some of the underlying concepts such as orthographic projection and parallax barrier.

I've done my best to break down each stage of the logic used to generate the 3D animated cube for this project with extensive comments and JSDoc syntax that accompanies each property and method within the HomePage component class.

You'll see this with the following code for the ionic-webgl/src/pages/home/home.ts component class:

import { Component, ViewChild, ElementRef } from '@angular/core';
import { NavController } from 'ionic-angular';
import * as THREE from 'three';



@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {


   /**
    * @name _DB
    * @type {object}
    * @private
    * @description     Defines an object for handling interfacing with the
    				   SQLite plugin
    */
   @ViewChild('domObj') canvasEl: ElementRef;




   /**
    * @name _ELEMENT
    * @type {object}
    * @private
    * @description      Defines an object for referencing the DOM element
    					where the WebGL object will be rendered to
    */
   private _ELEMENT : any;




   /**
    * @name _SCENE
    * @type {object}
    * @private
    * @description      ThreeJS needs a scene to render a WebGL object - this 
    					will act as an object reference for handling that requirement
    */
   private _SCENE;




   /**
    * @name _CAMERA
    * @type {object}
    * @private
    * @description      ThreeJS requires a camera for WebGL object generation - this 
    					will act as an object reference for handling that requirement
    */
   private _CAMERA;




   /**
    * @name renderer
    * @type {object}
    * @public
    * @description      ThreeJS requires a renderer for rendering the generated WebGL
    					object to the page DOM element - this will act as an object 
    					reference for handling that requirement
    */
   public renderer;




   /**
    * @name _GEOMETRY
    * @type {object}
    * @private
    * @description      Define a Geometry object for subsequent object rendering
    */
   private _GEOMETRY;




   /**
    * @name _MATERIAL
    * @type {object}
    * @private
    * @description      Define a Material object for subsequent object rendering
    */
   public _MATERIAL;




   /**
    * @name _CUBE
    * @type {object}
    * @private 
    * @description      Define a property for storing a reference to a polygon mesh object
    */
   public _CUBE;
   



   constructor(public navCtrl: NavController) 
   {  }



   
   /**
    * Execute methods when page view has fully loaded
    *
    * @public
    * @method ionViewDidLoad
    * @return {none}
    */
   ionViewDidLoad() : void
   {
      this.initialiseWebGLObjectAndEnvironment();
      this.renderAnimation();
   }




   /**
    * Initialise the WebGL objecty to be generated using 
    * selected ThreeJS methods and properties
    *
    * @public
    * @method initialiseWebGLObjectAndEnvironment
    * @return {none}
    */
   initialiseWebGLObjectAndEnvironment() : void
   {

      // Reference the DOM element that the WebGL generated object 
      // will be assigned to
      this._ELEMENT 			= this.canvasEl.nativeElement;


      // Define a new ThreeJS scene
      this._SCENE 				= new THREE.Scene();


      // Define a new ThreeJS camera from the following types:
      /* 
         1. CubeCamera				(Creates 6 cameras - one for each face of a cube)
         2. OrthographicCamera		(Creates a camera using orthographic projection - object size stays constant 
        							 regardless of distance from the camera)
         3. PerspectiveCamera		(Creates a camera using perspective projection - most common projection type 
        							 for 3D rendering [designed to mimic the way the human eye sees])
         4. StereoCamera			(Dual PerspectiveCameras - used for 3D effects such as parallax barrier)
      */
   	  this._CAMERA 				= new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );


   	  // Define an object to manage display of ThreeJS scene
   	  this.renderer 			= new THREE.WebGLRenderer();


   	  // Resizes the output canvas to match the supplied width/height parameters
   	  this.renderer.setSize( window.innerWidth, window.innerHeight );


   	  // Attach the canvas, where the renderer draws the scene, to the specified DOM element 
   	  this._ELEMENT.appendChild( this.renderer.domElement );


   	  // BoxGeometry class allows us to create a cube (with width, height and depth dimensions supplied as 
   	  // parameters - default is 1 for these values) 
      this._GEOMETRY 			= new THREE.BoxGeometry( 1, 1, 1 ); 


      // Define the material (and its appearance) for drawing the geometry to the scene
      this._MATERIAL 			= new THREE.MeshBasicMaterial( { color: 0xffffff, wireframe : true } );


      // Use the Mesh class to define a polygon mesh based object with the supplied geometry and material objects
      this._CUBE 				= new THREE.Mesh( this._GEOMETRY, this._MATERIAL );


      // Add the object to the scene
      this._SCENE.add(this._CUBE);


      // Define the depth position of the camera
      this._CAMERA.position.z 	= 5;
   }




   /**
    * Define the animation properties for the WebGL object rendered in the DOM element, using the requestAnimationFrame 
    * method to animate the object
    *
    * @private
    * @method animate
    * @return {none}
    */
   private _animate () : void
   {
   	  requestAnimationFrame(() =>
   	  {
   	     this._animate();
   	  });
  

  	  // Define rotation speeds on x and y axes - lower values means lower speeds
   	  this._CUBE.rotation.x += 0.015;
   	  this._CUBE.rotation.y += 0.015;
  

      // Render the scene (will be called using the requestAnimationFrame method to ensure the cube is constantly animated)
   	  this.renderer.render(this._SCENE, this._CAMERA);
   };




   /**
    * Render the animation 
    *
    * @public
    * @method _renderAnimation
    * @return {none}
    */
   renderAnimation() : void
   {
      //if (Detector.webgl) 
      //{
         this._animate();
      /*}
      else {
         var warning = Detector.getWebGLErrorMessage();
         console.log(warning);
      }*/
   }


}

Although this might be a lot to take in at first, particularly for those new to ThreeJS (and I'm currently at the new end of that scale myself!), the above comments should help explain the purpose of these different properties and methods and how they are used, in conjunction with the ThreeJS library API methods, to generate the 3D animated cube.

In order to complete the development for this project we need to add the necessary templating to the component view.

Templating the application

As you'll soon see the markup required for our application is quite minimal.

We simply add a <div> tag which is assigned a template reference variable of #domObj.

This template reference variable is then able to programmatically link the template with the component class, courtesy of Angular's ViewChild and ElementRef modules, to allow the 3D animated cube to be rendered to the screen.

Open the ionic-webgl/src/pages/home/home.html component view and add this markup like so:

<ion-header>
  <ion-navbar>
    <ion-title>
      Three JS rotating cube
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
  <div #domObj></div>
</ion-content>

Told you it was minimal didn't I? :)

Running the application

With our code now in place for the HomePage component all that remains is to actually test this works (pretty important when you're a developer - particularly when you want to get paid for client work!)

From your system CLI run the following command to preview and run the application within your system browser:

ionic serve

Assuming that a) your browser supports WebGL and b) you followed the above code when developing this application you should see the following being rendered to the screen (albeit while animating):

In summary

ThreeJS, which may appear a little complex at first with its particular underlying concepts, terminology and approach, makes browser based 3D generation and animation a relatively simple task to accomplish.

With an extensive and richly documented API developers have carte blanche when it comes to exploring and realising their ideas in the 3D workspace - although that doesn't mean they still don't have to be mindful of taxing system resources; particularly on handheld devices and older platforms.

There's definitely more we could have done with the above tutorial such as creating a more expansive and detailed environment for our animated cube to rotate within or adding multiple different animated objects to the scene but we can always explore further possibilities with ThreeJS and Ionic in future tutorials.

Hopefully you have found this tutorial useful and it's given you some idea of how simple it is to incorporate 3D animation within your Ionic projects.

Please feel free to leave a comment in the section below and share your thoughts, suggestions and general feedback with other readers.

In my Mastering Ionic : The Definitive Guide e-book I explore using Angular animations within Ionic but a future release, post Ionic 4, will feature a WebGL project so stay tuned for development on that front by subscribing to my e-mail newsletter (if you haven't already done so).

Tags

Categories

Post a comment

All comments are welcome and the rules are simple - be nice and do NOT engage in trolling, spamming, abusiveness or illegal behaviour. If you fail to observe these rules you will be permanently banned from being able to comment.

Top