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.
49 lines
1.4 KiB
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
|
|
|