packages feed

HRay-1.2.0: HRayEngine.lhs

	module HRayEngine, which contains the functions needed to raytrace a scene
	intended for usage with the other modules in the HRay package

   	author: Kenneth Hoste, 2004-2005
	part of a masters thesis at the University of Ghent, Belgium

	==========================================================================

> module HRayEngine (Resolution, Color, Diff(Solid,Perlin), Texture(Texture), TexturedObject, 
>		     Light(AmbientLight,PointLight), Scene(Scene), Camera(Camera), rayTrace) where

> import Maybe
> import HRayMath


        representation of a color

> type Color = (Double,Double,Double)

        representation of the diffuse component of a material: solid or perlin noise

> data Diff = Solid Color |
>             Perlin (Point3D -> Color)

        representation of a material

> data Texture = Texture Diff Double Int Double Double

        representation of an object

> type TexturedObject = (Object,Texture)

	representation of a light intensity

> type Intensity = (Double,Double,Double)

        representation of a light source

> data Light = PointLight Point3D Intensity
>            | AmbientLight Intensity

        representation of a camera

> data Camera = Camera Point3D Dimension

	representation of a scene

> data Scene = Scene Camera Color [TexturedObject] [Light]

        representation of an intersection

> data Intersection = Intersection Double Ray TexturedObject

        representation of an image

> type Image = Point2D -> Color

	determines the distance between the start point of the ray and the intersection point

> intDist :: (Maybe Intersection) -> Double
> intDist Nothing = 0.0
> intDist (Just (Intersection d _ _)) = d

	determines the texture of the intersected object

> intText :: (Maybe Intersection) -> Texture
> intText Nothing = Texture (Solid (0.0,0.0,0.0)) 0.0 0 0.0 0.0
> intText (Just (Intersection _ _ (_,t))) = t

	determines the color at the intersection point
	- if the texture has a solid color, this color is returned
	- if the texture has a noise function to determine the color, 
	  this function is used to determine the color for the given point

> colorAt :: (Maybe Intersection) -> Color
> colorAt Nothing   = (0.0,0.0,0.0)
> colorAt (Just (Intersection _ _ (_,Texture (Solid color) _ _ _ _) )) = color
> colorAt i@(Just (Intersection _ _ (_,Texture (Perlin f) _ _ _ _) )) = f (intPt i)

	determines the normal at the intersection point

> normalAt :: (Maybe Intersection) -> Vector
> normalAt Nothing   = (0.0,0.0,0.0)
> normalAt i@(Just (Intersection _ _ (o,_) )) = normal (intPt i) o

	determines the intersection point of the given intersection

> intPt :: (Maybe Intersection) -> Point3D
> intPt Nothing = (0.0,0.0,0.0)
> intPt (Just (Intersection d (Ray start dir) _)) = start <+> (dir *> d)


	determines the first positive value in a list

> fstPos :: [Double] -> Double
> fstPos   []   = 0.0
> fstPos (l:ls) = if l > 10**(-6) then l else fstPos ls

        determines the _closest_ intersection of a ray and an object, with a distance bigger then the given distance
        if no intersection (with a distance higher then the given distance) is found, the given intersection is returned,
        else, the new intersection is created and returned
        ! ! ! the list returned by intRayWith should be sorted ! ! !

> closestInt :: Ray -> (Maybe Intersection) -> TexturedObject -> (Maybe Intersection)

> closestInt r i (o,m) = if d > 10**(-6) && ((isNothing i) || d < (intDist i)) 
>				then Just (Intersection d r (o,m))
>				else i
>    where
>	d = fstPos (intRayWith r o)

	determines the closest intersection of aray and a list of objects

> intersect :: Ray -> [TexturedObject] -> (Maybe Intersection)
> intersect r o = foldl (closestInt r) Nothing o

	determines the diffuse color at the intersection point

