From f5347bb07a80bd4290081ff553ad3f57ca0776df Mon Sep 17 00:00:00 2001 From: "m.gaedke" Date: Thu, 26 Jan 2023 22:56:23 +0100 Subject: [PATCH] Field of View renderer finally working pretty good + some restructioring of code --- CMakeLists.txt | 6 +- camera/camera.h | 6 + camera/perspectivecamera.h | 11 +- ex4.cpp | 32 +++-- .../bloom.cpp | 14 +- .../bloomshader.h => post_processing/bloom.h | 10 +- renderer/depthoffieldrenderer.cpp | 124 ++++++++++++++++++ renderer/depthoffieldrenderer.h | 35 +++++ renderer/simplerenderer.cpp | 6 +- renderer/simplerenderer.h | 7 +- shader/depthoffieldshader.cpp | 47 ------- shader/depthoffieldshader.h | 33 ----- 12 files changed, 209 insertions(+), 122 deletions(-) rename post-processing/bloomshader.cpp => post_processing/bloom.cpp (82%) rename post-processing/bloomshader.h => post_processing/bloom.h (73%) create mode 100644 renderer/depthoffieldrenderer.cpp create mode 100644 renderer/depthoffieldrenderer.h delete mode 100644 shader/depthoffieldshader.cpp delete mode 100644 shader/depthoffieldshader.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 52d5575..466550e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,11 +24,13 @@ file(GLOB primitive_src "primitive/*.cpp") file(GLOB renderer_src "renderer/*.cpp") file(GLOB scene_src "scene/*.cpp") file(GLOB shader_src "shader/*.cpp") +file(GLOB effect_src "effect/*.cpp") +file(GLOB post_processing_src "post_processing/*.cpp") # The tracey library add_library(tracey STATIC ${common_src} ${noise_src} ${camera_src} ${light_src} - ${primitive_src} ${renderer_src} ${scene_src} ${shader_src} light/ambientlight.cpp light/ambientlight.h - light/spotlight.cpp light/spotlight.h post-processing/bloomshader.cpp post-processing/bloomshader.h shader/depthoffieldshader.cpp shader/depthoffieldshader.h) + ${primitive_src} ${renderer_src} ${scene_src} ${shader_src} ${effect_src} + ${post_processing_src}) if(NOT WIN32) target_link_libraries(tracey ${CMAKE_THREAD_LIBS_INIT} ${X11_LIBRARIES}) endif() diff --git a/camera/camera.h b/camera/camera.h index 93d82bf..2933d46 100644 --- a/camera/camera.h +++ b/camera/camera.h @@ -12,6 +12,12 @@ public: // Camera functions virtual Ray createRay(float x, float y) const = 0; + + // Setter methods + virtual Vector3d getPosition() const = 0; + virtual Vector3d getRightDirection() const = 0; + virtual Vector3d getUpDirection() const = 0; }; + #endif diff --git a/camera/perspectivecamera.h b/camera/perspectivecamera.h index 0d0f8f2..d935200 100644 --- a/camera/perspectivecamera.h +++ b/camera/perspectivecamera.h @@ -13,11 +13,6 @@ public: // Set void setPosition(Vector3d const &position) { this->position = position; } void setForwardDirection(Vector3d const &forwardDirection) { - // IMPLEMENT ME - // Set up a left-handed coordinate system, - // in which the camera looks along the positive z-Axis - // Set up a left-handed coordinate system, - // in which the camera looks along the positive z-Axis std::tie(this->forwardDirection, this->upDirection, this->rightDirection) = orthoNormalized(forwardDirection, this->upDirection, crossProduct(this->upDirection, forwardDirection)); } void setUpDirection(Vector3d const &upDirection) { @@ -37,9 +32,9 @@ public: Ray createRay(float x, float y) const override; //Getter - Vector3d getPosition() const { return position; } - Vector3d getRightDirection() const { return rightDirection; } - Vector3d getUpDirection() const { return upDirection; } + Vector3d getPosition() const override { return position; } + Vector3d getRightDirection() const override{ return rightDirection; } + Vector3d getUpDirection() const override { return upDirection; } protected: diff --git a/ex4.cpp b/ex4.cpp index 678962c..ee1154a 100644 --- a/ex4.cpp +++ b/ex4.cpp @@ -16,7 +16,7 @@ #include "shader/mirrorshader.h" #include "shader/phongshader.h" #include "shader/cooktorranceshader.h" -#include "shader/depthoffieldshader.h" +#include "renderer/depthoffieldrenderer.h" #include "light/ambientlight.h" #include "light/pointlight.h" @@ -43,8 +43,8 @@ int main() { auto blueMetallic = std::make_shared("../data/blue-metallic-paint.binary", Color(7.0f, 7.0f, 7.0f)); auto darkRed = std::make_shared("../data/dark-red-paint.binary", Color(7.0f, 7.0f, 7.0f)); - auto dofShader = std::make_shared(scene, Color(0.9f, 0.9f, 0.9f), 100, 0.1f, 10.0f, 50.0f, camera); - + // DOF Shader + bool dofShader = true; // Set up the walls @@ -55,20 +55,13 @@ int main() { scene.add(std::make_shared(Vector3d(0.0f, 0.0f, -5.0f), Vector3d(0.0f, 0.0f, +1.0f), mirror)); scene.add(std::make_shared(Vector3d(0.0f, +5.0f, 0.0f), Vector3d(0.0f, -1.0f, 0.0f), white)); scene.add(std::make_shared(Vector3d(0.0f, -5.0f, 0.0f), Vector3d(0.0f, +1.0f, 0.0f), white)); - scene.add(std::make_shared(Vector3d(+5.0f, 0.0f, 0.0f), Vector3d(-1.0f, 0.0f, 0.0f), dofShader)); + scene.add(std::make_shared(Vector3d(+5.0f, 0.0f, 0.0f), Vector3d(-1.0f, 0.0f, 0.0f), blue)); scene.add(std::make_shared(Vector3d(-5.0f, 0.0f, 0.0f), Vector3d(+1.0f, 0.0f, 0.0f), red)); scene.add(std::make_shared(Vector3d(-3.0f, 0.0f, 0.0f), 1.0f, blueMetallic)); scene.add(std::make_shared(Vector3d(0.0f, 2.0f, 0.0f), 1.0f, orange)); scene.add(std::make_shared(Vector3d(3.0f, 0.0f, 0.0f), 1.0f, darkRed)); - - // Create a DOFShader instance with the desired aperture size, focal distance, and focal length - - // Use the DOFShader instance as the shader for an object in the scene - auto sphere = std::make_shared(Vector3d(-3.0f, 0.0f, 0.0f), 1.0f, dofShader); - - // Add the sphere to the scene - scene.add(sphere); + scene.add(std::make_shared(Vector3d(-3.0f, -3.3f, -4.0f), 1.0f, mirror)); // Add the teapot auto teapot = std::make_shared(gold); @@ -83,8 +76,19 @@ int main() { // Render the scene - SimpleRenderer renderer; - renderer.renderImage(scene, camera, 512, 512).save("result.png"); + // SimpleRenderer renderer; + // renderer.renderImage(scene, camera, 1024, 1024).save("result.png"); + + + // initialize renderer: aperture = lens thickness, secondaryRayCount = how many rays per pixel are created + // focalLength = the area which is in focus + DOFRenderer renderer(0.2, 100, 10.0f); + + // Use DOFRenderer to raytrace + Texture image = renderer.renderImage(scene, camera, 1024, 1024); + + // save image + image.save("result.png"); return 0; } diff --git a/post-processing/bloomshader.cpp b/post_processing/bloom.cpp similarity index 82% rename from post-processing/bloomshader.cpp rename to post_processing/bloom.cpp index 62cb032..93291fe 100644 --- a/post-processing/bloomshader.cpp +++ b/post_processing/bloom.cpp @@ -1,11 +1,11 @@ #include -#include "bloomshader.h" +#include "bloom.h" -Bloomshader::Bloomshader(CImg image) : image(image) {} +Bloom::Bloom(CImg image) : image(image) {} -CImg Bloomshader::bloom(float threshold, int kernelSize, float sigma, float intensity) { +CImg Bloom::bloom(float threshold, int kernelSize, float sigma, float intensity) { // Apply threshold to image //CImg brightPixels = image_.get_threshold(threshold); //brightPixels.save("brightpixels.png"); @@ -28,13 +28,13 @@ CImg Bloomshader::bloom(float threshold, int kernelSize, float sigma, flo return image; } -void Bloomshader::gaussianBlur(int kernelSize, float sigma) { +void Bloom::gaussianBlur(int kernelSize, float sigma) { CImg kernel = computeGaussianKernel(kernelSize, sigma); image = convolution(image, kernel); } // Function to compute Gaussian kernel -CImg Bloomshader::computeGaussianKernel(int kernelSize, float sigma) { +CImg Bloom::computeGaussianKernel(int kernelSize, float sigma) { // Create kernel CImg kernel(kernelSize, kernelSize, 1, 1); @@ -56,7 +56,7 @@ CImg Bloomshader::computeGaussianKernel(int kernelSize, float sigma) { } // Function to perform convolution -CImg Bloomshader::convolution(CImg &img, CImg &kernel) { +CImg Bloom::convolution(CImg &img, CImg &kernel) { int kernelSize = kernel.width(); int imgRows = img.height(); int imgCols = img.width(); @@ -83,6 +83,6 @@ CImg Bloomshader::convolution(CImg &img, CImg &kernel) { return result; } -void Bloomshader::scaleBrightness(float scale) { +void Bloom::scaleBrightness(float scale) { image *= scale; } diff --git a/post-processing/bloomshader.h b/post_processing/bloom.h similarity index 73% rename from post-processing/bloomshader.h rename to post_processing/bloom.h index addcf0a..694b0d8 100644 --- a/post-processing/bloomshader.h +++ b/post_processing/bloom.h @@ -1,14 +1,14 @@ -#ifndef CG1_TRACER_BLOOMSHADER_H -#define CG1_TRACER_BLOOMSHADER_H +#ifndef CG1_TRACER_BLOOM_H +#define CG1_TRACER_BLOOM_H #include "common/texture.h" #include "common/vector3d.h" -class Bloomshader { +class Bloom { public: - Bloomshader(CImg image); + Bloom(CImg image); CImg bloom(float threshold, int kernelSize, float sigma, float intensity); private: @@ -24,4 +24,4 @@ private: }; -#endif //CG1_TRACER_BLOOMSHADER_H +#endif //CG1_TRACER_BLOOM_H diff --git a/renderer/depthoffieldrenderer.cpp b/renderer/depthoffieldrenderer.cpp new file mode 100644 index 0000000..aba7d57 --- /dev/null +++ b/renderer/depthoffieldrenderer.cpp @@ -0,0 +1,124 @@ +#include +#include +#include +#include "depthoffieldrenderer.h" +#include +#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 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; + + // 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; +} \ No newline at end of file diff --git a/renderer/depthoffieldrenderer.h b/renderer/depthoffieldrenderer.h new file mode 100644 index 0000000..d195735 --- /dev/null +++ b/renderer/depthoffieldrenderer.h @@ -0,0 +1,35 @@ +#ifndef DEPTHOFFIELDSHADER_H +#define DEPTHOFFIELDSHADER_H + +#include "camera/camera.h" +#include +#include "renderer/renderer.h" +#include "scene/simplescene.h" + + +class DOFRenderer : public Renderer { + static void renderThread(const Scene *scene, const Camera *camera, Texture *image, const DOFRenderer *renderer, int width, int widthStep, + int widthOffset, int height, int heightStep, int heightOffset, std::atomic *k, + const int stepSize); + +public: + // Constructor + DOFRenderer(float _aperture, int _secondaryRayCount, float _focalLength); + ~DOFRenderer() override = default; + + //Render Functions + Texture renderImage(Scene const &scene, Camera const &camera, int width, int height) override; + + // DOF sampler + Color sample(const Ray &ray, const Scene& scene, const Camera& camera) const; + +private: + float aperture, focalLength; + int numSamples; + + static std::random_device rd; + static std::mt19937 gen; + +}; + +#endif \ No newline at end of file diff --git a/renderer/simplerenderer.cpp b/renderer/simplerenderer.cpp index fea71a3..3647efc 100644 --- a/renderer/simplerenderer.cpp +++ b/renderer/simplerenderer.cpp @@ -5,7 +5,7 @@ #include #include #include -#include "post-processing/bloomshader.h" +#include "post_processing/bloom.h" void SimpleRenderer::renderThread(const Scene *scene, Camera const *camera, Texture *image, 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; @@ -79,8 +79,8 @@ Texture SimpleRenderer::renderImage(Scene const &scene, Camera const &camera, in image.save("original.png"); - Bloomshader bloomEffect = Bloomshader(image.getImage()); + Bloom bloomEffect = Bloom(image.getImage()); image.setTexture(bloomEffect.bloom(0.55f, 5, 10.0f, 0.06f)); return image; -} +} \ No newline at end of file diff --git a/renderer/simplerenderer.h b/renderer/simplerenderer.h index 21e1f69..c1c9ed2 100644 --- a/renderer/simplerenderer.h +++ b/renderer/simplerenderer.h @@ -3,11 +3,12 @@ #include #include "renderer/renderer.h" +#include class SimpleRenderer : public Renderer { - static void renderThread(const Scene *scene, Camera const *camera, Texture *image, int width, int widthStep, - int widthOffset, int height, int heightStep, int heightOffset, std::atomic *k, - int const stepSize); + static void renderThread(const Scene *scene, const Camera *camera, Texture *image, int width, int widthStep, + int widthOffset, int height, int heightStep, int heightOffset, std::atomic *k, + const int stepSize); public: // Constructor / Destructor diff --git a/shader/depthoffieldshader.cpp b/shader/depthoffieldshader.cpp deleted file mode 100644 index ab6672e..0000000 --- a/shader/depthoffieldshader.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include - -#include "depthoffieldshader.h" - - -DOFShader::DOFShader(SimpleScene& _scene, Color const &_diffuseColor, int _numSamples, float _aperture, float _focalDistance, float _focalLength, PerspectiveCamera& _camera) : scene(_scene), diffuseColor(_diffuseColor), numSamples(_numSamples), aperture(_aperture), -focalDistance(_focalDistance), focalLength(_focalLength), camera(_camera) {} - -std::random_device DOFShader::rd; -std::mt19937 DOFShader::gen(DOFShader::rd()); - -Color DOFShader::shade(Scene const &scene, Ray const &ray) const { - Color color; - - // Accumulate the light over all light sources - for (const auto &light : scene.lights()) { - Light::Illumination const illum = light->illuminate(scene, ray); - Color const diffuse = this->diffuseColor * std::max(dotProduct(-illum.direction, ray.normal), 0.0f); - // Add the sample color to the final color - color += diffuse * sample(ray, illum); - } - - return color; -} - -Color DOFShader::sample(Ray ray, Light::Illumination const &illum) const { - - std::uniform_real_distribution dis(-1.0, 1.0); - - // calculate the point of focus - Vector3d focusPoint = ray.origin + ray.direction * focalDistance; - - // create a random point on the aperture - Vector3d rnd = Vector3d(dis(gen), dis(gen), 0); - Vector3d offset = aperture * (rnd.x * camera.getRightDirection() + rnd.y * camera.getUpDirection()); - - // create the new ray with the offset point - Vector3d dofRayStart = camera.getPosition() + offset; - Vector3d dofRayDir = normalized(focusPoint - (camera.getPosition() + offset)); - - Ray dofRay = Ray(dofRayStart, dofRayDir); - - // trace the new ray and sample the color - - Color tracedColor = scene.traceRay(dofRay); - return tracedColor; -} diff --git a/shader/depthoffieldshader.h b/shader/depthoffieldshader.h deleted file mode 100644 index d9adeb9..0000000 --- a/shader/depthoffieldshader.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef DEPTHOFFIELDSHADER_H -#define DEPTHOFFIELDSHADER_H - -#include "shader/shader.h" -#include "light/light.h" -#include "camera/perspectivecamera.h" -#include -#include "scene/simplescene.h" - -class DOFShader : public Shader { - -public: - // Constructor / Desctructor - DOFShader(SimpleScene& _scene, Color const &_diffuseColor, int _numSamples, float _aperture, float _focalDistance, float _focalLength, PerspectiveCamera& _camera); - virtual ~DOFShader() = default; - - // Shader functions - virtual Color shade(Scene const &scene, Ray const &ray) const; - -private: - float aperture, focalDistance, focalLength; - int numSamples; - PerspectiveCamera& camera; - SimpleScene& scene; - Color diffuseColor; - static std::random_device rd; - static std::mt19937 gen; - - - Color sample(Ray ray, Light::Illumination const &illum) const; -}; - -#endif \ No newline at end of file