Sebastian Morawietz

Software Developer

Didn't 'healthy' mean 'not being sick' once?

St_louis There's one particular behavior of my fellow bipeds that never fails to puzzle me. I'm currently on a vacation with my family and many friends in our house in southern france, close to Perpignan. Yesterday evening my mother cooked up a lovely chicken soup that all the present folks including me vociferously enjoyed. A friend added: "... and it's really healthy. Chicken soup is real medicine, you knew that?". After dinner we took a walk through the hills surrounding the village to waste some of the acquired calories. I really love the feeling of walking barefoot, so I left my shoes at home. Another friend commented this: "No shoes, eh? Really healthy for the feet!". A potential health benefit never came to my mind. Call me nuts, but I just like the way it feels.

I hear this over and over - not exclusively from friends or coworkers. Yummy asparagus? Detoxes your blood -> healthy (which is bullshit by the way). Tomato salad? Healthy! Massage? Healthy! Peppermint tea? Healthy. Lots of sex? Healthy, unless you're catholic. Even TV chefs never fail to emphasize their création du jour to not only being delicious but also supporting your bowel function because of the high concentration of blah in parsley.

Now, this post is not about confirming or refuting the question if these things and behaviors indeed have a health benefit. This category of question is awfully hard to answer and conventional wisdom notoriously fails in that area.

The interesting question is this: Why isn't great food it's own best justification? Why isn't the mere fact that something is safe to do and feels good it's own reason to do it?

Not a week goes by without some science journal reporting about a new study that debunks simplistic health claims (food x improves your heart condition, activity y can save you from back-pain/headache/cancer, etc.) or at least puts them into perspective. If you really care about not getting sick - which I originally thought the term 'healthy' is about - stick to the classics. But if you're lucky and someone serves you a surprisingly good chicken soup - do something crazy and enjoy it for it's own sake.

0 comments

Learning Clojure - Tracing some rays

This week we're going to start implementing the actual raytracer. The goal for today's session is to bring us to the point where we can render spheres after the phong reflection model.

Raytracing illustration

Some Raytracing Basics

Alright. This is how the most naive raytracer works: All you need is an eye-point in space, objects (in our case a sphere), an image plane and one or more light sources.

Originating from the eye point we're going to shoot a ray through each of the pixels in the image and see if it hits the sphere - or to put it in math-lingo:

Given a ray consisting of an eye point e and a direction vector d, we're looking for a scalar value t so that the distance of the point e+(d*t) to the center of the sphere c is equal to its radius r.
All the points on the ray are described by the line equation ||x-c||^2=r^2. The points on the sphere's surface are described by the sphere equation . To get the points that the surface of the sphere and the ray have in common, we insert the first into the second equation: . For simplified reading we declare and resolve the equation to t:
. Note that the square root is not defined for negative values. If the part under the square root is less than zero, the ray doesn't intersect the sphere.

So what we need first is code that lets us perform operations on vectors.

vectr.clj
(ns vectr)

(defstruct vectr :x :y :z)

(defn make-vectr
  "Creates a new vector out of its  x, y and z coordinate"
  [x y z]
  (struct vectr (float x) (float y) (float z)) )

(defn vectr-add
  "Adds two vectors"
  [a b]
  (make-vectr (+ (:x a) (:x b))
              (+ (:y a) (:y b))
              (+ (:z a) (:z b))))

(defn vectr-subtract
  "Subtracts the second vector off the first"
  [a b]
  (make-vectr (- (:x a) (:x b))
              (- (:y a) (:y b)) 
              (- (:z a) (:z b))))

(defn vectr-dot
  "Computes the dot product of two vectors"
  [a b]
  (+ (* (:x a) (:x b))
     (* (:y a) (:y b))
     (* (:z a) (:z b))))

(defn vectr-scale
  "Scales the a vector"
  [vectr scalar]
  (make-vectr (* scalar (:x vectr))
              (* scalar (:y vectr))
              (* scalar (:z vectr))))

(defn vectr-length-square
  "Computes the square of the vectors length"
  [vectr]
  (+ (* (:x vectr) (:x vectr))
     (* (:y vectr) (:y vectr))
     (* (:z vectr) (:z vectr))))

(defn vectr-length
  "Computes the vectors length"
  [vectr]
  (Math/sqrt (vectr-length-square vectr)))

(defn vectr-normalize
  "Scales the vector, so that its length is 1"
  [vectr]
  (vectr-scale vectr (/ 1 (vectr-length vectr))))