> diff :: (Maybe Intersection) -> Light -> Color
> diff _ (AmbientLight _)     = (0.0,0.0,0.0)
> diff i (PointLight pos int) = (int *> ((mkNormVect (intPt i) pos) *. (normalAt i))) <*> (colorAt i)

	determines the specular color at the intersection point

> spec :: (Maybe Intersection) -> Vector -> Light -> Color
> spec _ _ (AmbientLight _)     = (0.0,0.0,0.0)
> spec i d (PointLight pos int) = int *> (reflCoef * ( ((normalAt i) *. h)**(fromIntegral specCoef) ))
>   where
>       h  				  = norm ((d *> (-1)) <+> (mkNormVect (intPt i) pos))
>	(Texture _ reflCoef specCoef _ _) = intText i  

        shades the intersection point 

> shadePt :: Intersection -> Vector -> [TexturedObject] -> Light -> Color 

		if there is an ambient light in the scene (always in front of the list), then use it 

> shadePt i d o (AmbientLight int) = int

		illuminate an intersection point with a point light

> shadePt i d o l@(PointLight pos int)
>	-- distance between light point and an object is smaller than distance between light point and shaded intersection 
>       -- => shadow -> no color factor added by this light source 
>	| s         = (0.0,0.0,0.0)
>	-- no shadow -> color factor added by this light source 
>	| otherwise = (diff (Just i) l) <+> (spec (Just i) d l)
>	where 
>		s     = not (isNothing i_s) && (intDist i_s) <= dist (intPt (Just i)) pos 
>           	i_s = intersect (mkRay (intPt (Just i)) pos) o 

        calculates the reflected component at the given intersection point 

> reflectPt :: Int -> Intersection -> Vector -> [TexturedObject] -> [Light] -> Color 
> reflectPt depth i d = colorPt depth (Ray (intPt (Just i)) (reflectDir d (normalAt (Just i)))) (0.0,0.0,0.0) 
 
        calculates the refracted component at the given intersection point

> refractPt :: Int -> Intersection -> Vector -> Color -> [TexturedObject] -> [Light] -> Color  
> refractPt depth i d b = if refractedDir == (0.0,0.0,0.0) then (\x y -> (0.0,0.0,0.0))  
>							   else colorPt depth (Ray (intPt (Just i)) refractedDir) (b *> refrCoef) 
>   where 
>	refractedDir                       = refractDir d (normalAt (Just i)) refrIndex  
>	(Texture _ _ _ refrCoef refrIndex) = intText (Just i)  


        determines the color at the given point of the view plane

> colorPt :: Int -> Ray -> Color -> [TexturedObject] -> [Light] -> Color

		when the maximum depth is reached, recursion stops

> colorPt (-1) _ _ _ _ = (0.0, 0.0, 0.0) 

> colorPt d r@(Ray _ dir) b o l = if (isNothing i) then b else clip $ shadeColor <+> reflectColor <+> refractColor
>   where 
>       shadeColor   = foldl (<+>) (0.0,0.0,0.0) (map (shadePt (fromJust i) dir o) l)
>       reflectColor = if (reflCoef == 0.0) then (0.0, 0.0, 0.0) 
>                                          else (reflectPt (d-1) (fromJust i) dir o l) *> reflCoef 
>       refractColor = if (refrCoef == 0.0) then (0.0, 0.0, 0.0) 
>                                          else (refractPt (d-1) (fromJust i) dir b o l) *> refrCoef 
>       i = intersect r o 
>	(Texture _ reflCoef _ refrCoef _) = intText i 

	determines the color of one ray through a given point 

> rayTracePt :: Int -> Scene -> Point3D -> Color 
> rayTracePt d (Scene (Camera eye _) b o l) p = colorPt d (Ray p (mkNormVect eye p)) b o l 

        raytraces the scene, and returns a list of colors representing the image

> rayTrace :: Int -> Resolution -> Scene -> Image 
> rayTrace d r s@(Scene (Camera _ dim) _ _ _) = (rayTracePt d s) . (mapToWin r dim)