Some time ago, I wrote an n-dimensional raytracer in C++. It does a fair number of things, none of them efficiently, most of the rigidly.
There are a bunch of things that I wanted to do with it for a long time, but it’s been too slow and rigid to make any of those things fun.
Enter Lisp. As soon as it made it through my skull that Lisp is actually compiled (honest-to-goodness your-CPU instructions), I wanted to rewrite the whole thing in Lisp. I have finally gotten started on doing that. And, I just made it to the point where I’m actually tracing rays. Here is a stereo pair of a three-dimensional scene:
It use’s xach‘s ZPNG library for output, my OpenMPI library for sharing work across machines, and a thin layer that I wrote on top of Portable Threads for threading within a machine.
It doesn’t yet do reflections and refractions, directional lights, or most of the shapes that my old raytracer does.
But, it’s already got multithreading, MPI, more meaningful camera parameters, and functional color characteristics.
So, here’s the source code that generated the above images. Note that the one sphere has checkboarded diffuseness and the other has gradated phong-exponent and positional coloring.
#'(lambda (&key position)
(let ((sum (reduce #'+
position
:key #'(lambda (vv)
(if (< 1.0 (mod vv 2.0)) 1 0)))))
(if (evenp sum) a b))))
(defun my-universe ()
(rt:universe (:spatial-dimensions 3
:color-dimensions 3)
(let ((look-at (rt:v 18.0 0.0 0.0))
(eye-offset (rt:v 0.0 0.25 0.0))
(aspect (rt:v 16.0 9.0))
(field-of-view 120.0)
(object-scale (rt:v 3.0 3.0 3.0))
(x-axis (rt:v 1.0 0.0 0.0))
(y-axis (rt:v 0.0 1.0 0.0))
(z-axis (rt:v 0.0 0.0 1.0))
(angle 10.0))
(rt:with-transforms (:translation (rt:v* eye-offset -1.0)
:look-at look-at)
(rt:camera :name :main-camera-l
:aspect aspect
:field-of-view field-of-view))
(rt:with-transforms (:translation (rt:v* eye-offset 1.0)
:look-at look-at)
(rt:camera :name :main-camera-r
:aspect aspect
:field-of-view field-of-view))
(rt:with-translation (rt:v 0.0 -5.0 -2.0)
(rt:light :color (rt:v 0.7 0.7 0.7)))
(rt:with-translation (rt:v -10.0 -5.0 8.0)
(rt:light :color (rt:v 0.7 0.7 1.0)))
(rt:with-transforms (:translation look-at
:scaling object-scale
:look-at (rt:v 0.0 0.0 0.0)
:translation (rt:v 0.0 0.0 -1.0)
:rotation (x-axis y-axis angle))
(rt:with-transforms (:translation (rt:v 0.0 -1.5 0.0)
:color-scaling (rt:v 0.75 0.75 0.75)
:color-rotation (y-axis z-axis angle))
(rt:with-color (rt:c (rt:v 0.2 0.8 0.2)
:diffuseness (make-checkerboard-func 0.2 0.6)
:specularity 0.4)
(rt:sphere)))
(rt:with-transforms (:translation (rt:v 2.0 2.0 1.5)
:scaling (rt:v 1.5 1.5 1.5)
:color-translation (rt:v 0.0 0.2 0.0))
(rt:with-color (rt:c #'(lambda (&key position)
(map 'vector #'abs position))
:diffuseness 0.6
:specularity 0.4
:phong-exponent #'(lambda (&key position)
(+ 10
(abs (* 100
(aref position 2)
)))))
(rt:sphere)))
(rt:with-rotation (x-axis y-axis angle)
(rt:with-translation (rt:v -15.0 0.0 0.0)
(rt:with-color (rt:c (rt:v 0.8 0.2 0.2))
(rt:halfspace :name :hspace1))))))))
#+:openmpi
(mpi:init)
(rt:with-workers (1)
(let ((uu (my-universe))
(dpd (rt:v 2.0 2.0)))
(rt:render-png :dots-per-degree dpd
:universe uu
:filename #P"output-l.png"
:camera-name :main-camera-l)
(rt:render-png :dots-per-degree dpd
:universe uu
:filename #P"output-r.png"
:camera-name :main-camera-r)))
#+:openmpi
(mpi:finalize)
And, here are the same images swapped for those of you who prefer cross-eyed stereo pairs: