writer, web developer, designer

From the Blog

Dec
21

At my new job I’m taking a look at WebGL for various prototype visualisations. Having tried a number of frameworks, I’ve found ThreeJS to be the easiest of them to get up and running quickly.

WebGL cube via ThreeJS

var container, stats;
var camera, scene, renderer;
var cube;

var targetRotationX = 10;
var targetRotationY = 10;
var targetRotationZ = 10;
var targetRotationOnMouseDown = 0;

var mouseX = 0;
var mouseXOnMouseDown = 10;

var mouseY = 0;
var mouseYOnMouseDown = 10;


var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;

$(function() {
    init();
    animate();
})

function init() {

    container = document.createElement( 'div' );
    document.body.appendChild( container );

    scene = new THREE.Scene();

    camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
    camera.position.y = 150;
    camera.position.z = 500;
    scene.add( camera );
    
    // LIGHT IN FRONT
    var light = new THREE.PointLight( 0xffffff, 2.0 );
    light.position.set( 0, 500, 1000 );
    light.castShadow = false;
    scene.add( light );
    
    var materials = [];

    for ( var i = 0; i < 6; i ++ ) {
        materials.push( new THREE.MeshPhongMaterial( {
            color: 0x9CDB79,
            opacity: 0.5,
            transparent:true
        } ) );
    }

    cube = new THREE.Mesh( new THREE.CubeGeometry( 200, 200, 200, 1, 1, 1, materials ), new THREE.MeshFaceMaterial() );
    cube.position.x = 0;
    cube.position.y = 150;
    cube.position.z = 0;
    cube.rotation.x = 5;
    cube.rotation.y = 5;
    cube.rotation.z = 5;
    cube.doubleSided = true;
    cube.flipSided = false;
    cube.overdraw = true;
    cube.dynamic = false;
        
    cube.overdraw = true;
    scene.add( cube );

    renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize( window.innerWidth, window.innerHeight );

    container.appendChild( renderer.domElement );

    stats = new Stats();
    $("#stats").append( stats.domElement )

    document.addEventListener( 'mousedown', onDocumentMouseDown, false );
}

function onDocumentMouseDown( event ) {
    event.preventDefault();
    document.addEventListener( 'mousemove', onDocumentMouseMove, false );
    document.addEventListener( 'mouseup', onDocumentMouseUp, false );
    document.addEventListener( 'mouseout', onDocumentMouseOut, false );
    mouseXOnMouseDown = event.clientX - windowHalfX;
    mouseYOnMouseDown = event.clientY - windowHalfY;
    targetRotationOnMouseDown = 5;
}
function onDocumentMouseMove( event ) {
    mouseX = event.clientX - windowHalfX;
    targetRotationY = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.02;
    mouseY = event.clientY - windowHalfY;
    targetRotationX = targetRotationOnMouseDown + ( mouseY - mouseYOnMouseDown ) * 0.02;
}
function onDocumentMouseUp( event ) {
    document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
    document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
    document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
}
function onDocumentMouseOut( event ) {
    document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
    document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
    document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
}
function animate() {
    requestAnimationFrame( animate );
    render();
    stats.update();
}
function render() {
    cube.rotation.x += ( targetRotationX - cube.rotation.x ) * 0.05;
    cube.rotation.y += ( targetRotationY - cube.rotation.y ) * 0.05;
    renderer.render( scene, camera );
}

									

Click here to view the demo in action.

When creating an object we can colour it. A notes that I found useful:

cube = new THREE.Mesh( cubeGeo, new THREE.MeshLambertMaterial({ color: Math.random() * 0xffffff, opacity: 0.9, transparent: true }) );
									

Math.random() * 0xffffff generates a random colour

opacity sets the opacity level for the surfaces within our cube. For example, the you can see ‘into’ the cube through its surfaces, but other objects that are behind your cube will not be visible.

transparent:true will apply your the opacity to the entire cube. Other objects in the scene will be visible through the cube.

I’ve also seen this technique for applying a material directly to each side of a cube:

for ( var i = 0; i < 6; i ++ ) {
        materials.push( new THREE.MeshPhongMaterial( {
            color: 0x9CDB79,
            opacity: 0.5
        } ) );
    }

cube = new THREE.Mesh( new THREE.CubeGeometry( cubeSize, cubeSize, cubeSize, 1, 1, 1, materials ), new THREE.MeshFaceMaterial() );
        
									

…however it causes horrific flickering in Google Chrome. Probably best to avoid.