@thespite

JSConf.Budapest

Getting started with three.js and WebGL

Jaume Sanchez | @thespite

JSConf.Budapest

Getting started things done with three.js and WebGL

Jaume Sanchez | @thespite

First, some unit testing

Building 3D experiences

WebGL

khronos.org/webgl
get.weblg.org

MDN WebGL
MSDN

WebGL samples
Chrome Experiments WebGL

three.js

threejs.org
Github Project

Examples
Documentation

Getting started

Setting up

Code structure

Initialise renderer
Initialise scene and camera
Set render loop

throw it in a pot, add some broth, a potato.
Baby, you've got a stew going.

Setting up


<script src="three.min.js" ></script>
threejs.org | GitHub

var renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

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

function render() {

	requestAnimationFrame( render );
	renderer.render( scene, camera );

}

render();

Adding stuff to render

Meshes


var mesh = new THREE.Mesh( geometry, material );

scene.add( mesh );

Choosing a geometry

Three.js primitives:
Sphere, Box, Cylinder and many more!

Adding stuff to render

Meshes


var material = new THREE.MeshNormalMaterial( { wireframe: true } );

var cube = new THREE.Mesh( new THREE.BoxGeometry( 20, 20, 20 ), material );
scene.add( cube );

var sphere = new THREE.Mesh( new THREE.IcosahedronGeometry( 10, 2 ), material );
sphere.position.x = 30;
scene.add( sphere );

var torus = new THREE.Mesh( new THREE.TorusKnotGeometry( 10, 3, 50, 20 ), material );
torus.position.x = -30;
scene.add( torus );

Choosing a geometry

models (OBJ, STL, etc.)

Adding stuff to render

Models


<script src="js/OBJLoader.js" ></script>

var snowden;

var loader = new THREE.OBJLoader();
loader.load( 'assets/snowden.obj', function( geometry ) { 

	snowden = new THREE.Mesh(
		geometry,
		new THREE.MeshNormalMaterial() } )
	);
	scene.add( snowden );

}

Choosing a light model

Flat, basic, Lambert, Phong...

Adding stuff to render that can be seen

Lights


// Soft white light

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

// White directional light at half intensity shining from the top.

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

var mesh = new THREE.Mesh(
	new THREE.BoxGeometry( 10, 10, 10 ),
	new THREE.MeshBasicMaterial( { color: 0xff00ff } )
);
scene.add( mesh );

Adding stuff to render that can be seen

Lights


// white spotlight shining from the side, casting shadow

var spotLight = new THREE.SpotLight( 0xffffff );
spotLight.position.set( 100, 1000, 100 );

spotLight.castShadow = true;

scene.add( spotLight );

var mesh = new THREE.Mesh(
	new THREE.BoxGeometry( 10, 10, 10 ),
	new THREE.MeshPhongMaterial()
);
scene.add( mesh );

Choosing a light model

Spherical environment mapping (SEM)

Choosing a light model

Image-based lighting (IBL)

Choosing a light model

Baked

Choosing a light model

Shaders

Cru·ci·form shaders

Animation

Everything is a THREE.Object3D

Can be translated, rotated, scaled

Animation

cube.position.set( 10, 20 + t, 30 );

cylinder.position.y = 100 * Math.sin( t );
cylinder.rotation.z = t;

sphere.rotation.set( t, 2 * t, 3 * t );

camera.position.set( 0, 10, 10 + t );
var pos = new THREE.Vector3( 0, 10 * Math.sin( t ), 0 );
camera.lookAt( pos );

camera.lookAt( cube.position );

Camera controls

// Standard controls
var controls = new THREE.OrbitControls( camera );

// WebVR (HMD) controls
var controls = new THREE.VRControls( camera );

// DeviceOrientation (Cardboard) controls
var controls = new THREE.DeviceOrientationControls( camera );

function render() {

	controls.update();
	renderer.render( scene, camera );

}

Exploration

or the unexpected virtue of
creation through procrastination

Exploration

Parallax-corrected reflection mapping

Surfacing and PBR materials

Camera scripting

Postprocessing

Wagner
GitHub page


<script src="Wagner.js" ></script>
<script src="Wagner.base.js" ></script>

var composer = new WAGNER.Composer( renderer, {} );
composer.setSize( renderer.domElement.clientWidth, renderer.domElement.clientHeight );

function render() {

	requestAnimationFrame( render );

	//renderer.render( scene, camera );

	composer.reset();
	composer.render( scene, camera );
	composer.toScreen();

}

Postprocessing

passes


var CGAPass = new WAGNER.CGAPass();

function render() {

	requestAnimationFrame( render );

	composer.reset();
	composer.render( scene, camera );
	composer.pass( CGAPass );
	composer.toScreen();

}

Postprocessing

Passes you can never go wrong with:

Depth-of-field
Bloom
Chromatic aberration
Tone mapping
Vignette
Noise

The secret is to not over do it!

Debugging and optimisation

AugmentedShaderCompiler

GitHub page

npm install augmented-compile-shader

Debugging and optimisation

THREE.AugmentedConsole

GitHub page

Debugging and optimisation

WebGL Shader Editor

GitHub page | Chrome Store

Snowden shaders

Releasing!

Different versions and hosting considerations

Mobile
ANGLE
Retina displays

Might have to play with:
simplify models and textures
devicePixelRatio / CSS scaling
reduce or remove postprocessing

Use a CDN, like CloudFlare

Releasing!

Congratulations!

Lessons learned

Release early, release often

Don't obsess, let it rest,
come back at a later time

Remember: creation through procrastination
or yak shaving. That works, too

Lessons learned

10 Iterate

20 Goto 10

Lessons learned

Blocking as soon as possible

Keep music for last, you'll end up hating it

Lessons learned

Performance driven development

Lessons learned

As long as it works, it's fine

Jaume Sanchez

Technical Director / Creative Technologist @ B-REEL

clicktorelease.com

Thanks!

Questions?
Hit me up on twitter!
@thespite