cs291 ยป

three.js reference

This reference page is here to save you time skimming through videos to find and copy code snippets. Relevant snippets of three.js code are shown by lesson, with an additional comment or two; the course's source code contains more. See the three.js documentation site for more about three.js. See the syllabus for links to the individual lessons.

Lesson 2: Points, Vectors, and Meshes

Creating Geometry in three.js

var material = new THREE.MeshBasicMaterial( { color: 0xff0000, side: THREE.DoubleSide } );

var geometry = new THREE.Geometry();
geometry.vertices.push( new THREE.Vector3( 5, 10, 0 ) );  // vertex 0
geometry.vertices.push( new THREE.Vector3( 5, 5, 0 ) );   // vertex 1
geometry.vertices.push( new THREE.Vector3( 10, 5, 0 ) );  // vertex 2

geometry.faces.push( new THREE.Face3( 0, 1, 2 ) );  // make a triangle

var mesh = new THREE.Mesh( geometry, material );  // create an object

scene.add( mesh ); // add object to the scene to make it visible

Build A Stairway

var geoBlock = new THREE.CubeGeometry( width, height, thickness );
var blockMesh = new THREE.Mesh( geoBlock, material );
// set the X,Y,Z position
stepMesh.position.x = xPosition;
stepMesh.position.y = yPosition;
stepMesh.position.z = zPosition;

The Drinking Bird

// values 32, 16 are longitude and latitude tessellations
var sphere = new THREE.Mesh(
    new THREE.SphereGeometry( radius, 32, 16 ), sphereMaterial );

var cylinder = new THREE.Mesh(
    new THREE.CylinderGeometry( radiusTop, radiusBottom, height, 32 ), cylMaterial );

Lesson 3: Colors and Materials

Setting the Color

var sphereMaterial = new THREE.MeshLambertMaterial( );
// three separate floats to set RGB
sphereMaterial.color.r = 1.0;    
sphereMaterial.color.g = 0.0;
sphereMaterial.color.b = 0.0;
// or use the setRGB method
sphereMaterial.color.setRGB( 0.972, 0.749, 0.141 );
// or use a hex value, 0x00 to 0xFF (0-255), for each channel
sphereMaterial.color.setHex( 0x1280FF );

// or initialize your material with the color
var cylMaterial = new THREE.MeshLambertMaterial( { color: 0xF4F100 } );

Vertex Attributes

// how to set the three vertex colors for face #0
var color1 = new THREE.Color( 0xF08000 ); // orange
var color2 = new THREE.Color( 0x808000 ); // olive
var color3 = new THREE.Color( 0x0982FF ); // bright blue
geometry.faces[0].vertexColors = [ color1, color2, color3 ];

Diffuse Material

material = new THREE.MeshBasicMaterial( { color: 0x80fc66, shading: THREE.FlatShading } );
material.color.setRGB( red, green, blue );
var newRed = material.color.r * 0.7;
material.ambient.setRGB( ... );

Ka, Kd, and HSL

var color = new Color();
// hue, saturation, and lightness, all 0-1
color.setHSL( 0.117, 0.937, 0.557 ); // orange

Transparency and Three.js

var movingBoxMaterial = new THREE.MeshLambertMaterial(
    { color: 0xE53319, opacity: 0.7, transparent: true } );

Lesson 4: Transforms

Translation

sphere.position.x = xPosition;
sphere.position.y = yPosition;
sphere.position.z = zPosition;

Rotation

cube.rotation.x = xRotationInRadians; // e.g. -70 * Math.PI/180
cube.rotation.y = yRotationInRadians;
cube.rotation.z = zRotationInRadians;

Rigid Body Transforms vs Scaling

cube.scale.x = xSize;
cube.scale.y = ySize;
cube.scale.z = zSize;

Scale Rotate Translate

// This is always the order of application:
cube.scale.set( xSize, ySize, zSize );
cube.rotation.set( xRotationInRadians, yRotationInRadians, zRotationInRadians );
cube.position.set( xPosition, yPosition, zPosition );

Object3D

var block = new THREE.Mesh(
    new THREE.CubeGeometry( 100, 4, 4 ), clockHandMaterial );
block.position.x = 40;
// make the parent object
var clockHand = new THREE.Object3D();
clockHand.add( block );

clockHand.rotation.y = -70 * Math.PI/180;
scene.add( clockHand );

Lesson 5: Matrices

Identity Matrix

var mtx = new THREE.Matrix4();
mtx.identity();

