-
Notifications
You must be signed in to change notification settings - Fork 0
/
Sphere.roc
43 lines (31 loc) · 1.28 KB
/
Sphere.roc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
interface Sphere
exposes [Sphere, make, hit]
imports [Vec.{ Vec }, Ray.{ Ray }, Material.{ Material }, HitRecord.{ HitRecord }]
Sphere : { center : Vec, radius : F64, material : Material }
make : Vec, F64, Material -> Sphere
make = \center, radius, material ->
{center, radius, material}
hit : Sphere, Ray, { min : F64, max : F64 } -> Result { rec : HitRecord, mat : Material } [NoHit]
hit = \{ center, radius, material }, ray, { min, max } ->
oc = Vec.sub ray.origin center
a = Vec.lengthSquared ray.direction
halfB = Vec.dot oc ray.direction
c = Vec.lengthSquared oc - (radius * radius)
discriminant = halfB * halfB - a * c
if discriminant <= 0 then
Err NoHit
else
sqrtd = Num.sqrt discriminant
negativeRoot = (-halfB - sqrtd) / a
positiveRoot = (-halfB + sqrtd) / a
root = if negativeRoot > min && negativeRoot < max then
Ok negativeRoot
else if positiveRoot > min && positiveRoot < max then
Ok positiveRoot
else
Err NoHit
t <- Result.map root
p = Ray.at ray t
outwardNormal = Vec.sub p center |> Vec.shrink radius
rec = HitRecord.make {p, t, ray, outwardNormal }
{rec, mat: material}