Fractals are a wonderful part of computer graphics – with just some lines of code, you can create awesome effects.
Here’s how to create a fractal torus (i.e. a ring made up of smaller rings, recursively). Click on the image to see a live demo with WebGL.
In pseudocode:
createTorus if (recursionFinished) drawBasicShape(); else for each segment rotate by 90 degrees move to torus center rotate by one segment part createTorus with smaller size
and here’s the core part of the torus generation with WebGL/three.js:
function createTorus(radius, hoseRadius, segments, recursionDepth, matrix)
{
if (recursionDepth < 1)
{
var geometry = new THREE.TorusGeometry(radius, hoseRadius, 9, 15, 0);
var torus = new THREE.Mesh(geometry, materials[objects.length % SEGMENT_COUNT]);
geometry.applyMatrix(matrix);
sceneHolder.add(torus);
objects.push(torus);
}
else
{
for (var i = 0; i < segments; i++)
{
var localMatrix = new THREE.Matrix4();
localMatrix.copy(matrix);
//rotate by 1 nth of the torus
var angle = i / segments * 2 * Math.PI;
var rotationMatrix = new THREE.Matrix4();
rotationMatrix.setRotationZ(angle);
//move to torus center
var translationMatrix = new THREE.Matrix4();
translationMatrix.setTranslation(0.0, -radius, 0.0);
//twist be 90 degrees - the next smaller torus generation
var recursionRotation = new THREE.Matrix4();
recursionRotation.setRotationY(Math.PI / 2)
localMatrix.multiplySelf(rotationMatrix);
localMatrix.multiplySelf(translationMatrix);
localMatrix.multiplySelf(recursionRotation);
createTorus(radius / 5, hoseRadius / 5, segments, recursionDepth - 1, localMatrix);
}
}
}
and in OpenGL (a lot shorter, because the matrix operations are single function calls)
void torus(double mainRadius, double hoseRadius, int segments, int rDepth) {
int i;
GLfloat m[16];/*temporary matrix*/
if (--recDepth < 1) {
glutSolidTorus(hoseRadius*2.0, mainRadius, segments, segments);
} else {/*recurse further*/
for (i=0; i < segments; i++) {
glGetFloatv(GL_MODELVIEW_MATRIX, m);
glRotatef(double(i)*360/double(segments), 0.0, 0.0, 1.0);
glTranslatef(0.0, -mainRadius, 0.0);
glRotatef(90.0, 0.0, 1.0, 0.0);
torus(mainRadius/5.0, hoseRadius/5.0, segments, recDepth);
glLoadMatrixf(m);
}
}
}