Prepare for ray tracing

February 9th, 2008

In previous post I already mentioned that I'm going to write in incoming semester a simple ray tracer in C++ as a "programming project" (already finished, description is here). As C++ is not mine favorite language out there I've decided to give ray tracing a try with Objective Caml. Brief illustrated history follows...

Reaching the result of the last image took me about two days. It's also my first program written entirely with Emacs, so there was a little C-M-S-whatever fighting but it was really worth learning.

First image - after almost a day of coding:
First raytrace done
15 seconds rendering time, about 500 lines of code and... well, it looks exactly as a flag of my nationality... (It's an infinite, horizontal, red plane).

The same day rendering improved a bit more:
Something is happening...
And more...

Reaching finally:

Next day work went just a little bit forward, I corrected mistakes in calculations of diffuse lightening, removed artifacts, added simple anti-aliasing, voilla:

Variation of previous picture:

At last, nearly finished. Specular, diffuse, ambient and reflected lightening in place!

Still no refraction... and no texture support. If I won't get bored too soon I guess I'll add some of this features. And hence I can create a little road map for C++ version.

Two days later...
Code rewritten, refraction seems to more/less work, simple functional textures and texture mapping is done. There are for sure minor things to correct in lightening model, and plane mapping.

Texturing:

Refraction:

Another refraction example:

Summary given for the last rendering is as follows:

(1233284 main rays) (0 reflect) (1578544 refract) (61606006 shadow rays) traced = 64417834 in 522.00 seconds

So it took 8.7 minutes to trace 64 millions rays... I guess it would at least triple with reflections.

Code under GNU GPL3 license can be seen here:
highlighted version and pure source version: raytracer.ml

It's 900 lines without functions generating scenes (and 1267 with them). Not so big.

Comment by lambda ninja

submitted on February 12th, 2008 at 21:07

Well done! ;)

Comment by Marcin

submitted on February 13th, 2008 at 17:20

Niezle Tomku :)

Comment by Jon Harrop

submitted on March 28th, 2008 at 17:09

Great program!

Only takes 335s on my dual core 4400+ AMD64. Your "collide" function is very slow though, e.g. reallocating the accumulator at every step unnecessarily. Just optimizing it a bit brings the time down to 199s on my machine:

let minimal_distance = 0.00001 in
let vx = s.center.Vect.x -. ray_start.Vect.x in
let vy = s.center.Vect.y -. ray_start.Vect.y in
let vz = s.center.Vect.z -. ray_start.Vect.z in
let dx = ray_dir.Vect.x in
let dy = ray_dir.Vect.y in
let dz = ray_dir.Vect.z in
let r = s.radius in
let v' = vx *. vx +. vy *. vy +. vz *. vz in
let d' = dx *. dx +. dy *. dy +. dz *. dz in
let a = 2.0 *. (vx *. dx +. vy *. dy +. vz *. dz) in
let delta = a *. a -. 4.0 *. d' *. (v' -. r *. r) in
if delta minimal_distance then
if second minimal_distance then second else infinity in
if t >= best_t then collision else
let opacity' = 1.0 -.
(Material.get_property
~material:(get_object_material obj)
~property:`TRANSPARENCY) in
t, sphere, opacity +. opacity'

Add a comment [+] Hide the comment form [-]

I'm a bot, please ignore this comment.

I'm not a bot. Tick this box.

This is a mail of my good friend who loves rubbish email. Send him some if you want to land on my not-so-welcome lists: John Sparrow john@thera.be john(at)thera.be