InParticular – Three JS WebGL test

So I finally got around to checking out the brillaint Three.js, the 3D JavaScript Engine, by the incredible Mr Doob. It’s really easy to pick up, even for a JavaScript novice like me – and the performance (WebGL in chrome) is absolultey astounding.
Three JS has a few different renderers –

  • Canvas Renderer
  • DOM Renderer
  • SVG Renderer
  • Sound Renderer
  • WebGL Renderer

In these demos, I’ve been using the Canvas Renderer and the WebGL Renderer.

Here’s a brief wikipedia defintion of each –

The Canvas Element

The canvas element is part of HTML5 and allows for dynamic, scriptable rendering of 2D shapes and bitmap images. It is a low level, procedural model that updates a bitmap and does not have a built-in scene graph.


“WebGL is a Web-based Graphics Library. It extends the capability of the JavaScript programming language to allow it to generate interactive 3D graphics within any compatible web browser.”

Canvas is nice – but WebGL is fast. Really fast. Here’s a video of my first Three.js experiment – InParticular.

Note – The screncapture software I used caps the video at 22fps – it actually runs faster – usually at around 35 odd FPS and is much smoother than the video appears. I’ve also optimised a little since I recorded the video.

Here’s a few stills i’ve taken from the app –
View the set on Flickr

I really enjoyed using WebGL – but a major drawback is varying browser support and speed. WebGL should be supported by all the latest browsers – although for me, the only browser that ran it at a good framerate was Chrome.

Table from –

Try it out for yourself –

The first version you see in the video is a demo file included with Three.js. Not being overly familiar with JS, I used this as my starting point. I’ve put the demo up for you to see too – it’s the “Original Mr Doob demo version”.
In the demo – canvas_lines.html – white particles are placed in a 3d scene and connected by a line.

I built upon this, to set the particle positions using some basic 3d maths, adding some varibles, a GUI and some colour options.
The basic maths used for positioning the particles is based on a question from – Plotting points round a sphere

The forula given was –

x = r * cos(s) * sin(t)
y = r * sin(s) * sin(t)
z = r * cos(t)
here, s is the angle around the z-axis, and t is the height angle, measured ‘down’ from the z-axis.

I gave this a go, but I’m not great with maths. I ended up assigning a variables to the following –

  • The initial T-Angle
  • The initial S-Angle
  • A step variable by which to increase the T-Angle by for each step in the loop
  • A step variable by which to increase the S-Angle by for each step in the loop

It’s probably terrible, ActionScript style JS but here’s the loop code I used to lay out the particles –

for ( var i = 1; i < = _numBalls; i ++ ) {
	particle = new THREE.Particle( material );
	_tAngle += _tStep;
	_sAngle += _sStep;
	particle.position.x = _radius * Math.cos(_sAngle) * Math.sin(_tAngle)
	particle.position.y = _radius * Math.sin(_sAngle) * Math.sin(_tAngle)
	particle.position.z = _radius * Math.cos(_tAngle)
	particle.position.multiplyScalar( Math.random() * 10 + _radius );
	particle.scale.x = particle.scale.y = 5;

	geometry.vertices.push( new THREE.Vertex( particle.position ) );
	lGeometry.vertices.push( new THREE.Vertex( particle.position ) );


Right hand side - What's DAT

For a nice, quick interface for altering varibles and calling functions, I used the brilliant DAT.GUI.
It's a brilliant tool that will sit in with other UI frameworks I love using, such as MinimalComps (for Flash) and ControlP5 for Processing).

I also added in some keyboard shorcuts - indicated by a letter in brackets on the GUI menu.

Pro tips

  • Q decreases the radius
  • W increases the radius
  • A decreases the color variable
  • S increases the color variable


You have to redraw the scene for changed varibale to take effect.

Randomising the scene clears any current objects.

"Redrawing" draws the scene again over the top of the current scene. So you can try decreasing the radius and color values, then redrawing, to add another copy of the structure inside itself!

The canvas version offers a ghosting effect - deselect "clear canvas" and select "ghosting" to see it in action. It gives the nice smooth, blur images seen in the Flickr Set. For some reason though, it removes the particles. I'd love to get the ghosting to work in the speedy WebGL version - but that's still a work in progress.

The canvas version's image export does not include the solid black background color.

TIP TOPS - Further development links

Phew! That turned out to be a rather long post - by my standards anyway.
If you get any nice screenshots, I'd love to see them. Or if you have any requests, or optimisation suggestions - get in touch.