Simple yet Frequently Asked Questions on three.js (SFAQ)

As promised, here's what I learnt with my latest test with three.js :-D

How do I get smooth color transitions between the vertices of a face?

If you want to get color "interpolation" like the faces in the image... mesh subdivision

... you have to do a few things:

  1. Create a colors array, with as many entries as vertices in your mesh.
  2. Set the colors array as the vertexColors property of the geometry
  3. Using THREE.MeshBasicMaterial, set the vertexColors property to THREE.VertexColors

This would create a single-triangle mesh, with red, green and blue colors in each vertex respectively:


var vertices = [], colors = [], faces = [], geometry, material, mesh;

vertices.push( new THREE.Vertex( new THREE.Vector3(0, 0, 0) ) );
colors.push( new THREE.Color(0xFF0000) );

vertices.push( new THREE.Vertex( new THREE.Vector3(0, 1, 0) ) );
colors.push( new THREE.Color(0x00FF00) );

vertices.push( new THREE.Vertex( new THREE.Vector3(1, 1, 0) ) );
colors.push( new THREE.Color(0x0000FF) );

// 0, 1 and 2 are the indices of the vertices in the vertices array
faces.push( new THREE.Face3(0, 1, 2) );

geometry = new THREE.Geometry();
geometry.vertices = vertices;
geometry.faces = faces;
geometry.vertexColors = colors;

material = new THREE.MeshBasicMaterial({ vertexColors: THREE.VertexColors });

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

How do I change the line width of an object displayed as wireframe?

Using THREE.MeshBasicMaterial, set the value of the wireframeLinewidth property:

E.g. for a black, three units thick wireframe material:


var mat = new THREE.MeshBasicMaterial({ wireframeLinewidth: 3, color: 0x000000, wireframe: true });

How do I make an object display as double-sided?

I thought this was a property that had to be set in the material, but I was wrong. It's an Object3D property, so if you want an object to display both of its sides, you have to do:


mesh.doubleSided = true;

Why aren't the children objects hidden when the parent is invisible?

For optimisation reasons this is not automatic. So you have to manually iterate over the parent's children and set their visible property explicitly. But three.js has a utility function for traversing object hierarchies:


var visible = false;
THREE.SceneUtils.traverseHierarchy(parent, function(child) {
    child.visible = visible;
});

How do I get the camera position updated? It's not moving even if I change its position!

Ah, because you have to tell it where to lookAt. Assuming camera_x, camera_y and camera_z are numbers, and cam_target is a Vector3:


camera.position.x = camera_x;
camera.position.y = camera_y;
camera.position.z = camera_z;

camera.lookAt( cam_target );

Every time you change either the camera position or the target position (or both!) you need to call camera.lookAt or you won't get any visible result.

This seems to be a recent change in three.js. Apparently the camera was automatically updated in older revisions.

How do I get the contents of the current canvas? All I get is an empty, transparent image in Chrome!

This is an expected behaviour of the WebGL implementation. The solution is to create the WebGL context with the preserveDrawingBuffer flag. Of course, three.js already has that in mind!

So you simply have to add that parameter when initialising the renderer:


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

Once that's done you can happily extract screenshots of the current output with the usual canvas.toDataURL (although I used canvas.toBlob for directly downloading the image to the browser).

How do I modify a geometry dynamically? (from javascript, not in a vertex shader)

This is my super favourite question, so I left it for the end!

You can change the vertices position in a geometry once it's been added to the scene, but you won't notice any difference until you let three.js know that you've changed something in the object!

That's done with:


mesh.geometry.__dirtyVertices = true;

every time you've modified the geometry and need to get it updated in the screen.

It's also possible to modify other geometry properties, such as the vertex colors. If you modify the vertex colors, you then need to set the __dirtyColors property to true.

Actually, this is not the 'proper' way of doing things with WebGL. Every time a geometry is marked as 'dirty', it needs to be re-sent and re-created in the GPU, so to speak. Therefore, this flexibility comes at a cost; the larger the geometry, the slowest it'll be. I should be doing these calculations in a vertex shader, running in the GPU, but since I'm still learning I'm allowing myself this little computational luxury ;-)