How to create a fractal torus




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);
    }
  }
}

This entry was posted in Software. Bookmark the permalink.