WebGL and Three.js with Blender - the Browser 3D geometry

In this post, I will explain how you can display 3D content in browser. By content, I mean a whole set of objects in a scene: those are named Meshs. The scene at left is an example for WebGL: you can zoom, turn around and move inside through the scene.

Technical stack

webGL and three.js

Step1 : Browser 3D

There is several ways to display 3D content in a browser. The simplest is to use an image or movie to simulate a 3D content. Disadvantages are:

  • User does not interact with the scene: for example, it is impossible to make a planet move on a solar system photo.
  • High data loading: the content is load from server and nothing is calculated client side (as WebGL does).

Browser recently offers more ways to display 3D content. Before that, Flash was mainly used to display 3D but this technology needs to be installed before use. Besides, Apple doesn’t want to use it: a lot of people cannot access content using Flash. Fortunately, there is other ways to proceed now. Unity 3D is one of them but the Unity community is too small and underused. Recently, the WebGL technology appears to be an efficient way to get 3D content in browser. More and more user uses it every days that’s why it could become the standard on the market.

In this article, I’ll explain you how to proceed to use the WebGL technology through a JavaScript motor named Three.js I advise you to go on their web site to see webGL examples: it could convince you!

Step2: Get all requirements

Browser

Before using WebGL, you must verify the browser versions supporting webGL or test your own browser compatibility.

Three.js : JavaScript motor for WebGL

To use webGL with Three.js, you must at least download Three.js files.

Text editor for JavaScript

Actually, I use Sublime Text 2 that is, I found out, a really effective way to develop in JavaScript (and really efficient to make massive replacement through large amount à files).

Blender

It is easy to display mesh in a 3D scene with three.js but it can be hard to model your mesh with three.js: the best way to model your mesh is the use of a 3D editor. If you want, you can download Blender. With Blender, I use a really useful plugin allowing JSON file export from Blender 3D model: those files will be then loaded by Three.js. This plugin is given by Three.js and can be found at this path: three.js-master\utils\exporters\blender\2.65\scripts\addons. Move the folder iomeshthreejs in Blender folder* Blender\2.70\scripts\addons*.

Step 3 : Model 3D objects

Open Blender and model what you want. For example, I made five circles around a sphere:

Damien-Leroux-webgl-Blender1.jpg

Then, I used the plugin to export what I made in Blender to JSON files that contains modelisation data (vertices, colors, position, textures,…)

Damien-Leroux-webgl-Blender2.jpg

Select as I do the plugin options to export the simplest way the Blender model.

Damien-Leroux-webgl-Blender3.png

You should obtain a set of JavaScript files in your export folder.

  • A main file with main data: mesh names, positions, rotations, etc...
  • A file for each mesh:th emesh name, vertices, normales, colors, etc...

Damien-Leroux-webgl-Blender4.png

Those files, build on JSON format, will be loaded by three.js. You can download the files I export here.

Step 4 : Initialisation - load and set the 3D scene

Below the code the WebGL scene:

function createScene() {
    scene =  new THREE.Scene(),

    /*Camera*/
    camera = new THREE.PerspectiveCamera( 65, container.clientWidth / container.clientHeight, 1, 1500 )
    camera.position.y = 4;
    camera.position.x = 5;
    camera.position.z = 0;
    var camTarget = new THREE.Vector3(0,0,0);
    camera.lookAt( camTarget );
    scene.add( camera );
}


function loadScene() {
    var callbackFinished = function ( result ) {
        result.scene.traverse( function ( object ) {
            if ( object instanceof THREE.Mesh ) {
                meshs.push(object);
            }
        } );
        for ( meshsId in meshs) {
            scene.add(meshs[meshsId]);
        }
    };

    /*load scene*/
    var loader = new THREE.SceneLoader();
    loader.load('./exportBlender/WebGLExample.js', callbackFinished);

}


function initRenderer(){
    renderer = new THREE.WebGLRenderer( { antialias: true } );
    renderer.setSize(container.clientWidth, container.clientHeight);
    renderer.domElement.style.position = "relative";
    renderer.setClearColor(new THREE.Color(0xffffff));

    container.appendChild( renderer.domElement );
    container.addEventListener( 'resize', onWindowResize, false );
}


