#include #include #include #include "depthoffieldrenderer.h" #include DOFRenderer::DOFRenderer(float _aperture, int _secondaryRayCount, float _focalLength) : aperture(_aperture), numSamples(_secondaryRayCount), focalLength(_focalLength) {} std::random_device DOFRenderer::rd; std::mt19937 DOFRenderer::gen(DOFRenderer::rd()); Color DOFRenderer::sample(const Ray &ray, const Scene& scene, const Camera& camera) const { std::uniform_real_distribution dis(-1.0, 1.0); // calculate the point of focus Vector3d focusPoint = ray.origin + ray.direction * focalLength; // Final color Color finalColor; // Calculate all secondary Rays for (int i = 0; i < numSamples; i++) { // create a random point on the aperture Vector3d rnd = Vector3d(dis(gen), dis(gen), 0); Vector3d apertureOffset = aperture * (rnd.x * camera.getRightDirection() + rnd.y * camera.getUpDirection()); // create the new ray with the offset point Vector3d dofRayOrigin = ray.origin + apertureOffset; Vector3d dofRayDirection = normalized(focusPoint - dofRayOrigin); Ray dofRay(dofRayOrigin, dofRayDirection); // get Color of the new Ray finalColor += scene.traceRay(dofRay); } // trace the new ray and return the color return finalColor /= float(numSamples);; } void DOFRenderer::renderThread(const Scene *scene, Camera const *camera, Texture *image, const DOFRenderer *renderer, int width, int widthStep, int widthOffset, int height, int heightStep, int heightOffset, std::atomic *k, int const stepSize) { float const aspectRatio = static_cast(height) / width; for (int y = heightOffset; y < height; y += heightStep) { for (int x = widthOffset; x < width; x += widthStep) { Ray ray = camera->createRay((static_cast(x) / width * 2 - 1), -(static_cast(y) / height * 2 - 1) * aspectRatio); // Trace rays with DOF image->setPixelAt(x, y, clamped(renderer->sample(ray, *scene, *camera))); // Super hacky progress bar! if (++*k % stepSize == 0) { std::cout << "=" << std::flush; } } } } Texture DOFRenderer::renderImage(Scene const &scene, Camera const &camera, int width, int height) { Texture image(width, height); // Setup timer std::chrono::steady_clock::time_point start, stop; // Reset Ray counting Ray::resetRayCount(); // Super-hacky progress bar! std::cout << "(SimpleRenderer): Begin rendering..." << std::endl; std::cout << "| 0%"; int const barSize = 50; int const stepSize = (width * height) / barSize; for (int i = 0; i < barSize - 3 - 5; ++i) std::cout << " "; std::cout << "100% |" << std::endl << "|"; std::atomic k(0); /* Start timer */ start = std::chrono::steady_clock::now(); // Spawn a thread for every logical processor -1, calling the renderThread function int const nThreads = std::thread::hardware_concurrency(); std::vector threads; for (int t = 0; t < nThreads - 1; ++t) { threads.emplace_back(renderThread, &scene, &camera, &image, this, width, nThreads, t, height, 1, 0, &k, stepSize); } // Call the renderThread function yourself renderThread(&scene, &camera, &image, this, width, nThreads, nThreads - 1, height, 1, 0, &k, stepSize); // Rejoin the threads for (int t = 0; t < nThreads - 1; ++t) { threads[t].join(); } // Stop timer stop = std::chrono::steady_clock::now(); std::cout << "| Done!" << std::endl; // Calculate the Time taken in seconds double seconds = std::chrono::duration_cast>(stop - start).count(); std::cout << "Time: " << seconds << "s" << std::endl; // Get the number of seconds per ray int rays = Ray::getRayCount(); std::cout << "Paths: " << rays << std::endl; std::cout << "Paths per second: " << std::fixed << std::setprecision(0) << rays / seconds << std::endl; return image; }