James Green

Posted on

# Raytracing β Part I: Overview

π TL;DR - Haskell lends itself nicely to basic raytracing, simple code (not mine) creates incredible first results.

## Table of Contents

Β 1. Intro
Β 2. Vectors
Β 3. Geometric functions
Β 4. Conclusion

## Intro

Hello! This is my first post, and realistically, my first real attempt at blogging. Without further ado, we'll jump straight into the content.

Weβre looking at functional programming. Specifically, weβre going to look at implementing some basic raytracing in Haskell. Firstly, the code for this project is all on my GitHub. Hopefully, at some point moving forward Iβll have a website set-up to show off the results.

There are a couple of basic resources Iβm using to have a first stab at the project:

• Htrace is the initial work weβll be analysing and expanding upon.
• This incredible video explaining how modern CGI and ray tracing works. The implementation of any of this will be post the initial analysis.

## Vectors

Let's jump into some code.

``````type Vector3 = (Float, Float, Float)
``````

Here we have a definition of a vector, as you can see the syntax here is pretty self-explanatory. A 3-dimensional vector is an ordered 3-tuple. Next let's talk about some operations you'll be familiar with.

``````add :: Vector3 -> Vector3 -> Vector3
add (x,y,z) (a,b,c) = (a+x, b+y, c+z)

sub :: Vector3 -> Vector3 -> Vector3
sub (a,b,c) (x,y,z) = (a-x, b-y, c-z)

squared_mag :: Vector3 -> Float
squared_mag (x,y,z) = (x*x + y*y + z*z)

mag :: Vector3 -> Float
mag v = sqrt (squared_mag v)
``````

All of the above are pretty basic mathematically, and similarly the code is faily trivial. We could alternativly, and worsely (though pointfreely), define:

``````squared_mag :: Vector3 -> Float
squared_mag = sum map (**2)
``````

But then we'd have to worry about defining `map` and `sum` for `Vector3` and suddenly I've lost interest.

``````scalarmult :: Vector3 -> Float -> Vector3
scalarmult (x,y,z) c = (x*c, y*c, z*c)

dot :: Vector3 -> Vector3 -> Float
dot (x,y,z) (a,b,c) = x*a + b*y + c*z

cross :: Vector3 -> Vector3 -> Vector3
cross (a,b,c) (x,y,z) = (b*z + c*y, -(a*z + c*x), a*y + b*x)

normalize :: Vector3 -> Vector3
normalize v
| (mag v) /= 0 = scalarmult v (1 / mag v)
| otherwise    = (0,0,0)

neg :: Vector3 -> Vector3
neg (x,y,z) = (-x,-y,-z)
``````

These again are all pretty standard, the only change I'd make is to make `scalarmult` left multiplication:

``````scalarmult :: Float -> Vector3 -> Vector3
scalarmult c (x,y,z) = (c*x, c*y, c*z)

neg :: Vector3 -> Vector3
neg = scalarmult (-1)
``````

## Geometric functions

Now we can move into some more geometric mathematics, we define some more datatypes.

``````type Point3 = Vector3
type Direction3 = Vector3
type Time = Float
type Ray = (Point3, Direction3) -- base and direction

position_at_time :: Ray -> Time -> Point3
position_at_time (base, dir) t = base `add` (scalarmult dir t)
``````

Note the `position_at_time` function assumes no acceleration (allowed as we're working with light). We'll omit code for the next couple of definitions for brevity, we define a quadratic solver and `xor`. These are the standard definition.

## Conclusion

The next steps are to start looking into colours, I have something substantially different intended for this. So we'll cut this post here for the time being.