You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
haskell-raytracer/src/Hittable.hs

49 lines
1.4 KiB

module Hittable (Shape (..), Circle (..), Hit (..), isFrontFace) where
import Linear.V3
import Linear.Vector
import Material
import Maths
import Ray
class Shape s where
testHit :: Ray Double -> s -> Maybe Hit
data Circle = Circle (V3 Double) Double Material
data Hit = Hit {root :: Double, p :: V3 Double, n :: V3 Double, m :: Material}
getFaceNormal :: Ray Double -> V3 Double -> V3 Double
getFaceNormal (Ray o d) n
| (d `dotP` n) < 0.0 = n
| otherwise = (-1.0) *^ n
isFrontFace :: Ray Double -> V3 Double -> Bool
isFrontFace (Ray o d) n
| (d `dotP` n) < 0.0 = True
| otherwise = False
-- t_min 0 t_max infinity... need closest so far
instance Shape Circle where
testHit (Ray o d) (Circle center r m) =
if discriminant < 0.0
then Nothing
else
if root > 0.001
then Just (Hit root p (getFaceNormal (Ray o d) ((p - center) ^/ r)) m)
else
if rootP > 0.001
then Just (Hit rootP pp (getFaceNormal (Ray o d) ((pp - center) ^/ r)) m)
else Nothing
where
co = o - center
a = lengthSquared d -- a vector dotted with itself is = lengthSquared
b = co `dotP` d
c = lengthSquared co - r ^ 2
discriminant = b ^ 2 - a * c
root = (b * (-1.0) - sqrt discriminant) / a
rootP = (b * (-1.0) + sqrt discriminant) / a
p = rayAt (Ray o d) root
pp = rayAt (Ray o d) rootP
-- would make sense to build a Functor for shapes