aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNat Lasseter <user@4574.co.uk>2024-06-24 17:26:09 +0100
committerNat Lasseter <user@4574.co.uk>2024-06-24 17:26:09 +0100
commitbd3bbdd239fd91056442384bfe3a86b2b8c0e68e (patch)
treece12c3a6289820092bb9b1f346ee16361b805e4c
parent2f025ebfc6c9e3146ef1c356f99045edc203c9ee (diff)
chapter 9
-rw-r--r--camera.go27
-rw-r--r--hittable.go2
-rw-r--r--interval.go4
-rw-r--r--ray.go17
-rw-r--r--rtiaw.go2
-rw-r--r--vec3.go29
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;
+}