From bd3bbdd239fd91056442384bfe3a86b2b8c0e68e Mon Sep 17 00:00:00 2001 From: Nat Lasseter Date: Mon, 24 Jun 2024 17:26:09 +0100 Subject: chapter 9 --- camera.go | 27 +++++++++++++++------------ hittable.go | 2 +- interval.go | 4 ++++ ray.go | 17 +++++++++++------ rtiaw.go | 2 +- vec3.go | 29 +++++++++++++++++++++++++---- 6 files changed, 57 insertions(+), 24 deletions(-) diff --git a/camera.go b/camera.go index 569d385..b42e9e1 100644 --- a/camera.go +++ b/camera.go @@ -13,9 +13,10 @@ type Camera struct { PDV Vec3 Pixel00 Vec3 AntiAliasing uint + MaxDepth uint } -func NewCamera(w uint, ar float64, aa uint) (cam Camera) { +func NewCamera(w uint, ar float64, aa uint, md uint) (cam Camera) { cam.ImageWidth = w; cam.ImageHeight = uint(float64(cam.ImageWidth) / ar); if cam.ImageHeight < 1 { @@ -23,26 +24,27 @@ func NewCamera(w uint, ar float64, aa uint) (cam Camera) { } cam.AntiAliasing = aa; + cam.MaxDepth = md; focal_length := 1.0; viewport_height := 2.0; viewport_width := viewport_height * float64(cam.ImageWidth) / float64(cam.ImageHeight); - cam.Centre = Splat(0); + cam.Centre = SplatVec3(0); viewport_u := Vec3{viewport_width, 0, 0}; viewport_v := Vec3{0, -viewport_height, 0}; - cam.PDU = viewport_u.Div(Splat(float64(cam.ImageWidth))); - cam.PDV = viewport_v.Div(Splat(float64(cam.ImageHeight))); + cam.PDU = viewport_u.Div(SplatVec3(float64(cam.ImageWidth))); + cam.PDV = viewport_v.Div(SplatVec3(float64(cam.ImageHeight))); viewport_upperleft := cam.Centre. Sub(Vec3{0, 0, focal_length}). - Sub(viewport_u.Div(Splat(2))). - Sub(viewport_v.Div(Splat(2))); + Sub(viewport_u.Div(SplatVec3(2))). + Sub(viewport_v.Div(SplatVec3(2))); cam.Pixel00 = viewport_upperleft. - Add(cam.PDU.Add(cam.PDV).Div(Splat(2))); + Add(cam.PDU.Add(cam.PDV).Div(SplatVec3(2))); return; } @@ -54,12 +56,13 @@ func (cam Camera) Render(world Hittable) { "Scanlines remaining: %3d...", (cam.ImageHeight - row)); for col := uint(0); col < cam.ImageWidth; col++ { - pixel_colour := Splat(0); + pixel_colour := SplatVec3(0); for i := uint(0); i < cam.AntiAliasing; i++ { r := cam.GetRay(row, col); - pixel_colour = pixel_colour.Add(r.Colour(world)); + pixel_colour = pixel_colour.Add(r.Colour(world, cam.MaxDepth)); } - pixel_colour = pixel_colour.Div(Splat(float64(cam.AntiAliasing))); + pixel_colour = pixel_colour. + Div(SplatVec3(float64(cam.AntiAliasing))); fmt.Printf("%s ", pixel_colour.ToPPM()); } fmt.Printf("\n"); @@ -69,8 +72,8 @@ func (cam Camera) Render(world Hittable) { func (cam Camera) GetRay(row uint, col uint) Ray { offset := unit_square(); pixel_sample := cam.Pixel00. - Add(cam.PDU.Mul(Splat(float64(col) + offset.X))). - Add(cam.PDV.Mul(Splat(float64(row) + offset.Y))); + Add(cam.PDU.Mul(SplatVec3(float64(col) + offset.X))). + Add(cam.PDV.Mul(SplatVec3(float64(row) + offset.Y))); return Ray{cam.Centre, pixel_sample.Sub(cam.Centre)}; } diff --git a/hittable.go b/hittable.go index 5320a0f..5ab11cc 100644 --- a/hittable.go +++ b/hittable.go @@ -56,7 +56,7 @@ func (s Sphere) Hit(r Ray, ray_t Interval) (rec HitRecord) { rec.T = root; rec.P = r.At(rec.T); - out_n := rec.P.Sub(s.Origin).Div(Splat(s.Radius)); + out_n := rec.P.Sub(s.Origin).Div(SplatVec3(s.Radius)); rec.SetFaceNormal(r, out_n); rec.Valid = true; return; diff --git a/interval.go b/interval.go index 763939a..b7deb68 100644 --- a/interval.go +++ b/interval.go @@ -34,3 +34,7 @@ func (i Interval) Clamp(x float64) float64 { func (i Interval) Sample() float64 { return rand.Float64() * i.Size() + i.Min; } + +func (i Interval) RandomVec3() Vec3 { + return Vec3{i.Sample(), i.Sample(), i.Sample()}; +} diff --git a/ray.go b/ray.go index cd4f6aa..18c8a39 100644 --- a/ray.go +++ b/ray.go @@ -10,17 +10,22 @@ type Ray struct { } func (r Ray) At(t float64) Vec3 { - return r.Origin.Add(r.Direction.Mul(Splat(t))); + return r.Origin.Add(r.Direction.Mul(SplatVec3(t))); } -func (r Ray) Colour(world Hittable) Vec3 { - hit := world.Hit(r, Interval{0, maths.Inf(1)}) +func (r Ray) Colour(world Hittable, md uint) Vec3 { + if md <= 0 { + return SplatVec3(0); + } + + hit := world.Hit(r, Interval{0.001, maths.Inf(1)}) if hit.Valid { - return hit.N.Add(Splat(1)).Div(Splat(2)); + dir := hit.N.Add(RandomVec3OnUnitSphere()); + return Ray{hit.P, dir}.Colour(world, md - 1).Div(SplatVec3(10)); } unit_dir := r.Direction.Unit(); a := (unit_dir.Y + 1) / 2; - return Vec3{0.5, 0.7, 1.0}.Mul(Splat(a)). - Add(Splat(1).Mul(Splat(1.0 - a))); + return Vec3{0.5, 0.7, 1.0}.Mul(SplatVec3(a)). + Add(SplatVec3(1).Mul(SplatVec3(1.0 - a))); } diff --git a/rtiaw.go b/rtiaw.go index ec5975e..99bc31a 100644 --- a/rtiaw.go +++ b/rtiaw.go @@ -13,7 +13,7 @@ func main() { world.Add(Sphere{Vec3{0, 0 , -1}, 0.5}); world.Add(Sphere{Vec3{0, -100.5, -1}, 100 }); - cam := NewCamera(400, 16.0/9.0, 100); + cam := NewCamera(400, 16.0/9.0, 100, 50); cam.Render(world); dur := time.Since(start); diff --git a/vec3.go b/vec3.go index 4212b46..bc16a07 100644 --- a/vec3.go +++ b/vec3.go @@ -52,16 +52,37 @@ func (v Vec3) Cross(w Vec3) Vec3 { v.X * w.Y - v.Y * w.X}; } +func linear_to_gamma(comp float64) float64 { + if comp > 0 { + return maths.Sqrt(comp); + } + return 0; +} + func (v Vec3) ToPPM() string { i := Interval{0, 0.999}; - r := uint8(256 * i.Clamp(v.X)); - g := uint8(256 * i.Clamp(v.Y)); - b := uint8(256 * i.Clamp(v.Z)); + r := uint8(256 * i.Clamp(linear_to_gamma(v.X))); + g := uint8(256 * i.Clamp(linear_to_gamma(v.Y))); + b := uint8(256 * i.Clamp(linear_to_gamma(v.Z))); return fmt.Sprintf("%3d %3d %3d", r, g, b); } -func Splat(f float64) Vec3 { +func SplatVec3(f float64) Vec3 { return Vec3{f, f, f}; } + +func RandomVec3OnUnitSphere() (v Vec3) { + i := Interval{-1, 1} + + for true { + v = i.RandomVec3() + if v.MagSqr() < 1 { + v = v.Unit(); + return; + } + } + + return; +} -- cgit v1.2.1