(defn vectr-cross
  "Computes the cross product of two vectors"
  [a b]
  (make-vectr (- (* (:y a) (:z b))
                 (* (:z a) (:y b)))
              (- (* (:z a) (:x b))
                 (* (:x a) (:z b)))
              (- (* (:x a) (:y b))
                 (* (:y a) (:x b)))))

Now we can construct a ray ...

ray.clj
(ns ray
    (:use vectr))

(defstruct ray :o :d)

(defn make-ray
  [from to]
  (struct ray from (vectr-normalize (vectr-subtract to from))))

(defn ray-point-at
  [ray t]
  (vectr-add (:o ray) (vectr-scale (:d ray) t)))

.. and a sphere.

sphere.clj
(ns sphere
    (:use vectr))

(defstruct sphere :c :r)

(defn make-sphere
  "Creates a sphere out of its center and radius"
  [center radius] 
  (struct sphere center (float radius)))

(defn sphere-intersect
  "Tests whether a ray intersects a sphere.
   Returns the intersection points or nil"
  [sphere ray]
  (let [v (vectr-subtract (:o ray) (:c sphere))
        v-dot-d (vectr-dot v (:d ray))
        q (- (vectr-dot v v) 
             (Math/pow (:r sphere) 2.0))
        sub-sqrt (- (* v-dot-d v-dot-d) q)]
    (if (> sub-sqrt 0.0) 
      (let [sqrt (Math/sqrt sub-sqrt)] 
        [(- (* v-dot-d -1) sqrt)
         (+ (* v-dot-d -1) sqrt)])
      nil )))

We can now use these structures to replace our stub code in cray.clj to perform a real intersection test between a ray and a sphere.

cray.clj
(let [img    (make-image 400 400)
      eye    (make-vectr 200 200 -500  )
      sphere (make-sphere (make-vectr 200 200 300) 100)]
  (image-every-pixel 
   img
   (fn [img x y w h]
       (let [pixel (make-vectr x (- h 1 y) 0 )
             ray (make-ray eye pixel)]
         (image-set-pixel!
          img
          x y
          (if (not (nil? (sphere-intersect sphere ray)))
            blue-color
            black-color)))))

Executing this, we again get a black image with a blue circle in the middle - but this time we did it the proper way :).

cray $ clj cray.clj out.png

The Phong Reflection Model

Now, a blue circle isn't that exciting. What we really want is a nicely shaded sphere. In order to do this we need to introduce a shading model. One of the most popular ones is the Phong Reflection Model, named after Bui Tuong Phong. Although not being physically correct, it provides an acceptable tradeoff between accuratesse and algorithmic complexity.

It divides an intersection point's color into three separate parts:

  • Ambient

    This portion of the color is constant all over the object, independent of the intersection point's surface normale. The blue circle that we rendered up to now is basically correct phong shading with 100% ambient portion, no diffuse and no specular part.

  • Diffuse

    This part depends on the surface normale of the intersection point between the ray and the object. The object's color is scaled by the dot product of the reflection vector and the vector that points from the intersection point towards a light source. If these are orthogonal, the dot product is 0 and the diffuse part is black. If the vectors have the same direction, their dot product is 1 and the diffuse part is the object's color itself.

  • Specular

    The specular component is reponsible for the little highlights on shiny surfaces, such as glass or plastic. If the reflection vector points almost directly to a light source, a portion of the light source's color is added.

Jump to the illustration

The weight of these components can be played with to define an objects material properties. A low ambient value with medium diffuse and high specular values looks like plastic. A higher ambient value with a high diffuse and zero specular value resembles a pebble.

What computational tools do we need to proceed?

We need to be able to add and scale colors.

color.clj
(defn color-clamp
  "Makes sure that the components of the color are in legal range"
  [clr]
  (make-color 
   (max (min (:r clr) 1.0) 0.0)
   (max (min (:g clr) 1.0) 0.0)
   (max (min (:b clr) 1.0) 0.0 )))


(defn color-add
  "Adds some colors"
  [& args]
  (color-clamp
   (make-color 
    (reduce (fn [v obj] (+ (:r obj) v ) ) 0 args) 
    (reduce (fn [v obj] (+ (:g obj) v ) ) 0 args) 
    (reduce (fn [v obj] (+ (:b obj) v ) ) 0 args) ) )
  )

(defn color-scale
  "Dims a color by a scalar value. color*0==black, color*1==color"
  [clr in-coeff]
  (let [coeff (float in-coeff)]
    (make-color (* coeff (:r clr))
                (* coeff (:g clr))
                (* coeff (:b clr)) ) ) )