function init() {
    //create the scene to display on screen
    createScene();
    //load the scene from JSON Files
    loadScene();
    //init the renderer to display the created scene
    initRenderer();
}

createScene() At first, we must create the scene. We add a camera: a mandatory element to be able to see something in the scene.

loadScene() Then, we load elements to display thanks to the JSON files. To do so, we create a function that will be called when all JSON files are loaded: this is a callback function. This function will go through loaded objects from files to add them in the current webGL scene. To call this function, we must load files with loader.load('/static/WebGLExample.js', callbackFinished) with the main JSON file path and the callback function as parameters. Loading the main JSON file will load all others related files.

initRenderer() After loading the scene, we open a window to display it. This window is called « renderer ». It is initialized with a final length and width and other parameters as color, position, etc... The list of parameters is large. When the renderer is ready, we link the chosen DOM element to it:

var container = document.getElementById( 'renderWebGL1' );
container.appendChild( renderer.domElement );

Step 5 : Display the scene

Damien Leroux WebGL1

When the renderer and the scene are ready, we animate the scene with the function animate(). This function automatically refreshs the scene with the function requestAnimationFrame(animate). animate() will be continually called. Another function named render() will then display the scene each time this one is refreshed. This function displays the scene and the camera: renderer.render( scene, camera );. As you see, the result is simple: colors, lights and mouvements are missing. Download the corresponding JavaScript file here

Step 6 : Lights and colors

Damien Leroux WebGL2

Adding lights is really easy: You must choose the type of light you want to add in the scene: directional or ambient light. Before trying to choose color for lights, it is interesting to color objects. Objects get a material used to set transparency, colors, textures, etc... Download the corresponding JavaScript file here

In my example, objects are randomly colored when the scene is loaded.

var callbackFinished = function ( result ) {for ( meshsId in meshs) {
        …
        meshs[meshsId].material.materials[0].color.b = Math.random();
        meshs[meshsId].material.materials[0].color.g = Math.random();
        meshs[meshsId].material.materials[0].color.r = Math.random();
    }
};

Damien Leroux WebGL3

Another way to color objects could be to call setHex to give a hexa color to material: meshs[meshsId].material.materials[0].color.setHex(0x0000ff); Download the corresponding JavaScript file here

Step 7 : Movement

Damien Leroux WebGL4

Everything can be moved in a webGL scene. Let’s begin with the meshes: A number of rotations are applied:

function rotate(object, axis, radians) {
    //rotation matrix is calculated
    var rotationMatrix = new THREE.Matrix4();
    rotationMatrix.makeRotationAxis(axis.normalize(), radians);

    //apply rotation on the object matrix ( set the objet direction)
    rotationMatrix.multiply(object.matrix);             
    object.matrix = rotationMatrix;

    //apply rotation on object (set the object inclinaison)
    object.rotation.setFromRotationMatrix(rotationMatrix);
}

Download the corresponding JavaScript file here

Another thing to move is the camera. In my example, I use a trackball to turn around the meshes. To do it, the code is given by three.js: you must load the JavaScript file: TrackballControls.js from repository three.js-master/examples/js/controls. When this file is included, we initialize the trackball:

function createScene() {
    scene =  new THREE.Scene();

    /*Camera*/
    camera = new THREE.PerspectiveCamera( 65, container.clientWidth / container.clientHeight, 1, 1500 )
    camera.position.y = 4;
    camera.position.x = 5;
    camera.position.z = 0;
    var camTarget = new THREE.Vector3(0,0,0);
    camera.lookAt( camTarget );
    scene.add( camera ); 

}

and then update it when displaying the scene;

function animate() {//update trackball here
    trackball.update();}

Download the corresponding JavaScript file here

Step 8 : What to do if WebGL is not supported

We want modify what will be displayed if WebGL is not supported by your browser or if no canvas has been generated.

if (window.WebGLRenderingContext){
    init();
    animate();

    var canvas = container.getElementsByTagName("canvas");
    if ( canvas != undefined){
        var context = canvas[0].getContext("webgl");
        if (!context) {
            container.innerHTML= 'webGL content not initialized';
        }
    }else{
        container.innerHTML= 'webGL content Not Found';
    }
}else{
    container.innerHTML= 'impossible to display webGL content';

}

In this example, init() and animate() will be called only if webGL rendering is possible. Otherwise, a message is displayed.