- Monte-carlo path-tracing transport
- Emitter sampling
- Progressive refinement
- RGB light
- Diffuse materials
- Triangle modelling primitives
- Octree spatial index
- Pin-hole ‘lens’
- Ward linear tone-mapping
Together, this set of techniques is part of the Global illumination rendering algorithm. This considers not only a single ray (see my previous attempt) but reflections and emissions from all objects in the scene.
Over the next few weeks, I'll attempt to implement this in Clojure.
So for part 1, we'll look at reading in a scene file and converting it into a Clojure representation. The format for a model is simple. There's an example here.
Clojure really simplifies things because of the
readfunction and because it's homioiconic (a Clojure function is a Clojure data structure).
The main gotcha I found was that
read, by default, throws an exception when it reaches the end of the file. This made things slightly more complicated than I needed. Further investigation shows that
readtakes some optional parameters allowing you to control how EOF should be treated.
For now, I've just read the data in raw form. I've no idea if this will be a suitable data structure for actually doing anything with, but we'll see how this evolves...
(defmacro safe-read [x]
`(read ~x false nil))
(let [geom [(safe-read r) (safe-read r) (safe-read r)] refl (safe-read r) emit (safe-read r)]
(if (first geom)
(recur (cons (struct triangle geom refl emit) triangles))
(with-open [r (PushbackReader. (reader f))]
(.skip r (count "#MiniLight"))
(read r) ;iterations
(read r) ;width
(read r) ;height
(read r) ;eye-position
(read r) ;look-direction
(read r) ;view-angle
(read r) ;sky-emission
(read r) ;ground-reflection
(read-triangles r)))) ;triangles