Tachyonic

Introduction

Tachyonic is a global illumination ray tracer that I have been working on for several years. It does not receive the same amount of love and attention as it used to. But it is still a project that is near and dear to me.

I first implemented Tachyonic as a CS 490 (Supervised Independent Research) project under the supervision of Dr. Kavita Bala when I was a junior at Cornell. I presented the results in Book 2003. The first version of Tachyonic was written entirely in C++ and STL.

Since then I have expanded Tachyonic has a rendering platform that supports multiple rendering algorithms including path tracing, bidirection ray tracing, and photon mapping. It also supports several acceleration structures including octtrees and kd-trees. The current implementation of Tachyonic is written in C# and C++.

Implementation

The photon mapping implementation of Tachyonic is based on the algorithm described in Henrik Jensen’s book, Realistic Image Synthesis with Photon Mapping. It also implements final gathering and irradiance caching as described in Per Christensen’s paper “Faster Photon Map Global Illumination.” Irradiance is precomputed and stored in a kd-tree. Whenever a final gather ray his a surface, the irradnace at that point is approximated using the precomputed values and returned. Therefore, in a depareture from traditional path tracing, it is possible to sample multiple rays over the hemiphere using importance and stratified sampling. I have found that using Photon Mapping with Final Gathering results in a much faster converage than path tracing or bidirectional light tracing. I personally could care less about the bias introduced by Photon Mapping.

There are a few things that I have changed from the vanilla photon mapping algorithm. For instance, I do not use a projection map to concentrate photons toward specular objects. Instead, I use a rejection test to fill the casutic photon map. I first cast a predetermined amount of global photons. Then, I lock the global photon map, and continually cast more photons until the casted photon map is filled. Here, I precompute the initial flux that each caustic photon must carry. The number of photons casted and stored is scene controlled via setting.

The kd-tree implements the OSAH (Ordinary Surface Area Heuristic) cost function model and recursive ray traversal algorithm outlined in the paperĀ “Heuristic Ray Shooting Algorithms.” I find this spatial data structure to be flexible and fast. It seems to be able to accomodate the widest range of scenes.

Currently I support two object primitives: triangles and spheres. The ray-triangle intersection code uses the Moller-Trumbore method without precomputed normals. However, I do precompute and store the E1 and E2 edges. I referred to the implementation given here.

The random number generator I used is based on M. Matsumoto and T. Nishimura’s article. Please refer to http://www.agner.org/random.

Rendered Images

Diffuse Cornell Box

Diffuse Cornell Box

Cornell Box with Caustics

Cornell Box with Caustics

Cornell Box with Ward Spheres

Cornell Box with Ward Spheres

Ward Spheres

Ward Spheres

Knot

Knot

M-16 Model

M-16 Model