package main import ( "fmt" "os" ) type Camera struct { ImageWidth uint ImageHeight uint Centre Vec3 PDU Vec3 PDV Vec3 Pixel00 Vec3 AntiAliasing uint MaxDepth uint } 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 { cam.ImageHeight = 1; } 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 = SplatVec3(0); viewport_u := Vec3{viewport_width, 0, 0}; viewport_v := Vec3{0, -viewport_height, 0}; 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(SplatVec3(2))). Sub(viewport_v.Div(SplatVec3(2))); cam.Pixel00 = viewport_upperleft. Add(cam.PDU.Add(cam.PDV).Div(SplatVec3(2))); return; } func (cam Camera) Render(world Hittable) { fmt.Printf("P3\n%d %d\n255\n", cam.ImageWidth, cam.ImageHeight); for row := uint(0); row < cam.ImageHeight; row++ { fmt.Fprintf(os.Stderr, "Scanlines remaining: %3d...", (cam.ImageHeight - row)); for col := uint(0); col < cam.ImageWidth; col++ { 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, cam.MaxDepth)); } pixel_colour = pixel_colour. Div(SplatVec3(float64(cam.AntiAliasing))); fmt.Printf("%s ", pixel_colour.ToPPM()); } fmt.Printf("\n"); } } func (cam Camera) GetRay(row uint, col uint) Ray { offset := unit_square(); pixel_sample := cam.Pixel00. 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), true}; } func unit_square() Vec3 { i := Interval{-0.5, 0.5}; return Vec3{i.Sample(), i.Sample(), 0}; }