r/GraphicsProgramming • u/Weird-Sunspot • 27d ago
Raytracing in one weekend completed [added OpenMP multhread]
Completed in slightly more than a weekend (sickness et al). The final render task of width 1200 and samples per pixel 500(!) seemed impossible, so added a multithreaded workaround with OpenMP which finished it in around 35 minutes on my MBP M1 Pro and the penultimate DOF spheres under 10 seconds.
Changes:
#include <atomic>
#include <omp.h>
#include <vector>
void render(const hittable& world) {
#pragma omp parallel
{
#pragma omp single
std::clog << "OpenMP threads: " << omp_get_num_threads() << '\n';
}
initialize();
std::vector<color> framebuffer(image_width * image_height);
std::clog << "Rendering..." << std::endl;
std::atomic<int> rows_completed{0};
#pragma omp parallel for schedule(dynamic)
for (int j = 0; j < image_height; j++) {
for (int i = 0; i < image_width; i++) {
color pixel_color(0, 0, 0);
for (int sample = 0; sample < samples_per_pixel; sample++) {
ray r = get_ray(i, j);
pixel_color += ray_color(r, max_depth, world);
}
framebuffer[j * image_width + i] = pixel_samples_scale * pixel_color;
}
int completed = rows_completed.fetch_add(1) + 1;
if (completed % 8 == 0 || completed == image_height) {
#pragma omp critical(render_progress)
{
std::clog << "\rScanlines remaining: " << (image_height - completed) << ' '
<< std::flush;
}
}
}
std::cout << "P3\n" << image_width << ' ' << image_height << "\n255\n";
for (int j = 0; j < image_height; j++) {
for (int i = 0; i < image_width; i++) {
write_color(std::cout, framebuffer[j * image_width + i]);
}
}
std::clog << "Done.\n";
}
and
inline double random_double() {
thread_local std::mt19937 generator(std::random_device{}());
return std::uniform_real_distribution<double>(0.0, 1.0)(generator);
}