A structure to hold the properties of a light source (position and color)

light.clj
(ns light)

(defstruct light :pos :col)

(defn make-light
  "Creates a light source out of its position and color"
  [pos col]
  (struct light pos col))

Then we need a way to encapsulate material properties and some predefinitions for the comfort of use.

material.clj
(ns material
    (:use color))

(defstruct material :col :amb :diff :spec :phong)

(defn make-material
  [col amb diff spec phong]
  (struct material col amb diff spec phong) )

(defn material-plastic
  [col]
  (make-material col 0.2 0.8 0.8 64) )
  
(def material-red-plastic (material-plastic red-color))
(def material-green-plastic (material-plastic green-color))
(def material-blue-plastic (material-plastic blue-color))

Now we can take one of our materials and apply it to our sphere.

sphere.clj
(defstruct sphere :c :r :material)

(defn make-sphere
  "Creates a sphere out of its center, radius and material"
  [center radius material] 
  (struct sphere center (float radius) material))

Given an intersection point, we need to compute the surface normale. This is easy for a sphere. We just subtract the center of the sphere off the intersection point and normalize the resulting vector.

(defn sphere-surface-normal
  "Computes the surface-normal for a given intersection point"
  [sphere point]
  (do 
    (vectr-scale (vectr-subtract point (:c sphere)) (/ 1 (:r sphere)))))

Last but not least we need to put our puzzle together, compute the reflection vector r out or the ray's direction v and the surface normal n at the intersection point.

Once we have this, we can finally add shading to our sphere.

cray.clj
(defn phong-compose
  [point ray normal material light] 
  (let [reflection  (compute-reflection-ray ray point normal)
        light-vectr (vectr-normalize (vectr-subtract point 
                                                     (:pos light)))
        half-vectr  (vectr-normalize (vectr-add light-vectr (:d ray)))
        diffuse     (max 0.0 (vectr-dot light-vectr 
                                        (vectr-scale normal -1) ) )
        specular    (Math/pow (max 0.0 
                                   (vectr-dot half-vectr 
                                              (vectr-scale normal -1)))
                              (:phong material))
        color (:col material)]
    (color-add (color-scale color (:amb material))
               (color-scale color (* diffuse (:diff material)))
               (color-scale (:col light) (* specular 
                                            (:spec material))))))

(defn compute-color
  [sphere light ray]
  (let [intersects (sphere-intersect sphere ray)
        material (:material sphere)]
    (if (nil? intersects) 
      black-color
      (let [point (ray-point-at ray (first intersects))
            normal (sphere-surface-normal sphere point)]
        (phong-compose point ray normal material light)))))

Finally we replace the simplistic intersection test in our main loop with compute-color

cray.clj
      (let [pixel (make-vectr x (- h 1 y) 0 )
            ray (make-ray eye pixel)]
        (image-set-pixel!
         img
         x y
         (compute-color sphere light ray))))))

Lets run the raytracer again and have a look at the result (Click to enlarge).

This looks more like a sphere, doesn't it? By a slight modification of the phong-compose-function, we can make the raytracer render only one of the components of the phong model for better understanding:

+ + =

Jump to the explanation

Okay, pfeww. That's it for today. Next time we clean up the code a little. Right now, our computation model is pretty limited:

  • Our objects, lights, materials, etc. are hardcoded in the main loop. A dynamic world-object is missing
  • The compute-color-function knows only about about spheres. But all it should know about is generic objects. We need some polymorphism here.

If you wanna hack around in the sources, rather than copy and paste the code from the site you can clone my cray-repository at github

9 comments

Learning Clojure - Getting started

Without further ado, let's get something running. Some tools are assumed to be installed on your machine:

Building Clojure

Let's check out the latest version from Google code and run it

development $ svn co http://clojure.googlecode.com/svn/trunk clojure
development $ cd clojure
clojure $ ant

This builds the clojure.jar. Let's check, if everything worked fine by launching a Repl (read eval print loop).

clojure $ java -cp clojure.jar clojure.lang.Repl
Clojure 1.1.0-alpha-SNAPSHOT
user=> (println "Hello World")
Hello World
nil

Looks good. The Repl works as expected and we can check "Hello World" off our list.
We should also get the clojure-contrib package. It's stuffed with goodies and you're going to need it when you want to unit-test your code

clojure $ cd ..
development $ svn co http://clojure-contrib.googlecode.com/svn/trunk \ 
 clojure-contrib
development $ cd clojure-contrib
clojure-contrib $ ant -Dclojure.jar ../clojure/clojure.jar
clojure-contrib $ cd ../clojure

