This time we will have a look at two types that will help us on your way. First I will show you how I implemented a ray-type for representing the most important aspect of ray-tracing itself and then I will show you the viewport-type I use to generate all starting-rays for the image we want to generate.

## The ray-type

My thinking behind a “ray” is very simple. It’s just a line starting at some point together with a direction. The start-point will be just that – a point in 3D space and the direction should be a direction-vector in 3D space having unit-length (length 1). So the type will imply this constraint (direction have length 1). For this I choose to give two static members for construction of the ray. One for point+direction and a one for constructing a ray from a start-point and another point lying on the ray – the second will make certain that the unit-length constraint is met, the first one will NOT check (for performance-reasons):

type Ray = struct val Start : Point val Direction : Direction new (s, d) = { Start = s; Direction = d } static member Create (start, direction) = new Ray (start, direction) static member FromPoints (start, pointOnRay) = let direction = Vector.Normalize (pointOnRay - start) Ray.Create (start, direction) end

## The view-port type

This one will be responsible for creating the a raster of points on the viewport and ultimately a ray for each of these raster points pointing from the eye-point in the world-space to the raster-point on the viewport – have a look at this diagram for details:

type RayRaster = Ray[,] type ViewPort(eye : Point, center : Point, dirUp : Direction, dirRight : Direction, height : float, width : float) = let createRaster (resX : int, resY : int) : Point[,] = let dX = width / (float resX) let dY = height / (float resY) let start = center - ((width-dX)/2.0)*dirRight - ((height-dY)/2.0)*dirUp Array2D.init resX resY (fun x y -> start + (float x*dX)*dirRight + (float y*dY)*dirUp) let createRay (viewPortPoint : Point) = Ray.FromPoints (eye, viewPortPoint) member vp.CreateRaster (resX, resY) : RayRaster = createRaster(resX, resY) |> Array2D.map createRay

I think the code is straight forward – resX/resY stands for Resolution in X and Y direction (on the viewport – so in the right/up-direction the type get’s in it’s constructor). In the diagram up points just up (vertical) and right just right (horizontal).

That’s it for now – next time we will talk about hitting spheres …

Pingback: FunTracer: Intro and let there be light | getting #er()