There’s no question about it: WebGL is the latest, greatest, and coolest thing a geek can be doing on the web right now.
Straight away I realize it’s not good enough.
The diagonal lines are a result of polygons being broken into triangles, a necessary step for 3D rendering. Because this sphere was constructed from squares there are two triangles for every plane but that’s not right; An ideal sphere has an infinite number of planes, a good sphere should try to maximise it’s planes for the resources used. The basic sphere is wasting triangles (the key resource of a graphics card) to draw half as many planes as it could – which means half the quality.
The poles have the same number of planes as around the equator but the circle around the pole is smaller than the equator so is getting an unfair concentration of detail. The top and bottom appear smoother than the middle. A real sphere is isotropic – it appears the same when viewed from any direction. The triangles should be spread out evenly and roughly the same size.
Our eyes are good at picking out straight edges. When shaded the basic sphere strongly shows horizontal and vertical edges. If the edges were more jumbled up it would look more natural.
This isn’t a new problem, and the solution isn’t new either. Typically the programmer just increases the number of polygons used until you cannot notice the edges but that increases the detail in the already-over-detailed pole areas. A better solution is to use a geodesic sphere instead, three.js even supplies an
IcosahedronGeometry class which has it’s sides subdivided until it appears round. It works well, here is one for comparison:
This geodesic sphere answers our major complaints; Triangles are spread evenly and no two triangles share the same plane. More planes mean more edges and they are shorter, they tend to lie in three directions rather than two, making it look less regular. Unfortunately the author of
IcosaherdonGeometrynotes that texturing is difficult and simply leaves it unsupported. It would help if there was one straight line running between any two opposing points but there isn’t, if anything the geometry is too good for practical use.
Back to the drawing board
A geodesic sphere is typically made from an icosahedron that has each triangle split into four sub-triangles, which then have their points projected out to the surface of the sphere, the process is then repeated until you have a reasonable approximation of a sphere. However, any platonic solidcan be used as a seed and after a bit of trial and error I found starting from an octahedron to have several benefits.
To begin with the calculations are simpler. To make an icosahedron requires 12 vertices (using the bestest number in the world, φ) whereas an octahedron only needs 6, all conveniently lying on the major axes. Obviously there are only 8 initial faces rather than 20. Unlike
IcosahedronGeometrythere are a choice of straight lines running between the six poles, they are at right angles to each other which is makes texture alignment very easy. Like all geodesic spheres every face is a single triangle, maximizing the smoothness of curves. Additionally the edges lie in four directions (horizontal, vertical and both diagonals) which to the eye is less regular than the other shapes and makes it harder to see the edges.
Look at a basic sphere (left) next to an octahedron-based geodesic sphere (right) and make your own comparison between the two. Which is better? I was careful to use the same lighting and material for both surfaces. And the two objects have the same number of triangles so should perform equally well when rendering.
When it came to texturing there was one tricky part I had not anticipated. Texture coordinates for a sphere are based on the inclination and azimuth (more commonly known as longitude and latitude). At the poles where inclination is ±180°, azimuth is unpredictable, it cannot be worked out from just the vertex. In this special case I assume the azimuth is the same as the centroid of that face and in practice that proves to be fairly accurate. Play spot the difference with this alignment texture:
¹The tutorial mentioned above is by Paul Lewis who runs an excellent site featuring many three.js experiments. You should look at his lab.