Haskell Raytracer Project - Part 3
Parts of this tutorial
- Bitmap output
- Vector handling
- Scene drawing
This is the third part of a step-by-step guide to constructing a basic ray-tracer (3d renderer) using the Haskell functional programming language.
Rendering a scene
We ought to define a data-type to represent the scene so we can pass it to our rendering function (that we're about to write).
type Scene = [Surface]
We may as well define our background colour now. I'll use white, since it fits with my website's colour scheme.
bgcolour = [255,255,255]
Next, let's make a function to convert a pixel to the ray associated with it.
rayforpixel :: Vector -> Ray rayforpixel (Vector pixel) = Ray zerovector (normalise (Vector (1.0:pixel)))
Now a function to find the intersections a ray makes with all the objects in a scene.
srintersections :: Scene -> Ray -> [(Surface, Maybe Scalar)] srintersections scene ray = [ (obj, intersect ray obj) | obj <- scene ]
And another to pick the first one.
srintersect :: Scene -> Ray -> Maybe (Surface, Scalar) srintersect scene ray = fstintersect Nothing (srintersections scene ray) where fstintersect Nothing ((s, Nothing):xs) = fstintersect Nothing xs fstintersect Nothing ((s, Just x):xs) = fstintersect (Just (s,x)) xs fstintersect m ((s, Nothing):xs) = fstintersect m xs fstintersect (Just (ms, m)) ((s, Just x):xs) | m > x = fstintersect (Just (s,x)) xs | otherwise = fstintersect (Just (ms, m)) xs fstintersect m [] = m
To detect the colour of a ray, we take the first object it intersects (if any) then use its colour.
srdetectcolour scene ray = srdetectcolour' scene ray (srintersect scene ray) srdetectcolour' :: Scene -> Ray -> Maybe (Surface, Scalar) -> Colour srdetectcolour' scene (Ray rx rv) (Just (s,d)) = surfcolour s srdetectcolour' scene r Nothing = bgcolour
Finally, let's bring it all together and make an image from the colours of the rays.
raytrace :: Scene -> Integer -> Integer -> Image raytrace scene width height = [ srdetectcolour scene (rayfor x y) | y <- [0..height - 1], x <- [0..width - 1]] where rayfor :: Integer -> Integer -> Ray rayfor x y = rayforpixel (Vector [((fromInteger x) - ((w - 1.0) / 2.0)) / (w / 2.0), (((fromInteger y) - (h - 1.0) / 2.0)) / (h / 2.0)]) w :: Scalar w = fromInteger width h :: Scalar h = fromInteger height
Download the full source code for the raytracer.
Copyright (C) 2006-8 Ryan Lothian. All rights reserved.
