Painless 3D graphics in browser with THREE.js

Speaker

Jakub Skałecki

"Painless 3D graphics with THREE.js"

2016-03-09

@jskalc

Presentation plan

  1. Examples!
  2. Short introduction to OpenGL and WebGL
  3. What is THREE.js
  4. Hello world
  5. Modify it!
  6. Shapes
  7. Extras

Examples!

  1. Arms Globe
  2. One million stars
  3. WebGL Water
  4. Bubbles
  5. One million particles
  6. Practical example - acko.net logo
  7. THREE.js examples
  8. Flight of the navigator

OpenGL

Open Graphics Library is a cross-language, cross-platform application programming interface (API) for rendering 2D and 3D vector graphics. The API is typically used to interact with a graphics processing unit (GPU), to achieve hardware-accelerated rendering.

Wikipedia

OpenGL

WebGL

Browser version of OpenGL. Allows to use GPU accelerated 3D rendering, currently supported by all modern browsers.

THREE.js to the rescue!

Most popular WebGL wrapper

You don't have to touch native WebGL code!

Lots of ready to use helpers, like OrbitCamera, and reference examples. Easy to learn, as each THREE.js example source code is easily available (just look at source of a site).

Scene and camera

            
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
60, window.innerWidth / window.innerHeight, 0.1, 1000 );

var renderer = new THREE.WebGLRenderer();           
renderer.setClearColor( 0xffffff );     
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
            
        

Objects

            
var geometry = new THREE.BoxGeometry( 2.5, 2.5, 2.5 );
var material = new THREE.MeshBasicMaterial({ 
    color: 0xff0000, 
    wireframe: true 
});
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );

// we have to move camera to actually see a cube
camera.position.z = 5;
            
        

Render loop

            
function render() {
    cube.rotation.x += 0.03;
    cube.rotation.y += 0.03;
    requestAnimationFrame( render );
    renderer.render( scene, camera );
}
render();
            
        

Hello world! (link) - 17 SLOC

Let's modify it - fog

            
// add fog
scene.fog = new THREE.FogExp2( 0xcccccc, 0.002 );

// and set clear color
renderer.setClearColor( scene.fog.color );  
            
        

Let's modify it - controls

            
// add and initialize OrbitControls.js  
var controls = new THREE.OrbitControls( 
    camera, renderer.domElement );
controls.enableDamping = true;
controls.dampingFactor = 0.2; 

// inside render()
controls.update();
            
        

Let's modify it - objects

            
var geometry = new THREE.CylinderGeometry( 0, 10, 30, 16, 1 );
var material =  new THREE.MeshPhongMaterial( { color:0x77ff77 } );
for ( var i = 0; i < 500; i ++ ) {
    var mesh = new THREE.Mesh( geometry, material );
    mesh.position.x = ( Math.random() - 0.5 ) * 1000;
    mesh.position.y = ( Math.random() - 0.5 ) * 1000;
    mesh.position.z = ( Math.random() - 0.5 ) * 1000;
    scene.add( mesh );
}
            
        

Let's modify it - lights

            
var light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 1, 1, 1 );
scene.add( light );

light = new THREE.DirectionalLight( 0x002288 );
light.position.set( -1, -1, -1 );
scene.add( light );

light = new THREE.AmbientLight( 0x222222 );
scene.add( light );
            
        

It's ready (link) - 30 SLOC

Last change - shape

            
var x = 0, y = 0, heartShape = new THREE.Shape(); 

heartShape.moveTo( x + 25, y + 25 );
heartShape.bezierCurveTo( x + 25, y + 25, x + 20, y, x, y );
heartShape.bezierCurveTo( x - 30, y, x - 30, y + 35,x - 30,y + 35 );
heartShape.bezierCurveTo( x - 30, y + 55, x - 10, y + 77, x + 25, y + 95 );
heartShape.bezierCurveTo( x + 60, y + 77, x + 80, y + 55, x + 80, y + 35 );
heartShape.bezierCurveTo( x + 80, y + 35, x + 80, y, x + 50, y );
heartShape.bezierCurveTo( x + 35, y, x + 25, y + 25, x + 25, y + 25 );
            
        

Last change - shape

            
var extrudeSettings = { 
    amount: 8, bevelEnabled: true, bevelSegments: 2, 
    steps: 2, bevelSize: 1, bevelThickness: 1 
};
var geometry = new THREE.ExtrudeGeometry( 
    heartShape, extrudeSettings );
            
        

Result (link) - 44 SLOC

Extra - custom shader (example)

            
var material = new THREE.ShaderMaterial( {
    uniforms: {
        time: { type: "f", value: 1.0 },
        resolution: { type: "v2", value: new THREE.Vector2() }
    },
    attributes: {
        vertexOpacity: { type: 'f', value: [] }
    },
    vertexShader: document.getElementById( 'vs' ).textContent,
    fragmentShader: document.getElementById( 'fs' ).textContent
} );
            
        

Extra - loading textures

            
var texture = new THREE.Texture();
var loader = new THREE.ImageLoader();
loader.load( 'path/to/texture.jpg', function ( image ) {
    texture.image = image;
    texture.needsUpdate = true;
} );
// usage
material.map = texture;
            
        

Extra - loading OBJ files (example)

            
var loader = new THREE.OBJLoader();    
loader.load( 'path/to/obj', function ( object ) {
    scene.add( object );
}, onProgress, onError );
            
        

Links

  1. THREE.js
  2. Orbit Controls
  3. OpenGL - wikipedia

Questions?

Speaker

Jakub Skałecki

Polyglot programmer

jakub.skalecki@gmail.com

@jskalc