Using a Matrix

var mtx = new THREE.Matrix4(
    1, 0, 0, 12,
    0, 1, 0, 16,
    0, 0, 1, -5,
    0, 0, 0,  1 );

mtx.makeTranslation( x, y, z );
mtx.makeTranslation(12,16,-5 );

forearm.matrix = mtx;
forearm.matrixAutoUpdate = false;

Axis of Rotation

mtx.makeRotationAxis( axis, theta );

Angle of Rotation

// get two diagonally-opposite corners of the cube
// and compute the cylinder axis direction and length
var maxCorner = new THREE.Vector3(  1, 1, 1 );
var minCorner = new THREE.Vector3( -1,-1,-1 );
var cylAxis = new THREE.Vector3();
cylAxis.subVectors( maxCorner, minCorner );
var cylLength = cylAxis.length();

// take dot product of cylAxis and up vector
// to get cosine of angle
cylAxis.normalize();
var theta = Math.acos(
    cylAxis.dot( new THREE.Vector3(0,1,0) ) );

// alternate version:
var theta = Math.acos( cylAxis.y );

Cross Product

var rotationAxis = new THREE.Vector3();
rotationAxis.crossVectors( cylAxis, new THREE.Vector3(0,1,0) );

var negRotationAxis = new THREE.Vector3();
negRotationAxis.crossVectors( new THREE.Vector3(0,1,0), cylAxis );

// special case: if rotationAxis is just about zero, set to X axis,
// so that the angle can be given as 0 or PI
if ( rotationAxis.length() == 0 )
{
    rotationAxis.set( 1, 0, 0 );
}
rotationAxis.normalize();

Make an Ornament or Caltrop

var cylinder = new THREE.Mesh(
    new THREE.CylinderGeometry( 0.2, 0.2, cylLength, 32 ), cylinderMaterial );

var rotationAxis = new THREE.Vector3(1,0,-1);
// makeRotationAxis wants its axis normalized
rotationAxis.normalize();
// don't use position, rotation, scale
cylinder.matrixAutoUpdate = false;
cylinder.matrix.makeRotationAxis( rotationAxis, theta );

Rotation Times Rotation

airplane.rotation.x = effectController.ex * Math.PI/180;    // pitch
airplane.rotation.y = effectController.ey * Math.PI/180;    // yaw
airplane.rotation.z = effectController.ez * Math.PI/180;    // roll

Lesson 6: Lights

Directional Light in three.js

var light = new THREE.DirectionalLight( 0xFFFAAD, 0.7 );
light.position.set( 200, 500, 600 );
scene.add( light );

light.position.set( 2, 5, 6 );
light.position.set( 0.02, 0.05, 0.06 );

Ambient Lighting

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

var someMaterial = new THREE.MeshLambertMaterial( );
someMaterial.color.setRGB( 0.8,0.2,0.1);
someMaterial.ambient.copy( someMaterial.color );

Head Light

var light = new THREE.PointLight( 0xFFFFFF, 1.0 );
light.position.set( 1000, 1000, 1000 );
scene.add( light );

function render() {
    var delta = clock.getDelta();
    cameraControls.update(delta);

    renderer.render(scene, camera);
}

Shadows in three.js

renderer.shadowMapEnabled = true;

spotlight.castShadow = true;

cube.castShadow = true;
cube.receiveShadow = true;


bbird.traverse( function ( object ) {
    if ( object instanceof THREE.Mesh ) {
        object.castShadow = true;
        object.receiveShadow = true;
    }
} );

// controls shadow bias:
spotlight.shadowBias = 0.0001;

Lesson 7: Cameras

Three.js Orthographic Camera

viewSize = 900;
aspectRatio = canvasWidth/canvasHeight;
// OrthographicCamera( left, right, top, bottom, near, far )
camera = new THREE.OrthographicCamera(
    -aspectRatio*viewSize / 2, aspectRatio*viewSize / 2,
    viewSize / 2, -viewSize / 2,
    -1000, 1000 );

camera.position.set( -890, 600, -480 );
cameraControls = new THREE.OrbitAndPanControls(camera, renderer.domElement);
cameraControls.target.set(0,310,0);

Three.js Perspective Camera

// PerspectiveCamera( angle, aspectRatio, near, far )
camera = new THREE.PerspectiveCamera( 30, aspectRatio, 1, 10000 );
camera.position.set( -170, 170, 40 );
cameraControls = new THREE.OrbitAndPanControls(camera, renderer.domElement);
cameraControls.target.set(0,50,0);

