|
|
@ -9,6 +9,7 @@ import Hittable |
|
|
|
import Linear.V2 |
|
|
|
import Linear.V2 |
|
|
|
import Linear.V3 |
|
|
|
import Linear.V3 |
|
|
|
import Linear.Vector |
|
|
|
import Linear.Vector |
|
|
|
|
|
|
|
import Material |
|
|
|
import Maths |
|
|
|
import Maths |
|
|
|
import Ray |
|
|
|
import Ray |
|
|
|
import Text.Printf |
|
|
|
import Text.Printf |
|
|
@ -22,12 +23,19 @@ type ImageDimensions = (Int, Int) |
|
|
|
type ViewPortDimensions = (Double, Double) |
|
|
|
type ViewPortDimensions = (Double, Double) |
|
|
|
|
|
|
|
|
|
|
|
-- TODO |
|
|
|
-- TODO |
|
|
|
-- DONE add multiple samples per pixel |
|
|
|
-- antialiasing |
|
|
|
-- fix coordinate system |
|
|
|
|
|
|
|
-- DONE fix random number generator |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backgroundColor = V3 0.0 0.0 0.0 |
|
|
|
backgroundColor = V3 0.0 0.0 0.0 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
scatter :: (RandomGen g) => Ray Double -> Hit -> Rand g (Ray Double) |
|
|
|
|
|
|
|
scatter (Ray o d) (Hit t p n (Lambertian c)) = do |
|
|
|
|
|
|
|
r <- randV3 |
|
|
|
|
|
|
|
let target = p ^+^ colorWithNormal (unitVector n) ^+^ r |
|
|
|
|
|
|
|
return $ Ray p (target ^-^ p) |
|
|
|
|
|
|
|
scatter (Ray o d) (Hit t p n (Metal c)) = do |
|
|
|
|
|
|
|
let reflected = reflect (unitVector d) n |
|
|
|
|
|
|
|
return $ Ray p reflected |
|
|
|
|
|
|
|
|
|
|
|
getRayColor :: (Shape s, RandomGen g) => [s] -> Int -> Ray Double -> Rand g (V3 Double) |
|
|
|
getRayColor :: (Shape s, RandomGen g) => [s] -> Int -> Ray Double -> Rand g (V3 Double) |
|
|
|
getRayColor ws d r = do |
|
|
|
getRayColor ws d r = do |
|
|
|
let h = getBestHit (mapMaybe (testHit r) ws) |
|
|
|
let h = getBestHit (mapMaybe (testHit r) ws) |
|
|
@ -37,19 +45,17 @@ getRayColor ws d r = do |
|
|
|
getRayColor' :: (Shape s, RandomGen g) => Ray Double -> Maybe Hit -> [s] -> Int -> Rand g (V3 Double) |
|
|
|
getRayColor' :: (Shape s, RandomGen g) => Ray Double -> Maybe Hit -> [s] -> Int -> Rand g (V3 Double) |
|
|
|
getRayColor' (Ray o d) Nothing _ _ = do return $ colorGradient (unitVector d) |
|
|
|
getRayColor' (Ray o d) Nothing _ _ = do return $ colorGradient (unitVector d) |
|
|
|
getRayColor' (Ray o d) _ _ 0 = do return $ colorGradient (unitVector d) |
|
|
|
getRayColor' (Ray o d) _ _ 0 = do return $ colorGradient (unitVector d) |
|
|
|
getRayColor' (Ray o d) (Just (Hit t p n)) ws depth = |
|
|
|
getRayColor' (Ray o d) (Just (Hit t p n m)) ws depth = do |
|
|
|
do |
|
|
|
let a = attenuation m |
|
|
|
r <- randV3 |
|
|
|
ray <- scatter (Ray o d) (Hit t p n m) |
|
|
|
let target = p ^+^ colorWithNormal (unitVector n) ^+^ r |
|
|
|
nextVal <- getRayColor ws (depth - 1) ray |
|
|
|
nextVal <- getRayColor ws (depth - 1) (Ray p (target ^-^ p)) |
|
|
|
return (a * nextVal) |
|
|
|
return (0.5 *^ nextVal) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
colorGradient :: V3 Double -> V3 Double |
|
|
|
colorGradient :: V3 Double -> V3 Double |
|
|
|
colorGradient (V3 x y z) = do |
|
|
|
colorGradient (V3 x y z) = do |
|
|
|
let t = 0.5 * (y + 1.0) |
|
|
|
let t = 0.5 * (y + 1.0) |
|
|
|
(1.0 - t) *^ V3 1.0 1.0 1.0 + t *^ V3 0.5 0.7 1.0 |
|
|
|
(1.0 - t) *^ V3 1.0 1.0 1.0 + t *^ V3 0.5 0.7 1.0 |
|
|
|
|
|
|
|
|
|
|
|
-- testHit needs to take into account other hits, not here |
|
|
|
|
|
|
|
getBestHit [] = Nothing |
|
|
|
getBestHit [] = Nothing |
|
|
|
getBestHit (h : hs) = Just (getBestHit' hs h) |
|
|
|
getBestHit (h : hs) = Just (getBestHit' hs h) |
|
|
|
|
|
|
|
|
|
|
@ -98,9 +104,10 @@ main :: IO () |
|
|
|
main = do |
|
|
|
main = do |
|
|
|
let w = 400 |
|
|
|
let w = 400 |
|
|
|
let h = 400 |
|
|
|
let h = 400 |
|
|
|
-- weirdly, the bottom circle appears on top and bottom |
|
|
|
let world = |
|
|
|
-- Circle (V3 0.0 (-10.05) 1.0) 5] |
|
|
|
[ Circle (V3 0.0 0.0 (-1.0)) 0.25 (Metal (V3 0.8 0.8 0.8)), |
|
|
|
let world = [Circle (V3 0.0 0.0 (-1.0)) 0.25, Circle (V3 0.0 (-10.25) (-1.0)) 10] |
|
|
|
Circle (V3 0.0 (-10.25) (-1.0)) 10 (Lambertian (V3 0.7 0.3 0.3)) |
|
|
|
|
|
|
|
] |
|
|
|
let coords = reverse $ range ((-1 * (w `div` 2), -1 * (h `div` 2)), ((w `div` 2) - 1, (h `div` 2) - 1)) -- "canvas" |
|
|
|
let coords = reverse $ range ((-1 * (w `div` 2), -1 * (h `div` 2)), ((w `div` 2) - 1, (h `div` 2) - 1)) -- "canvas" |
|
|
|
colors <- mapM (\x -> rayTrace x (w, h) (1.0, 1.0) world) coords |
|
|
|
colors <- mapM (\x -> rayTrace x (w, h) (1.0, 1.0) world) coords |
|
|
|
let convertedColors = map v3ToColor colors |
|
|
|
let convertedColors = map v3ToColor colors |
|
|
|