Ray tracing a torus

In this blog post I will show you how to ray trace a torus. I will assume that you already know how to ray trace simple shapes like spheres and cubes. I will also assume some basic familiarity with shading and ray tracing in general.

Obtaining torus equation

Before we start I must introduce some terminology. I will use to denote torus major radius (the distance from the center of the tube to the center of the torus), and to denote torus minor radius (the radius of the tube). Torus geometry

Let us consider torus centered at point with radiuses and . Torus can be defined as a set of points for which certain function returns zero:

Our task will be to find a suitable definition of function that properly describes torus .

We will start by looking at the intersection of torus with plane: Torus-XY plane intersection Every point on the circumference of the right circle satisfies equation:

Now imagine that we are taking some point on the circumference and we are rotating it around axis. Rotating point around Y axis This way point becomes a set of points in 3D space:

Torus can be obtained by rotating all points on the circumference of the circle. In other words points on the surface of a torus satisfy equations:

This equations can be simplified by removal of variable into:

And this is exactly what we were looking for, a suitable definition for our function . After a bit of renaming (, ) we can write our final equation:

Solving torus equation

Given ray definition:

where is the ray origin (starting point) and is a unit vector () that represents the ray direction, we will try to find all positive () solutions to the equation:

Notice that for a particular ray this equation can have 0, 1, 2, 3 or 4 solutions: Visual illustration of number of the solutions

We will start by substituting variables by point components in the formula of function :

And then we expand them to their full definition:

After long and tedious calculations and a lot of grouping and simplifications we finally get:

where

Since our equation is just a polynomial of 4th degree, we may use one of the standard algorithms to solve it. In my demo application I used algorithm from Graphic Gems book, freely available at GitHub. But you are free to use any other algorithm. In particular Numerical Recipes in C book is a good source of numerical algorithms.

TIP: Unfortunately Roots3And4.c file from Graphic Gems (called solver.js in my demo app) is sparsely documented. If you want to know how finding roots of 4th degree polynomial actually works please read section from Wikipedia about Ferrari method, but use second definition of the resolvent cubic described in this Wikipedia article. With a bit of effort you should be able to follow and understand source code of the solver then.

Practical considerations

  1. Currently we can only render tori centered at point and laying on plane. To obtain tori located at arbitrary points and/or in arbitrary positions, we must apply matrix transformations to the ray just before computing intersections with the torus surface. For example from the viewer point of view the results of the following operations are the same: translating ray by vector , translating torus by vector . In my demo app this transformation is done in RayTracer.js#rotationEnd method. For more details please see Ray Tracing from the Ground Up book.

  2. Due to limited accuracy of the floating point computations artifacts may be seen when we use huge numerical values for torus radiuses. For the best results we should keep . If you need huge tori in your scenes please use ray transformation technique described in point (1) to scale small tori as needed.

Source code

As a part of preparations to write this post I created a simple demo app that ray traces a torus: Demo application

Source code can be downloaded from this GitHub repository.

Application is written in JavaScript. To run demo app execute:

$ cd path/to/ray_tracing_torus_js/repo
$ npm install
$ bower install
$ gulp serve

npm install command may take a while to finish, so please be patient. Also notice that you have to had both bower and gulp installed on you local machine to make this work. You can install them by executing:

$ sudo npm install --global gulp-cli
$ sudo npm install --global bower

References

marcin-chwedczuk

A Programmer, A Geek, A Human