Theoretically we now got everything we need to run Clojure programs, but it's pretty clumsy to type all those classpath options java needs by hand. So let's create a clj-command to do the work for us.

clojure-contrib $ cd ../clojure
clojure $ mkdir bin
clojure $ cd bin
clojure $ touch clj
clojure $ chmod a+x clj

Open the new file clj with the text editor of your choice and enter the following

#!/bin/bash

#Don't forget to replace this with your actual path
BASE_PATH=~/development

CLOJURE_DIR=$BASE_PATH/clojure
CLOJURE_JAR=$CLOJURE_DIR/clojure.jar

CLOJURE_CONTRIB_DIR=$BASE_PATH/clojure-contrib
CLOJURE_CONTRIB_JAR=$CLOJURE_CONTRIB_DIR/clojure-contrib.jar

java -cp $CLOJURE_JAR:$CLOJURE_CONTRIB_JAR:. clojure.lang.Script $1 -- $*

Of course we want our clj command to be available everywhere, so as a last step let's open ~/.bashrc and add our newly created bin-folder to the $PATH-Variable

export PATH=$PATH:/usr/sbin:/sbin:~/development/clojure/bin

After starting a new bash session, we can issue the clj-command on any Clojure file - just like we know it from ruby or python.

Starting the Raytracer project

Okay. Time for doing what we're here for: Rendering pretty pictures! I'm going to call the raytracer cray (Clojure Raytracer).

development $ mkdir cray
development $ cd cray

First of all we need colors - and lots of 'em. We store the red, green and blue components as float values between 0.0 and 1.0.

color.clj
(ns color)

(defstruct color :r :g :b)

(defn make-color
  "Constructs a color out of its red, green and blue components"
  [r g b]
  (struct color (float r) (float g) (float b) ) )

(defn color-to-rgb
  "Converts the color into a 32-Bit integer compatible with
   java.awt.image.BufferedImage.TYPE_INT_RGB"
  [clr] 
  (+ (bit-shift-left (int (* (:r clr) 255) ) 16 ) 
     (bit-shift-left (int (* (:g clr) 255) ) 8 )
     (int (* (:b clr) 255) ) ) )

; Some predefined colors
(def black-color (make-color 0 0 0))
(def white-color (make-color 1 1 1))
(def red-color   (make-color 1 0 0))
(def green-color (make-color 0 1 0))
(def blue-color  (make-color 0 0 1))

Then we need an image structure that we can write our colors into. The process of raytracing is basically an iteration over all pixels of an image, solving a number of equations for each individual pixel with a color as the end result - so our image structure should make this easy. This is what the image-every-pixel-function is for:
It receives a function that it calls on every pixel, passing the function as parameters the image itself, the current coordinates and its width and height.

image.clj
(ns image
    (:use color))

(defstruct image :img-src)

(defn make-image
  "Constructs an image of w x h pixels"
  [w h]
  (struct image (new java.awt.image.BufferedImage w h
                     (java.awt.image.BufferedImage/TYPE_INT_RGB) ) ) )

(defn image-width
  [img]
  (.getWidth (:img-src img)) )

(defn image-height
  [img] 
  (.getHeight (:img-src img) ) )

(defn image-every-pixel
  "Iterates over every pixel in the image and calls func on it"
  [image func]
  (let [width  (image-width image)
        height (image-height image )]
    (doall (for [y (range height)]
             (doall (for [x (range width)] 
                      (func image x y width height ) ) ) ) ) ) )

(defn image-set-pixel!
  "Sets the pixel-color at position x,y"
  [image x y color]
  (doto (:img-src image) (.setRGB x y (color-to-rgb color ) ) ) )

(defn image-save
  "Saves the image to a given filepath"
  [image file-path]
  (let [file (new java.io.File file-path)]
    (javax.imageio.ImageIO/write (:img-src image) "png" file ) ) )

Well, these two structures are basically everything we need to produce images. As a last step for today, let's draw something simple.

cray.clj
(ns cray
    (:use color image))

(if (< (count *command-line-args*) 2 )
  (do
    (println "Usage:\nclj cray.clj ")
    (System/exit 0) ) )

(let [img (make-image 400 400)]
  (image-every-pixel 
   img
   (fn [img x y w h]
       (let [dx (- x (/ (image-width img) 2)) 
             dy (- y (/ (image-height img) 2))]
         (image-set-pixel!
          img
          x y
          (if (< (+ (* dx dx) (* dy dy) ) (* 150 150) )
            blue-color
            black-color ) ) ) ) )

  (image-save img (second *command-line-args* ) ) )

