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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
package main
import (
"fmt"
maths "math"
"os"
)
type Camera struct {
ImageWidth uint
ImageHeight uint
Centre Vec3
PDU Vec3
PDV Vec3
Pixel00 Vec3
AntiAliasing uint
MaxDepth uint
DOF float64
DefDiskU Vec3
DefDiskV Vec3
}
func NewCamera(wi uint, ar float64,
aa uint, md uint,
vfov float64, lookfrom Vec3,
lookat Vec3, vup Vec3,
dof float64, fd float64) (cam Camera) {
cam.ImageWidth = wi;
cam.ImageHeight = uint(float64(cam.ImageWidth) / ar);
if cam.ImageHeight < 1 {
cam.ImageHeight = 1;
}
cam.AntiAliasing = aa;
cam.MaxDepth = md;
cam.Centre = lookfrom;
cam.DOF = dof;
theta := vfov * maths.Pi / 180;
h := maths.Tan(theta / 2)
viewport_height := 2.0 * h * fd;
viewport_width := viewport_height *
float64(cam.ImageWidth) /
float64(cam.ImageHeight);
w := lookfrom.Sub(lookat).Unit();
u := vup.Cross(w).Unit();
v := w.Cross(u);
viewport_u := SplatVec3(viewport_width).Mul(u);
viewport_v := SplatVec3(viewport_height).Mul(v.Neg());
cam.PDU = viewport_u.Div(SplatVec3(float64(cam.ImageWidth)));
cam.PDV = viewport_v.Div(SplatVec3(float64(cam.ImageHeight)));
viewport_upperleft := cam.Centre.
Sub(SplatVec3(fd).Mul(w)).
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)));
def_radius := fd * maths.Tan((cam.DOF / 2) * (maths.Pi / 180));
cam.DefDiskU = SplatVec3(def_radius).Mul(u);
cam.DefDiskV = SplatVec3(def_radius).Mul(v);
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,
"[GScanlines 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)));
origin := cam.Centre;
if cam.DOF > 0 {
p := RandomVec3OnUnitDisk();
origin = cam.Centre.
Add(SplatVec3(p.X).Mul(cam.DefDiskU)).
Add(SplatVec3(p.Y).Mul(cam.DefDiskV));
}
direction := pixel_sample.Sub(origin);
return Ray{origin, direction, true};
}
func unit_square() Vec3 {
i := Interval{-0.5, 0.5};
return Vec3{i.Sample(), i.Sample(), 0};
}
|