From f230ab264adebce9868d088ea408445d66254963 Mon Sep 17 00:00:00 2001 From: Martin Lehoux Date: Sat, 4 Apr 2020 17:53:48 -0700 Subject: feat - Add several entities --- color.go | 4 ++-- hitable.go | 50 ++++++++++++++++++++++++++++++++++++++++---------- main.go | 10 ++++++++-- 3 files changed, 50 insertions(+), 14 deletions(-) diff --git a/color.go b/color.go index 1ac8141..b8776ca 100644 --- a/color.go +++ b/color.go @@ -16,8 +16,8 @@ func LinearBlend(color1 Color, color2 Color, param float64) Color { } } -func RayColor(ray Ray, hitable Hitable) Color { - hit := hitable.Hit(ray) +func RayColor(ray Ray, hitable_list HitableList) Color { + hit := hitable_list.Hit(ray, T_MIN, T_MAX) if hit.time > 0.0 { vec := AddVec3D(hit.normal, Vec3D{1.0, 1.0, 1.0}) return LinearBlend(Color{vec.x, vec.y, vec.z}, Color{0.0, 0.0, 0.0}, 0.5) diff --git a/hitable.go b/hitable.go index ed18a5d..bc9f9bc 100644 --- a/hitable.go +++ b/hitable.go @@ -9,8 +9,25 @@ type HitRecord struct { } type Hitable interface { - Hit(ray Ray) HitRecord - Normal(point Vec3D) Vec3D + Hit(ray Ray, t_min float64, t_max float64) HitRecord + Normal(point Vec3D, ray Ray) Vec3D +} + +type HitableList []Hitable + +func (hitable_list HitableList) Hit(ray Ray, t_min float64, t_max float64) HitRecord { + closest_hit := HitRecord{T_MAX, Vec3D{}, Vec3D{}} + for _, hitable := range hitable_list { + hit := hitable.Hit(ray, t_min, closest_hit.time) + if hit.time > 0 { + closest_hit = hit + } + } + if closest_hit.time < T_MAX { + return closest_hit + } else { + return HitRecord{} + } } type Sphere struct { @@ -18,20 +35,33 @@ type Sphere struct { radius float64 } -func (sphere Sphere) Normal(point Vec3D) Vec3D { - return SubVec3D(point, sphere.center).Unit() +func (sphere Sphere) Normal(point Vec3D, ray Ray) Vec3D { + out_normal := SubVec3D(point, sphere.center).Unit() + if DotProduct(ray.direction, out_normal) < 0.0 { + return out_normal + } else { + return out_normal.Invert() + } } -func (sphere Sphere) Hit(ray Ray) HitRecord { +func (sphere Sphere) Hit(ray Ray, t_min float64, t_max float64) HitRecord { oc := SubVec3D(ray.origin, sphere.center) a := DotProduct(ray.direction, ray.direction) b := 2.0 * DotProduct(oc, ray.direction) c := DotProduct(oc, oc) - sphere.radius*sphere.radius discriminant := b*b - 4*a*c - if discriminant < 0 { - return HitRecord{} + if discriminant > 0 { + root := math.Sqrt(discriminant) + time := (-b - root) / (2.0 * a) + if t_min < time && time < t_max { + point := ray.PointAt(time) + return HitRecord{time, point, sphere.Normal(point, ray)} + } + time = (-b + root) / (2.0 * a) + if t_min < time && time < t_max { + point := ray.PointAt(time) + return HitRecord{time, point, sphere.Normal(point, ray)} + } } - time := (-b - math.Sqrt(discriminant)) / (2.0 * a) - point := ray.PointAt(time) - return HitRecord{time, point, sphere.Normal(point)} + return HitRecord{} } diff --git a/main.go b/main.go index a1cb2c9..daf2718 100644 --- a/main.go +++ b/main.go @@ -2,19 +2,25 @@ package main const HEIGHT = 100 const WIDTH = 200 +const T_MIN = 0.001 +const T_MAX = 1000 func main() { LOWER_LEFT_CORNER := Vec3D{-2.0, -1.0, -1.0} ORIGIN := Vec3D{0.0, 0.0, 0.0} HORIZONTAL := Vec3D{4.0, 0.0, 0.0} VERTICAL := Vec3D{0.0, 2.0, 0.0} - SPHERE := Sphere{Vec3D{0.0, 0.0, -1.0}, .5} + + SPHERE := Sphere{Vec3D{0.0, 0.0, -1.0}, 0.5} + EARTH := Sphere{Vec3D{0.0, -100.5, -1.0}, 100.0} + + WORLD := HitableList{EARTH, SPHERE} frame := Frame{} for x := 0; x < HEIGHT; x++ { for y := 0; y < WIDTH; y++ { u, v := float64(y)/float64(WIDTH), float64(x)/float64(HEIGHT) ray := Ray{ORIGIN, AddVec3D(AddVec3D(LOWER_LEFT_CORNER, ScalarProduct(u, HORIZONTAL)), ScalarProduct(v, VERTICAL))} - color := RayColor(ray, SPHERE) + color := RayColor(ray, WORLD) frame[HEIGHT-1-x][y] = color.ToPixel() } } -- cgit v1.3