diff options
Diffstat (limited to 'hittable.go')
-rw-r--r-- | hittable.go | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/hittable.go b/hittable.go new file mode 100644 index 0000000..5320a0f --- /dev/null +++ b/hittable.go @@ -0,0 +1,87 @@ +package main + +import ( + maths "math" +) + +//HitRecord + +type HitRecord struct { + Valid bool + P Vec3 + N Vec3 + T float64 +} + +func (rec *HitRecord) SetFaceNormal(r Ray, out_n Vec3) { + if r.Direction.Dot(out_n) < 0 { + rec.N = out_n + } else { + rec.N = out_n.Neg(); + } +} + +//Hittable + +type Hittable interface { + Hit(r Ray, ray_t Interval) (rec HitRecord) +} + +//Sphere < Hittable + +type Sphere struct { + Origin Vec3 + Radius float64 +} + +func (s Sphere) Hit(r Ray, ray_t Interval) (rec HitRecord) { + oc := s.Origin.Sub(r.Origin); + a := r.Direction.MagSqr(); + h := r.Direction.Dot(oc); + c := oc.MagSqr() - maths.Pow(s.Radius, 2); + disc := maths.Pow(h, 2) - a*c; + + if disc < 0 { + return; + } + + sqrtd := maths.Sqrt(disc); + root := (h - sqrtd) / a; + if !ray_t.Surround(root) { + root = (h + sqrtd) / a; + if !ray_t.Surround(root) { + return; + } + } + + rec.T = root; + rec.P = r.At(rec.T); + out_n := rec.P.Sub(s.Origin).Div(Splat(s.Radius)); + rec.SetFaceNormal(r, out_n); + rec.Valid = true; + return; +} + +//Hittables < Hittable + +type Hittables struct { + Objects []Hittable +} + +func (l *Hittables) Add(o Hittable) { + l.Objects = append(l.Objects, o); +} + +func (l Hittables) Hit(r Ray, ray_t Interval) (rec HitRecord) { + closest_so_far := ray_t.Max; + + for _, o := range l.Objects { + temp_rec := o.Hit(r, Interval{ray_t.Min, closest_so_far}); + if temp_rec.Valid { + rec = temp_rec; + closest_so_far = rec.T; + } + } + + return; +} |