camera.updateProjectionMatrix();

Antialiasing

renderer = new THREE.WebGLRenderer( { antialias: true } );

Four Viewports

// don't clear when multiple viewports are drawn
renderer.autoClear = false;

// OrthographicCamera( left, right, top, bottom, near, far )
topCam = new THREE.OrthographicCamera(
    -aspectRatio*viewSize / 2, aspectRatio*viewSize / 2,
    viewSize / 2, -viewSize / 2,
    -1000, 1000 );
// set X to be the up axis
topCam.up.set( 1, 0, 0 );

render();

// top view
topCam.position.copy( cameraControls.target );
// move up a unit and look down at target
topCam.position.y +=1 ;
topCam.lookAt( cameraControls.target );

Lesson 8: Textures and Reflections

How Texturing Works

var crateTxr = THREE.ImageUtils.loadTexture( 'textures/crate.gif' );
var material = new THREE.MeshBasicMaterial( { map: crateTxr } );

UVs in three.js

var geo = new THREE.Geometry();

// generate vertices
geo.vertices.push( new THREE.Vector3( 0.0, 0.0, 0.0 ) );
geo.vertices.push( new THREE.Vector3( 4.0, 0.0, 0.0 ) );
geo.vertices.push( new THREE.Vector3( 4.0, 4.0, 0.0 ) );

var uvs = [];
uvs.push( new THREE.Vector2( 0.0, 0.0 ) );
uvs.push( new THREE.Vector2( 1.0, 0.0 ) );
uvs.push( new THREE.Vector2( 1.0, 1.0 ) );

// generate faces
geo.faces.push( new THREE.Face3( 0, 1, 2 ) );
geo.faceVertexUvs[ 0 ].push( [ uvs[0], uvs[1], uvs[2] ] );
geo.faces.push( new THREE.Face3( 8, 2, 6 ) );
geo.faceVertexUvs[ 0 ].push( [ uvs[8], uvs[2], uvs[6] ] );

Wrap Modes

var texture = new THREE.Texture();
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.wrapS = texture.wrapT = THREE.MirroredRepeatWrapping;
texture.wrapS = texture.wrapT = THREE.ClampToEdgeWrapping;

Texture Transform

var texture = new THREE.Texture();
texture.repeat.set( 1, 1 );
texture.offset.set( 0, 0 );

Texture Magnification

var texture = new THREE.Texture();
texture.magFilter = THREE.NearestFilter; // one "tap"
texture.magFilter = THREE.LinearFilter; // four "taps"

Sampling and Filtering

var texture = new THREE.Texture();
texture.magFilter = THREE.NearestFilter;
texture.magFilter = THREE.LinearFilter; // the norm

texture.minFilter = THREE.NearestFilter;
texture.minFilter = THREE.LinearFilter;
texture.minFilter = THREE.LinearMipMapLinearFilter; // the norm

texture.anisotropy = 1;
texture.anisotropy = renderer.getMaxAnisotropy();

Making Particles

var disk = THREE.ImageUtils.loadTexture( "textures/disc.png" );
var material = new THREE.ParticleBasicMaterial(
    { size: 35, sizeAttenuation: false, map: disk, transparent: true } );
material.color.setHSL( 0.9, 0.2, 0.6 );

var particles = new THREE.ParticleSystem( geometry, material );
particles.sortParticles = true;
scene.add( particles );

var geometry = new THREE.Geometry();
for ( var i = 0; i < 8000; i ++ ) {
    var vertex = new THREE.Vector3();
    do {
        vertex.x = 2000 * Math.random() - 1000;
        vertex.y = 2000 * Math.random() - 1000;
        vertex.z = 2000 * Math.random() - 1000;
    } while ( vertex.length() > 1000 );
    geometry.vertices.push( vertex );
}

Lesson 9: Shader Programming

Vertex Shader Example

uniform vec3 uMaterialColor;
uniform vec3 uDirLight;

varying vec3 vColor;

void main() {
    // Transform the vertex from model space to clip coordinates
    gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
    vec3 light = normalize( uDirLight );

    // Compute a diffuse color using Lambertian reflection, N * L
    float diffuse = max( dot( normal, light ), 0.0);

    vColor = uMaterialColor * diffuse;
}

Fragment Shader Example

varying vec3 vColor;

void main() {
    gl_FragColor = vec4(vColor, 1.0);
}


