aboutsummaryrefslogtreecommitdiff
path: root/hittable.go
blob: ac5e9968a9b8730361d5952c9204c2c4e1964f73 (plain)
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package main

import (
  maths "math"
)

//HitRecord

type HitRecord struct {
  Valid bool
  P Vec3
  N Vec3
  T float64
  F bool
  Mat Material
}

func (rec *HitRecord) SetFaceNormal(r Ray, out_n Vec3) {
  rec.F = r.Direction.Dot(out_n) < 0;
  if rec.F {
    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
  Mat Material
}

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(SplatVec3(s.Radius));
  rec.SetFaceNormal(r, out_n);
  rec.Mat = s.Mat;
  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;
}