-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsphere.go
56 lines (49 loc) · 1.15 KB
/
sphere.go
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package yagrt
import "math"
// Sphere represents a sphere in 3D, it has an origin and a radius
type Sphere struct {
Origin Vector
Radius float64
Mat Material
}
// Intersect calculates the intersection point of a ray with the sphere
// It returns the distance of the intersection from the ray's origin if
// ray intersects the sphere, INF if it doesn't.
func (s *Sphere) Intersect(r Ray) *Hit {
to := r.Origin.Sub(s.Origin)
a := r.Dir.Dot(r.Dir)
b := 2 * r.Dir.Dot(to)
c := to.Dot(to) - s.Radius*s.Radius
d := b*b - 4*a*c
if d < HitEpsilon {
return nil
}
d = math.Sqrt(d)
t1 := (-b + d) / (2 * a)
t2 := (-b - d) / (2 * a)
var small float64
var big float64
if small = t1; t2 < t1 {
small = t2
}
if big = t1; t2 > t1 {
big = t2
}
if small < HitEpsilon {
if big < HitEpsilon {
return nil
}
small = big
}
p := r.Origin.Add(r.Dir.Mul(small))
n := s.Normal(p)
return &Hit{T: small, Shape: s, Normal: n}
}
// Normal returns the sufrace normal of a sphere
func (s *Sphere) Normal(p Vector) Vector {
return p.Sub(s.Origin).Normalize()
}
// Material returns the material of a sphere
func (s *Sphere) Material() *Material {
return &s.Mat
}