Guest User

Untitled

a guest
Dec 10th, 2018
123
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -- ghc -O2 -fllvm -funbox-strict-fields -with-rtsopts=-N4 -threaded -o ray ray.hs
  2.  
  3. import Data.Maybe
  4. import Control.Parallel
  5. import Control.Parallel.Strategies
  6.  
  7. ---- precise comparison of Doubles
  8.  
  9. eps = 1e-8
  10. x !>  y = x     > y+eps
  11. x !<  y = x+eps < y
  12. x !>= y = x+eps > y
  13. x !<= y = x     < y+eps
  14. x !== y = x !<= y && x !>= y
  15.  
  16. ---- color (rgb values are between 0 and 1)
  17.  
  18. data Color = Color !Double !Double !Double
  19.  
  20. instance Show Color where
  21.   show (Color r g b) = format r ++ " " ++ format g ++ " " ++ format b
  22.     where format = show . round . (*255) . min 1
  23.  
  24. magnify (Color x y z)  k            = Color (k*x) (k*y) (k*z)
  25. apply   (Color x y z) (Color a b c) = Color (x*a) (y*b) (z*c)
  26. combine (Color x y z) (Color a b c) = Color (x+a) (y+b) (z+c)
  27. combineAll = foldr1 combine
  28.  
  29. ---- 3d vector (can represent a point)
  30.  
  31. data Vector = Vector !Double !Double !Double
  32.             deriving Show
  33.  
  34. (Vector x y z) ^* k = Vector (x*k) (y*k) (z*k)
  35. (Vector x y z) ^/ k = Vector (x/k) (y/k) (z/k)
  36.  
  37. (Vector x y z) ^+^ (Vector a b c) = Vector (x+a) (y+b) (z+c)
  38. (Vector x y z) ^-^ (Vector a b c) = Vector (x-a) (y-b) (z-c)
  39. (Vector x y z) ^*^ (Vector a b c) = Vector (y*c-b*z) (z*a-c*x) (x*b-a*y)
  40. (Vector x y z) ^.^ (Vector a b c) = x*a + y*b + z*c
  41. p              ^|^ q              = sqrt $ (p^-^q) ^.^ (p^-^q)
  42.  
  43. neg (Vector x y z) = Vector (-x) (-y) (-z)
  44. norm v = sqrt $ v ^.^ v
  45. normalize v = v ^/ norm v
  46.  
  47. ---- ray directed from starting point
  48.  
  49. data Ray = Ray { rayFrom :: Vector
  50.                , rayDir  :: Vector
  51.                } deriving Show
  52.  
  53. rayPoints :: Vector -> Vector -> Ray
  54. rayPoints a b = Ray a (normalize $ b^-^a)
  55.  
  56. ---- light source
  57.  
  58. data Light = Light { lightPos   :: Vector
  59.                    , lightColor :: Color
  60.                    } deriving Show
  61.  
  62. ---- objects in scenes
  63.  
  64. data Object = Sphere { sphCenter  :: Vector
  65.                      , sphRadius  :: Double
  66.                      , sphDiffuse :: Color
  67.                      , sphReflect :: Color
  68.                      , sphRough   :: Double
  69.                      } deriving Show
  70.  
  71. ---- intersection of a ray and an object
  72.  
  73. data Inter = Inter { interPoint   :: Vector
  74.                    , interDist    :: Double
  75.                    , interOuter   :: Bool
  76.                    , interNormal  :: Vector
  77.                    , interDiffuse :: Color
  78.                    , interReflect :: Color
  79.                    , interRough   :: Double
  80.                    } deriving Show
  81.  
  82. findInter :: Ray -> Object -> Maybe Inter
  83. findInter (Ray st dir) (Sphere c r diffuse reflect rough)
  84.   | d0 !>= r  = Nothing
  85.   | t2 !<= 0  = Nothing
  86.   | otherwise = Just $ Inter point dist outer normal diffuse reflect rough
  87.   where
  88.     t0     = (dir ^.^ (c^-^st)) / (dir ^.^ dir)
  89.     p0     = st ^+^ (dir^*t0)
  90.     d0     = p0 ^|^ c
  91.     delta  = sqrt $ r^2 - d0^2
  92.     t1     = t0 - delta
  93.     t2     = t0 + delta
  94.     outer  = t1 !> 0
  95.     time   = if outer then t1 else t2
  96.     point  = st ^+^ (dir^*time)
  97.     dist   = point ^|^ st
  98.     normal = normalize $ point ^-^ c
  99.  
  100. test 0 r = return ()
  101. test n r = do
  102.   let (Just x) = obstacle r
  103.   print $ interPoint x
  104.   test (n-1) (Ray (interPoint x) (rayDir r))
  105.  
  106. ---- light effects
  107.  
  108. ambiental :: Color
  109. ambiental = Color 0.06 0.06 0.06
  110.  
  111. diffusion :: Light -> Inter -> Color
  112. diffusion l i = lightColor l `apply` interDiffuse i `magnify` cosA `magnify` 0.5
  113.   where dirL = normalize $ lightPos l ^-^ interPoint i
  114.         cosA = dirL ^.^ interNormal i
  115.  
  116. reflection :: Ray -> Light -> Inter -> Color
  117. reflection r l i = lightColor l `apply` interReflect i `magnify` powCosA
  118.   where normal  = interNormal i
  119.         dirR    = rayDir r
  120.         dirL    = normalize $ lightPos l ^-^ interPoint i
  121.         cosA    = normal ^* (normal ^.^ dirL) ^* 2 ^-^ dirL ^.^ neg dirR
  122.         powCosA = cosA `max` 0 ** interRough i
  123.  
  124. refraction :: Int -> Ray -> Inter -> Color
  125. refraction iter r i
  126.   = traceRay (iter-1) rayO `magnify` 0.85 `combine`
  127.     traceRay (iter-1) rayI `magnify` 0.85
  128.   where
  129.     pt       = interPoint i
  130.     normal   = interNormal i
  131.     dirR     = rayDir r
  132.     outer    = interOuter i
  133.     n1       = if outer then 1.0 else 1.5
  134.     n2       = if outer then 1.5 else 1.0
  135.     normal'  = if outer then normal else neg normal
  136.    alpha    = acos $ neg dirR ^.^ normal'
  137.     arm      = normalize $ normal' ^* cos alpha ^+^ dirR
  138.    sinB     = sin alpha * (n1/n2)
  139.    validB   = sinB > -1 && sinB < 1
  140.    beta     = if validB then asin sinB else alpha
  141.    normal'' = if validB then normal' else neg normal'
  142.    
  143.    dirO     = normalize $ normal ^* (normal ^.^ neg dirR) ^* 2 ^+^ dirR
  144.    rayO     = Ray pt dirO
  145.    dirI     = normalize $ arm ^* tan beta ^-^ normal''
  146.    rayI     = Ray pt dirI
  147.  
  148. dropSingle :: Ray -> Light -> Inter -> Color
  149. dropSingle r l i | isNothing liM               = Color 0 0 0
  150.                 | interDist li !< (posL^|^pt) = Color 0 0 0
  151.                 | otherwise                   = result
  152.  where posL   = lightPos l
  153.        pt     = interPoint i
  154.        liM    = obstacle $ rayPoints posL pt
  155.        li     = fromJust liM
  156.        result = diffusion l i `combine` reflection r l i
  157.  
  158. dropLight :: Int -> Ray -> Inter -> Color
  159. dropLight iter r i = combineAll [dropSingle r l i | l <- lights]
  160.                     `combine` refraction iter r i
  161.                     `combine` ambiental
  162.  
  163. ---- rendering
  164.    
  165. obstacle :: Ray -> Maybe Inter
  166. obstacle ray = foldl (\a -> closer a . findInter ray) Nothing objs
  167.  where closer Nothing  b        = b
  168.        closer a        Nothing  = a
  169.        closer (Just x) (Just y) | interDist x < interDist y = Just x
  170.                                 | otherwise                 = Just y
  171.  
  172. traceRay :: Int -> Ray -> Color
  173. traceRay 0    ray                  = Color 0 0 0
  174. traceRay iter ray | isNothing obst = Color 0 0 0
  175.                  | otherwise      = dropLight iter ray i
  176.  where obst = obstacle ray
  177.        i    = fromJust obst
  178.  
  179. getPixel :: Int -> Int -> Int -> Int -> Color
  180. getPixel w h x y = traceRay 7 $ rayPoints eye pt
  181.  where w' = fromIntegral w
  182.         h' = fromIntegral h
  183.        x' = fromIntegral x
  184.         y' = fromIntegral y
  185.        pt = corner ^+^ (xAxis ^* (x' / (w'-1) * viewW))
  186.                    ^-^ (yAxis ^* (y' / (h'-1) * viewH))
  187.  
  188. render :: Int -> Int -> [Color]
  189. render w h = runEval $ parBuffer 10000 rseq im
  190.  where im = [getPixel w h x y | y <- [0..h-1], x <- [0..w-1]]
  191.  
  192. ---- writing to file
  193.  
  194. formatPGM :: Int -> Int -> String
  195. formatPGM w h = format $ render w h
  196.  where format ps = "P3\n" ++ show w ++ " " ++ show h ++ "\n" ++ "255\n" ++
  197.                   concatMap (\c -> show c ++ "\n") ps
  198.  
  199. writePGM :: Int -> Int -> IO ()
  200. writePGM w h = writeFile file $ formatPGM w h
  201.  
  202. main = writePGM 700 700
  203.  
  204. ---- constants
  205.  
  206. file    = "scene.ppm"
  207.  
  208. viewH   = 20
  209. viewW   = 20
  210. eye     = Vector (-20) 10 0
  211. view    = Vector  0 0  0
  212. viewUp  = Vector  0 0 10
  213. viewDir = normalize $ view ^-^ eye
  214. xAxis   = normalize $ viewDir ^*^ yAxis
  215. yAxis   = normalize $ viewUp ^-^ (viewDir ^* (viewDir^.^viewUp))
  216. zAxis   = normalize $ neg viewDir
  217. corner  = view ^-^ (xAxis ^* (viewW/2)) ^+^ (yAxis ^* (viewH/2))
  218.  
  219. lights  = [ Light (Vector 10   5    5 ) (Color   0 0.0 0.9)
  220.          , Light (Vector  2   5  (-1)) (Color 0.7 0.4 0.4)
  221.          , Light (Vector 10 (-5)   5 ) (Color   0 0.5   0)
  222.          ]
  223. objs    = [ Sphere (Vector (-2) (-4)   4 ) 5 (Color 1 1 1) (Color 0.5 0.5 0.5) 10
  224.          , Sphere (Vector (-2)   4  (-5)) 5 (Color 1 1 1) (Color 0.5 0.5 0.5) 10
  225.          ] ++
  226.          [ Sphere (Vector (-8) (i'/9*25-12.5) (j'/9*25-12.5)) 0.5
  227.                   (Color 1 1 1) (Color 0.5 0.5 0.5) 4
  228.          | i <- [0..9], j <- [0..9]
  229.          , let i' = fromIntegral i, let j' = fromIntegral j ]
Add Comment
Please, Sign In to add comment