-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcamera.cpp
More file actions
159 lines (115 loc) · 5.17 KB
/
Copy pathcamera.cpp
File metadata and controls
159 lines (115 loc) · 5.17 KB
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
159
#include "header/camera.h"
#include <iostream>
#include <fstream>
#include <thread>
void camera::render(world& world) {
std::clog << "Starting render..." << std::endl;
initialise();
auto start_time = std::chrono::high_resolution_clock::now();
// Render
std::ofstream ImageFile("images/image.ppm");
ImageFile << "P3\n" << image_width << ' ' << image_height << "\n255\n";
vector<color> imageBuffer(image_width * image_height);
std::vector<std::thread> threads;
int total_pixels = image_width * image_height;
std::clog << "Rendering " << total_pixels << " pixels with " << threadCount << " threads..." << std::endl;
std::atomic<int> completedPixels = 0;
for (int i = 0; i < threadCount; ++i) {
threads.emplace_back(&camera::calculateColorThread, this, i, std::ref(imageBuffer), std::ref(world), std::ref(completedPixels));
}
for (auto& t : threads) {
t.join();
}
for (vec3 pixel : imageBuffer) {
write_color(ImageFile, pixel);
}
ImageFile.close();
auto end_time = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::high_resolution_clock::now() - start_time;
auto ms_total = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
auto minutes = ms_total / 60000;
auto seconds = (ms_total % 60000) / 1000;
auto milliseconds = ms_total % 1000;
std::clog << "\rDone in " << minutes << "m " << seconds << "s " << milliseconds << "ms. \n";
}
void camera::initialise() {
this->image_height = int(image_width / aspect_ratio);
image_height = (image_height < 1) ? 1 : image_height;
double focal_length = (lookfrom - lookat).length();
double theta = vfov * numbers::pi / 180;
double h = std::tan(theta/2);
auto viewport_height = 2 * h * focal_length;
auto viewport_width = viewport_height * (double(image_width)/image_height);
auto camera_center = lookfrom;
vec3 w = (lookfrom - lookat).unit_vector();
vec3 u = vup.cross(w).unit_vector();
vec3 v = w.cross(u);
this->camera_up = v;
// Calculate the vectors across the horizontal and down the vertical viewport edges.
vec3 viewport_u = viewport_width * u; // Vector across viewport horizontal edge
vec3 viewport_v = viewport_height * -v; // Vector down viewport vertical edge
// Calculate the horizontal and vertical delta vectors from pixel to pixel.
this->pixel_delta_u = viewport_u / image_width;
this->pixel_delta_v = viewport_v / image_height;
// Calculate the location of the upper left pixel.
auto viewport_upper_left = camera_center - (focal_length * w) - viewport_u/2 - viewport_v/2;
this->pixel00_loc = viewport_upper_left + 0.5 * (pixel_delta_u + pixel_delta_v);
}
hitInfo camera::calculateClosestHit(const ray& r, const world& world) {
hitInfo closestHit;
closestHit.distance = std::numeric_limits<double>::infinity();
for (auto& obj : world.objects) {
hitInfo hit = obj->hit(r);
if (hit.didHit == true && hit.distance < closestHit.distance) {
closestHit = hit;
closestHit.material = obj->material;
}
}
return closestHit;
};
color camera::globalIllumination(const ray& r) const {
double alignment = r.direction.unit_vector().dot(camera_up);
double t = 0.5 * (alignment + 1.0);
color top = color(0.5, 0.7, 1.0); // Sky
color bottom = color(1.0, 1.0, 1.0); // Horizon
return (1.0 - t) * bottom + t * top;
}
color camera::trace(ray &r, const world& world) const {
color rayColor = color(1, 1, 1);
color incomingLight = color(0, 0,0);
for (int i = 0; i < maxBounceCount + 1; i++) {
hitInfo hit = calculateClosestHit(r, world);
if (hit.didHit) {
r.origin = hit.hitPoint;
r.direction = randomHemisphereDirection(hit.normal);
//r.direction = (hit.normal + randomDirection()).unit_vector();
vec3 emittedLight = hit.material.emissionColor * hit.material.emissionStrength;
incomingLight += emittedLight * rayColor;
rayColor *= hit.material.materialColor;
} else {
incomingLight += globalIllumination(r) * rayColor;
break;
}
}
return incomingLight;
}
void camera::calculateColorThread(int threadID, vector<color>& imageBuffer, const world& world, std::atomic<int>& completed_pixels) {
for (int k = threadID; k < imageBuffer.size(); k += threadCount) {
color pixel_color = color(0, 0, 0);
int i = k % image_width;
int j = k / image_width;
point3 pixel_center = pixel00_loc + (i * pixel_delta_u) + (j * pixel_delta_v);
vec3 ray_direction = (pixel_center - lookfrom).unit_vector();
for (int l = 0; l < rayPerPixel + 1; l++) {
ray r(lookfrom, ray_direction);
pixel_color += trace(r, world);
}
pixel_color /= rayPerPixel;
imageBuffer[k] = pixel_color;
completed_pixels.fetch_add(1, std::memory_order_relaxed);
if (threadID == 1) {
int progress = 100.0 * completed_pixels / (image_width * image_height);
clog << "\rProgress: " << progress << "%" << std::flush;
}
}
}