vec3 uSpecularColor;
float specular;
...
gl_FragColor.rgb += specular * uSpecularColor;

Cartoon Shading

float diffuse = max(
    dot( normal, light ), 0.0);

Debugging Shaders

gl_FragColor = vec4( uKd * uMaterialColor * uDirLightColor * diffuse, 1.0 );

Anisotropic Material

for ( int i = 0; i < 2; i++ ) {
   ... do things ...
}

Gamma Correction

renderer.gammaInput = true;
renderer.gammaOutput = true;

Texturing and Post-Processing

vec4 texelColor = texture2D( map, vUv );

vec4 cubeColor = textureCube( tCube,
    vec3( -vReflect.x, vReflect.yz ) );


varying vec2 vUv;

void main() {
    vUv = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}

uniform sampler2D tDiffuse;
varying vec2 vUv;

void main() {
    vec4 cTextureScreen = texture2D( tDiffuse, vUv );

    // luma, for non-gamma-corrected computations
    vec3 lumaColor = vec3(
        cTextureScreen.r * 0.3 +
        cTextureScreen.g * 0.59 +
        cTextureScreen.b * 0.11 );

    gl_FragColor.rgb = vec4( lumaColor, 1.0 );
}

Make a Moving Flashlight

if ( length( vViewPosition.xy ) > uFlashRadius ) {
    return;
}

uniform vec2 uFlashOffset;

Model Deformation

varying vec3 vNormal;
varying vec3 vViewPosition;

uniform float uSphereRadius2;

void main() {
    gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
    vNormal = normalize( normalMatrix * normal );
    vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
    vViewPosition = -mvPosition.xyz;
}

Lesson 10: Interaction and Animation

Events

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

function onDocumentMouseDown( event ) {
    even.preventDefault();

Picking

function onDocumentMouseDown( event ) {
    var mouseVector = new THREE.Vector3(
        2 * ( event.clientX / canvasWidth ) - 1,
        1 - 2 * ( event.clientY / canvasHeight ));
    var projector = new THREE.Projector();
    var raycaster = projector.pickingRay( mouseVector.clone(), camera );

// hit testing
var intersects = raycaster.intersectObjects( objects );
if ( intersects.length > 0 ) {
    intersects[ 0 ].object.material.color.setRGB(
        Math.random(), Math.random(), Math.random() );

    var sphere = new THREE.Mesh( sphereGeom, sphereMaterial );
    sphere.position = intersects[ 0 ].point;
    scene.add( sphere );
}

// various returned values:
intersects[ 0 ].object
intersects[ 0 ].face
intersects[ 0 ].faceIndex
intersects[ 0 ].distance
intersects[ 0 ].point

The Rendering Loop

renderer.render(scene, camera);

function animate() {
    window.requestAnimationFrame(animate);
    render();
}

function render() {
    var delta = clock.getDelta();
    cameraControls.update(delta);
    renderer.render(scene, camera);
}

Incremental Animation

var bodyhead = new THREE.Object3D();
bodyhead.add(body);
bodyhead.add(head);

// add field for animated part, for simplicity
bbird.animated = bodyhead;

bbird.add(support);
bbird.add(bodyhead);


var tiltDirection = 1;

function render() {
    bird.animated.rotation.z += tiltDirection * 0.5 * Math.PI/180;
    if ( bird.animated.rotation.z > 103 * Math.PI/180 ) {
        tiltDirection = -1;
        bird.animated.rotation.z = 2*(103 * Math.PI/180) - bird.animated.rotation.z;
    } else if ( bird.animated.rotation.z < -22 * Math.PI/180 ) {
        tiltDirection = 1;
        bird.animated.rotation.z = 2*(-22 * Math.PI/180) - bird.animated.rotation.z;
    }

    renderer.render(scene, camera);
}

Timed Animation

var clock = new THREE.Clock();

function render() {
    var delta = clock.getDelta();


// fixed step size:
bird.animated.rotation.z +=
    tiltDirection * 0.5 * Math.PI/180;

// clock controlled:
bird.animated.rotation.z +=
    tiltDirection * 30 * delta * Math.PI/180;


// final code:
var angle = (30 * clock.getElapsedTime()) % 250;
if ( angle < 125 ) {
    // go from -22 to 103 degrees
    bird.animated.rotation.z =
        (angle - 22) * Math.PI/180;
} else {
    // go back from 103 to -22 degrees
    bird.animated.rotation.z =
        ((250-angle) - 22) * Math.PI/180;
}