Okay, lets have go:

cray $ clj cray.clj out.png

blue circleThis produces a 400 by 400 pixels wide image containing a blue circle in the middle on a black background. How? We use image-every-pixel and pass it a function that paints a blue or black pixel, depending on whether the current pixel lies within a range of 150 pixels to the center of the image.

Thats it for today. We now have everything set up nicely, so next time we can do some actual raytracing. If you want to play with the sources rather than copy and paste snippets, you can check out the project from github. I'm going to update this repository every week but leave every step along the way intact as a branch.
Cheers!

3 comments

Learning Clojure - Introduction

Ever since I first saw the SICP-Lectures held by Harold Abelson and Gerald Sussman I wanted to spend some time playing with functional programming in Lisp. However - learning the syntactic and paradigmatic particularities plus the API of a new language like Common Lisp, Scheme or Emacs Lisp is a pretty high hurdle to get your weaker self around.

Fortunately there is a new star in functional programming heaven: Clojure, a lisp-dialect invented by Rich Hickey. Clojure offers some nice features that significantly lower the barrier of entry compared to other lisps.

Syntactic Sugar

It's a little less asketic in the syntactic department compared with other lisp dialects. When it comes to first class datastructures, traditional Lisps usually limit themselves to pure lists.

  (1 2 3 4 5)

In Clojure there's also syntactic support for near-constant-time-lookup vectors

  [1 2 3 4 5]

and associative arrays (hashtables).

  { :first-name "Rich" :last-name "Hickey" }

A JVM Language

Clojure runs on the Java Virtual Machine and interoperates painlessly with Java. The API provided with the language is very lean and covers little more than sequences. Using your existing Java code is not only possible, it's encouraged. To give a quick impression about the workings of Java interop, here's a little program writing a welcome message and the current system's separator into a file.

In Java
import java.io.File;
import java.io.FileOutputStream;
import java.io.StringWriter;

public class HelloWorld {
    public static void main( String[] args ) {
        try {
            FileOutputStream stream = 
                new FileOutputStream( "helloworld.txt" );
            StringWriter writer = new StringWriter();
            writer.write( "Hello World!\n");
            writer.write( "The separator on this system is: ");
            writer.write( File.separator );
            writer.write( "\n" );                
            stream.write( writer.toString().getBytes("UTF-8") );

            stream.close();
        } catch (Exception e ) {}
    }
}
In Clojure
(let [stream (new java.io.FileOutputStream "helloworld.txt")
      writer (new java.io.StringWriter)]
  (.write writer "Hello World!\n")
  (.write writer "The separator on this system is: ")
  (.write writer (java.io.File/separator) )
  (.write writer "\n")
  (.write stream (.getBytes (.toString writer) "UTF-8") )
  (.close stream) )

Immutability

Clojure's data structures are immutable. You can't just add an element to - say - a vector. You have to create a new instance that contains the element. Now, creating a full copy of a vector just to add an element is an obviously stupid idea. But since no part of the existing vector will ever change, you can just take your element plus the vector and link them together. Hickey invested a lot of effort to implement all of Clojure's own data structures in a way so that you can build larger data structures from smaller ones by linking them together without sacrificing the memory and performance footprint of their mutable cousins.
Now you might ask yourself: "Ugh... great work - but what the hassle for?".
Simple. If a container doesn't ever change, you can safely share it among threads without stepping onto the notorious concurrency landmines.

The Plan

What's left is to come up with a fun task to teach myself Clojure. Something that does heavy computation, needs to build upon existing code, can be parallelized and looks pretty - let's see. How about building a raytracer?
A raytracer is a computer program that computes an image by tracing the path of light through pixels in an image plane.

This is a pretty daunting task for a single blog post, so I'm gonna baby-step this into several parts:

  1. Getting started

    • Setting up an environment, that lets us compile and run Clojure programs
    • Implementing an image structure, that lets us write colors to pixels and save itself to a file
  2. Raytracing Basics

    • A short introduction into the math behind raytracing
    • Implementing the required computational objects
    • The phong shading model on a sphere
  3. Raytracing Basics 2

    • Shadows
    • Reflection
  4. Exploring Clojure's polymorphism by introducing some new geometric primitives

    • Planes
    • Cubes
  5. Benchmarking Clojure against some other JVM-languages by porting some key computations

    • Rhino
    • JRuby
    • Scala (maybe?)
    • pure Java

I'll post a new chapter every once in a while, so stay tuned...

60 comments