-
Notifications
You must be signed in to change notification settings - Fork 0
/
main_positionable_camera.cpp
158 lines (139 loc) · 4.53 KB
/
main_positionable_camera.cpp
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include "common.h"
#include "hittable_list.h"
#include "sphere.h"
#include "camera.h"
#include "material.h"
#include <iostream>
// ray_color samples the color of a scene using the given ray.
color ray_color(
const ray& r,
const hittable& scene,
const color bg_color_1,
const color bg_color_2,
int bounces,
bool use_hit_color
) {
if (bounces < 0) {
return color(0.0, 0.0, 0.0);
}
hit_record hit;
// t_min is 0.001, instead of 0.0, to avoid shadow acne caused by the bouncing
// ray hitting its origin surface.
if (scene.hit(r, 0.001, infinity, hit)) {
color bounce_color;
color attenuation;
ray bounce_ray;
if (!hit.material->scatter(r, hit, attenuation, bounce_ray)) {
return color(0.0, 0.0, 0.0);
}
bounce_color = ray_color(
bounce_ray,
scene,
bg_color_1,
bg_color_2,
bounces - 1,
use_hit_color
);
color sample_color = attenuation * bounce_color;
if (use_hit_color) {
sample_color += attenuation * hit.color;
}
return sample_color;
}
// Sample the background, blending blue and white linearly.
double t = 0.5 + 0.5 * unit_vector(r.direction()).y();
return t * bg_color_1 + (1 - t) * bg_color_2;
}
int main() {
const auto aspect_ratio = 16.0 / 9.0;
const int image_width = 384;
const int image_height = static_cast<int>(image_width / aspect_ratio);
const int samples_per_pixel = 100;
const int max_bounces = 50;
const color bg_color_1(134.0 / 256.0, 154.0 / 256.0, 181.0 / 256.0);
const color bg_color_2(134.0 / 256.0, 154.0 / 256.0, 181.0 / 256.0);
const double glass_refractive_index = 1.5;
std::cout << "P3\n" << image_width << " " << image_height << "\n255\n";
point3 origin(0.0, 0.0, 0.0);
vec3 horizontal(4.0, 0.0, 0.0);
vec3 vertical(0.0, 2.25, 0.0);
point3 lower_left_corner
= origin - horizontal / 2 - vertical / 2 - vec3(0.0, 0.0, 1.0);
hittable_list scene;
shared_ptr<fuzzy> mat1 = make_shared<fuzzy>(color(0.2, 0.2, 0.2), 0.5);
scene.add(
make_shared<sphere>(
point3(1.0, 0, -1),
0.5,
color(177.0 / 256.0, 169.0 / 256.0, 107.0 / 256.0),
color(177.0 / 256.0, 169.0 / 256.0, 107.0 / 256.0),
mat1
)
);
shared_ptr<lambertian> mat2 = make_shared<lambertian>(color(0.1, 0.2, 0.5));
scene.add(
make_shared<sphere>(
point3(0.0, 0, -1),
0.5,
color(171.0 / 256.0, 117.0 / 256.0, 133.0 / 256.0),
color(171.0 / 256.0, 117.0 / 256.0, 133.0 / 256.0),
mat2
)
);
shared_ptr<dielectric> mat3 = make_shared<dielectric>(glass_refractive_index);
scene.add(
make_shared<sphere>(
point3(-1.0, 0, -1),
0.5,
color(0.0 / 256.0, 0.0 / 256.0, 0.0 / 256.0),
color(0.0 / 256.0, 0.0 / 256.0, 0.0 / 256.0),
mat3
)
);
scene.add(
make_shared<sphere>(
point3(-1.0, 0, -1),
// The negative radius doesn't affect the geometry, because the equation
// of the sphere squares the radius. The normals get inverted, though,
// which is just what we need for the inner walls of a hollow glass ball.
-0.4,
color(0.0 / 256.0, 0.0 / 256.0, 0.0 / 256.0),
color(0.0 / 256.0, 0.0 / 256.0, 0.0 / 256.0),
mat3
)
);
// Ground.
shared_ptr<lambertian> mat4 = make_shared<lambertian>(color(134.0 / 256.0, 154.0 / 256.0, 181.0 / 256.0));
scene.add(
make_shared<sphere>(
point3(0, -100.5, -1),
100,
color(134.0 / 256.0, 154.0 / 256.0, 181.0 / 256.0),
color(134.0 / 256.0, 154.0 / 256.0, 181.0 / 256.0),
mat4
)
);
point3 look_from(3, 3, 2);
point3 look_at(0, 0, -1);
camera cam(look_from, look_at, vec3(0, 1, 0), 20, aspect_ratio, 2.0, (look_from - look_at).length());
for (int j = image_height - 1; j >= 0; --j) {
std::cerr << "\rScanlines remaining: " << j << " " << std::flush;
for (int i = 0; i < image_width; ++i) {
color pixel_color(0.0, 0.0, 0.0);
for (int s = 0; s < samples_per_pixel; s++) {
// Draw from [0, 1). It's important that it not be 1, because we don't
// want to step on the neighboring pixel.
auto sample_offset_u = random_double();
auto sample_offset_v = random_double();
auto u = (double(i) + sample_offset_u) / (double(image_width) - 1);
auto v = (double(j) + sample_offset_v) / (double(image_height) - 1);
ray r = cam.get_ray(u, v);
pixel_color += ray_color(
r, scene, bg_color_1, bg_color_2, max_bounces, false
);
}
write_color(std::cout, pixel_color, samples_per_pixel);
}
}
std::cerr << "\nDone.\n";
}