124 lines
4.3 KiB
C++
124 lines
4.3 KiB
C++
|
#include <iostream>
|
||
|
#include <thread>
|
||
|
#include <chrono>
|
||
|
#include "depthoffieldrenderer.h"
|
||
|
#include <iomanip>
|
||
|
#include "post_processing/bloom.h"
|
||
|
|
||
|
|
||
|
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<float> 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<int> *k, int const stepSize) {
|
||
|
float const aspectRatio = static_cast<float>(height) / width;
|
||
|
for (int y = heightOffset; y < height; y += heightStep) {
|
||
|
for (int x = widthOffset; x < width; x += widthStep) {
|
||
|
Ray ray = camera->createRay((static_cast<float>(x) / width * 2 - 1), -(static_cast<float>(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<int> 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<std::thread> 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<std::chrono::duration<double>>(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;
|
||
|
|
||
|
// Post-processing
|
||
|
// Bloom shader
|
||
|
|
||
|
image.save("original.png");
|
||
|
|
||
|
Bloom bloomEffect = Bloom(image.getImage());
|
||
|
image.setTexture(bloomEffect.bloom(0.55f, 5, 10.0f, 0.06f));
|
||
|
|
||
|
return image;
|
||
|
}
|