Merge branch 'Bloomshader'
Adding DOFRenderer and postProcessing bloom effect to master
This commit is contained in:
commit
ce1fe4dd9a
12 changed files with 372 additions and 41 deletions
|
@ -24,10 +24,13 @@ file(GLOB primitive_src "primitive/*.cpp")
|
||||||
file(GLOB renderer_src "renderer/*.cpp")
|
file(GLOB renderer_src "renderer/*.cpp")
|
||||||
file(GLOB scene_src "scene/*.cpp")
|
file(GLOB scene_src "scene/*.cpp")
|
||||||
file(GLOB shader_src "shader/*.cpp")
|
file(GLOB shader_src "shader/*.cpp")
|
||||||
|
file(GLOB effect_src "effect/*.cpp")
|
||||||
|
file(GLOB post_processing_src "post_processing/*.cpp")
|
||||||
|
|
||||||
# The tracey library
|
# The tracey library
|
||||||
add_library(tracey STATIC ${common_src} ${noise_src} ${camera_src} ${light_src}
|
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)
|
${primitive_src} ${renderer_src} ${scene_src} ${shader_src} ${effect_src}
|
||||||
|
${post_processing_src})
|
||||||
if(NOT WIN32)
|
if(NOT WIN32)
|
||||||
target_link_libraries(tracey ${CMAKE_THREAD_LIBS_INIT} ${X11_LIBRARIES})
|
target_link_libraries(tracey ${CMAKE_THREAD_LIBS_INIT} ${X11_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
@ -72,6 +75,10 @@ endif()
|
||||||
add_executable(fancy1 fancy1.cpp)
|
add_executable(fancy1 fancy1.cpp)
|
||||||
target_link_libraries(fancy1 tracey)
|
target_link_libraries(fancy1 tracey)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0")
|
||||||
|
|
||||||
|
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,12 @@ public:
|
||||||
|
|
||||||
// Camera functions
|
// Camera functions
|
||||||
virtual Ray createRay(float x, float y) const = 0;
|
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
|
#endif
|
||||||
|
|
|
@ -13,11 +13,6 @@ public:
|
||||||
// Set
|
// Set
|
||||||
void setPosition(Vector3d const &position) { this->position = position; }
|
void setPosition(Vector3d const &position) { this->position = position; }
|
||||||
void setForwardDirection(Vector3d const &forwardDirection) {
|
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));
|
std::tie(this->forwardDirection, this->upDirection, this->rightDirection) = orthoNormalized(forwardDirection, this->upDirection, crossProduct(this->upDirection, forwardDirection));
|
||||||
}
|
}
|
||||||
void setUpDirection(Vector3d const &upDirection) {
|
void setUpDirection(Vector3d const &upDirection) {
|
||||||
|
@ -36,6 +31,12 @@ public:
|
||||||
// Camera functions
|
// Camera functions
|
||||||
Ray createRay(float x, float y) const override;
|
Ray createRay(float x, float y) const override;
|
||||||
|
|
||||||
|
//Getter
|
||||||
|
Vector3d getPosition() const override { return position; }
|
||||||
|
Vector3d getRightDirection() const override{ return rightDirection; }
|
||||||
|
Vector3d getUpDirection() const override { return upDirection; }
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Vector3d position;
|
Vector3d position;
|
||||||
Vector3d forwardDirection;
|
Vector3d forwardDirection;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
Texture::Texture(int width, int height) { this->resize(width, height); }
|
Texture::Texture(int width, int height) { this->resize(width, height); }
|
||||||
|
|
||||||
|
@ -83,3 +84,12 @@ Color Texture::color(float u, float v, bool interpolate) const {
|
||||||
Color Texture::color(Vector2d const &surfacePosition, bool interpolate) const {
|
Color Texture::color(Vector2d const &surfacePosition, bool interpolate) const {
|
||||||
return color(surfacePosition.u, surfacePosition.v, interpolate);
|
return color(surfacePosition.u, surfacePosition.v, interpolate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CImg<float> Texture::getImage() {
|
||||||
|
return image_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Texture::setTexture(CImg<float> image){
|
||||||
|
image_ = std::move(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,30 +9,34 @@ using namespace cimg_library;
|
||||||
|
|
||||||
class Texture {
|
class Texture {
|
||||||
public:
|
public:
|
||||||
// Constructor
|
// Constructor
|
||||||
Texture(int width, int height);
|
Texture(int width, int height);
|
||||||
Texture(char const *fileName);
|
Texture(char const *fileName);
|
||||||
|
|
||||||
// Image functions
|
// Image functions
|
||||||
inline void resize(int width, int height) { this->image_.resize(width, height, 1, 3); }
|
inline void resize(int width, int height) { this->image_.resize(width, height, 1, 3); }
|
||||||
bool load(char const *fileName);
|
bool load(char const *fileName);
|
||||||
bool save(char const *fileName) const;
|
bool save(char const *fileName) const;
|
||||||
|
|
||||||
// Get
|
// Get
|
||||||
inline bool isNull() const { return this->image_.is_empty(); }
|
inline bool isNull() const { return this->image_.is_empty(); }
|
||||||
inline int width() const { return this->image_.width(); }
|
inline int width() const { return this->image_.width(); }
|
||||||
inline int height() const { return this->image_.height(); }
|
inline int height() const { return this->image_.height(); }
|
||||||
Color getPixelAt(int x, int y) const;
|
Color getPixelAt(int x, int y) const;
|
||||||
|
|
||||||
// Set
|
// Set
|
||||||
void setPixelAt(int x, int y, Color const &color);
|
void setPixelAt(int x, int y, Color const &color);
|
||||||
|
void setTexture(CImg<float> image);
|
||||||
|
|
||||||
// Color functions
|
|
||||||
Color color(float u, float v, bool interpolate = true) const;
|
// Color functions
|
||||||
Color color(Vector2d const &surfacePosition, bool interpolate = true) const;
|
Color color(float u, float v, bool interpolate = true) const;
|
||||||
|
Color color(Vector2d const &surfacePosition, bool interpolate = true) const;
|
||||||
|
|
||||||
|
CImg<float> getImage();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CImg<float> image_;
|
CImg<float> image_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
46
ex4.cpp
46
ex4.cpp
|
@ -16,6 +16,7 @@
|
||||||
#include "shader/mirrorshader.h"
|
#include "shader/mirrorshader.h"
|
||||||
#include "shader/phongshader.h"
|
#include "shader/phongshader.h"
|
||||||
#include "shader/cooktorranceshader.h"
|
#include "shader/cooktorranceshader.h"
|
||||||
|
#include "renderer/depthoffieldrenderer.h"
|
||||||
|
|
||||||
#include "light/ambientlight.h"
|
#include "light/ambientlight.h"
|
||||||
#include "light/pointlight.h"
|
#include "light/pointlight.h"
|
||||||
|
@ -25,6 +26,13 @@ int main() {
|
||||||
// Let's create a simple scene...
|
// Let's create a simple scene...
|
||||||
SimpleScene scene;
|
SimpleScene scene;
|
||||||
|
|
||||||
|
// Set up the camera
|
||||||
|
PerspectiveCamera camera;
|
||||||
|
camera.setFovAngle(90.0f);
|
||||||
|
camera.setPosition(Vector3d(0.0f, 0.0f, -10.0f));
|
||||||
|
camera.setForwardDirection(Vector3d(0.0f, 0.0f, 1.0f));
|
||||||
|
camera.setUpDirection(Vector3d(0.0f, 1.0f, 0.0f));
|
||||||
|
|
||||||
// Add shaders
|
// Add shaders
|
||||||
auto mirror = std::make_shared<MirrorShader>();
|
auto mirror = std::make_shared<MirrorShader>();
|
||||||
auto white = std::make_shared<LambertShader>(Color(0.9f, 0.9f, 0.9f));
|
auto white = std::make_shared<LambertShader>(Color(0.9f, 0.9f, 0.9f));
|
||||||
|
@ -32,11 +40,16 @@ int main() {
|
||||||
auto blue = std::make_shared<LambertShader>(Color(0.2f, 0.3f, 1.0f));
|
auto blue = std::make_shared<LambertShader>(Color(0.2f, 0.3f, 1.0f));
|
||||||
auto orange = std::make_shared<PhongShader>(Color(1.0f, 0.64f, 0.0f), 1.0f, Color(1.0f, 1.0f, 1.0f), 1.0f, 25.0f);
|
auto orange = std::make_shared<PhongShader>(Color(1.0f, 0.64f, 0.0f), 1.0f, Color(1.0f, 1.0f, 1.0f), 1.0f, 25.0f);
|
||||||
auto gold= std::make_shared<CookTorranceShader>(Color(0.83f, 0.69f, 0.22f), Color(1.0f, 1.0f, 0.0f), 1.2f, 0.2f);
|
auto gold= std::make_shared<CookTorranceShader>(Color(0.83f, 0.69f, 0.22f), Color(1.0f, 1.0f, 0.0f), 1.2f, 0.2f);
|
||||||
auto blueMetallic = std::make_shared<BrdfShader>("data/blue-metallic-paint.binary", Color(7.0f, 7.0f, 7.0f));
|
auto blueMetallic = std::make_shared<BrdfShader>("../data/blue-metallic-paint.binary", Color(7.0f, 7.0f, 7.0f));
|
||||||
auto darkRed = std::make_shared<BrdfShader>("data/dark-red-paint.binary", Color(7.0f, 7.0f, 7.0f));
|
auto darkRed = std::make_shared<BrdfShader>("../data/dark-red-paint.binary", Color(7.0f, 7.0f, 7.0f));
|
||||||
|
|
||||||
|
// DOF Shader
|
||||||
|
bool dofShader = true;
|
||||||
|
|
||||||
|
|
||||||
// Set up the walls
|
// Set up the walls
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
scene.add(std::make_shared<InfinitePlane>(Vector3d(0.0f, 0.0f, +5.0f), Vector3d(0.0f, 0.0f, -1.0f), mirror));
|
scene.add(std::make_shared<InfinitePlane>(Vector3d(0.0f, 0.0f, +5.0f), Vector3d(0.0f, 0.0f, -1.0f), mirror));
|
||||||
|
|
||||||
scene.add(std::make_shared<InfinitePlane>(Vector3d(0.0f, 0.0f, -5.0f), Vector3d(0.0f, 0.0f, +1.0f), mirror));
|
scene.add(std::make_shared<InfinitePlane>(Vector3d(0.0f, 0.0f, -5.0f), Vector3d(0.0f, 0.0f, +1.0f), mirror));
|
||||||
|
@ -48,27 +61,34 @@ int main() {
|
||||||
scene.add(std::make_shared<Sphere>(Vector3d(-3.0f, 0.0f, 0.0f), 1.0f, blueMetallic));
|
scene.add(std::make_shared<Sphere>(Vector3d(-3.0f, 0.0f, 0.0f), 1.0f, blueMetallic));
|
||||||
scene.add(std::make_shared<Sphere>(Vector3d(0.0f, 2.0f, 0.0f), 1.0f, orange));
|
scene.add(std::make_shared<Sphere>(Vector3d(0.0f, 2.0f, 0.0f), 1.0f, orange));
|
||||||
scene.add(std::make_shared<Sphere>(Vector3d(3.0f, 0.0f, 0.0f), 1.0f, darkRed));
|
scene.add(std::make_shared<Sphere>(Vector3d(3.0f, 0.0f, 0.0f), 1.0f, darkRed));
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(-3.0f, -3.3f, -4.0f), 1.0f, mirror));
|
||||||
|
|
||||||
// Add the teapot
|
// Add the teapot
|
||||||
auto teapot = std::make_shared<ObjModel>(gold);
|
auto teapot = std::make_shared<ObjModel>(gold);
|
||||||
teapot->loadObj("data/teapot.obj", Vector3d(3.0f, 3.0f, 3.0f), Vector3d(0.0f, -5.0f, 0.0f));
|
teapot->loadObj("../data/teapot.obj", Vector3d(3.0f, 3.0f, 3.0f), Vector3d(0.0f, -5.0f, 0.0f));
|
||||||
scene.add(teapot);
|
scene.add(teapot);
|
||||||
|
|
||||||
// Add ambient light
|
// Add ambient light
|
||||||
scene.add(std::make_shared<AmbientLight>(0.15f));
|
scene.add(std::make_shared<AmbientLight>(0.15f));
|
||||||
scene.add(std::make_shared<PointLight>(Vector3d(0.0f, 4.0f, -4.0f), 15.0f));
|
//scene.add(std::make_shared<PointLight>(Vector3d(0.0f, 4.0f, -4.0f), 15.0f));
|
||||||
scene.add(std::make_shared<PointLight>(Vector3d(0.0f, 4.0f, 4.0f), 15.0f));
|
scene.add(std::make_shared<PointLight>(Vector3d(0.0f, 2.5f, -4.0f), 7.0f));
|
||||||
|
|
||||||
|
|
||||||
// Set up the camera
|
|
||||||
PerspectiveCamera camera;
|
|
||||||
camera.setFovAngle(90.0f);
|
|
||||||
camera.setPosition(Vector3d(0.0f, 0.0f, -10.0f));
|
|
||||||
camera.setForwardDirection(Vector3d(0.0f, 0.0f, 1.0f));
|
|
||||||
camera.setUpDirection(Vector3d(0.0f, 1.0f, 0.0f));
|
|
||||||
|
|
||||||
// Render the scene
|
// Render the scene
|
||||||
SimpleRenderer renderer;
|
// SimpleRenderer renderer;
|
||||||
renderer.renderImage(scene, camera, 512, 512).save("result.png");
|
// 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
88
post_processing/bloom.cpp
Normal file
88
post_processing/bloom.cpp
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include "bloom.h"
|
||||||
|
|
||||||
|
Bloom::Bloom(CImg<float> image) : image(image) {}
|
||||||
|
|
||||||
|
|
||||||
|
CImg<float> Bloom::bloom(float threshold, int kernelSize, float sigma, float intensity) {
|
||||||
|
// Apply threshold to image
|
||||||
|
//CImg<float> brightPixels = image_.get_threshold(threshold);
|
||||||
|
//brightPixels.save("brightpixels.png");
|
||||||
|
|
||||||
|
// Apply gaussian blur to bright pixels
|
||||||
|
CImg<float> kernel = computeGaussianKernel(kernelSize, sigma);
|
||||||
|
CImg<float> blurred = convolution(image, kernel);
|
||||||
|
for(int i = 0; i < 3; i++){
|
||||||
|
kernel = computeGaussianKernel(kernelSize, sigma);
|
||||||
|
blurred = convolution(image, kernel);
|
||||||
|
blurred *= intensity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add blurred image back to original image
|
||||||
|
cimg_forXYC(image, x, y, c) {
|
||||||
|
float value = image(x,y,0,c) + blurred(x,y,0,c);
|
||||||
|
image(x,y,0,c) = (value > 1.0f) ? 1.0f : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bloom::gaussianBlur(int kernelSize, float sigma) {
|
||||||
|
CImg<float> kernel = computeGaussianKernel(kernelSize, sigma);
|
||||||
|
image = convolution(image, kernel);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to compute Gaussian kernel
|
||||||
|
CImg<float> Bloom::computeGaussianKernel(int kernelSize, float sigma) {
|
||||||
|
// Create kernel
|
||||||
|
CImg<float> kernel(kernelSize, kernelSize, 1, 1);
|
||||||
|
|
||||||
|
// Compute Gaussian kernel
|
||||||
|
float sum = 0.0f;
|
||||||
|
int i, j;
|
||||||
|
for (i = 0; i < kernelSize; i++) {
|
||||||
|
for (j = 0; j < kernelSize; j++) {
|
||||||
|
kernel(i, j) = exp(-0.5f * (pow((i - kernelSize / 2.f) / sigma, 2.f) +
|
||||||
|
pow((j - kernelSize / 2.f) / sigma, 2.f))) / (2 * M_PI * sigma * sigma);
|
||||||
|
sum += kernel(i, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize kernel
|
||||||
|
kernel /= sum;
|
||||||
|
|
||||||
|
return kernel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to perform convolution
|
||||||
|
CImg<float> Bloom::convolution(CImg<float> &img, CImg<float> &kernel) {
|
||||||
|
int kernelSize = kernel.width();
|
||||||
|
int imgRows = img.height();
|
||||||
|
int imgCols = img.width();
|
||||||
|
CImg<float> result(imgCols, imgRows, 1, 3);
|
||||||
|
float sum;
|
||||||
|
int i, j, m, n;
|
||||||
|
int kernelRadius = kernelSize / 2;
|
||||||
|
|
||||||
|
// Perform convolution
|
||||||
|
cimg_forXYC(img, i, j, c) {
|
||||||
|
sum = 0;
|
||||||
|
cimg_forY(kernel, m) {
|
||||||
|
cimg_forX(kernel, n) {
|
||||||
|
int x = i + n - kernelRadius;
|
||||||
|
int y = j + m - kernelRadius;
|
||||||
|
if(x >= 0 && x < imgCols && y >= 0 && y < imgRows){
|
||||||
|
sum += img(x, y, 0, c) * kernel(n, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result(i, j, 0, c) = sum;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bloom::scaleBrightness(float scale) {
|
||||||
|
image *= scale;
|
||||||
|
}
|
27
post_processing/bloom.h
Normal file
27
post_processing/bloom.h
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
|
||||||
|
#ifndef CG1_TRACER_BLOOM_H
|
||||||
|
#define CG1_TRACER_BLOOM_H
|
||||||
|
|
||||||
|
#include "common/texture.h"
|
||||||
|
#include "common/vector3d.h"
|
||||||
|
|
||||||
|
class Bloom {
|
||||||
|
|
||||||
|
public:
|
||||||
|
Bloom(CImg<float> image);
|
||||||
|
CImg<float> bloom(float threshold, int kernelSize, float sigma, float intensity);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void scaleBrightness(float scale);
|
||||||
|
void gaussianBlur(int kernelSize, float sigma);
|
||||||
|
|
||||||
|
CImg<float> convolution(CImg<float> &img, CImg<float> &kernel);
|
||||||
|
CImg<float> computeGaussianKernel(int kernelSize, float sigma);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
CImg<float> image;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //CG1_TRACER_BLOOM_H
|
124
renderer/depthoffieldrenderer.cpp
Normal file
124
renderer/depthoffieldrenderer.cpp
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
#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;
|
||||||
|
}
|
35
renderer/depthoffieldrenderer.h
Normal file
35
renderer/depthoffieldrenderer.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#ifndef DEPTHOFFIELDSHADER_H
|
||||||
|
#define DEPTHOFFIELDSHADER_H
|
||||||
|
|
||||||
|
#include "camera/camera.h"
|
||||||
|
#include <random>
|
||||||
|
#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<int> *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
|
|
@ -5,6 +5,7 @@
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
#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<int> *k, int const stepSize) {
|
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<int> *k, int const stepSize) {
|
||||||
float const aspectRatio = static_cast<float>(height) / width;
|
float const aspectRatio = static_cast<float>(height) / width;
|
||||||
|
@ -73,6 +74,13 @@ Texture SimpleRenderer::renderImage(Scene const &scene, Camera const &camera, in
|
||||||
std::cout << "Paths: " << rays << std::endl;
|
std::cout << "Paths: " << rays << std::endl;
|
||||||
std::cout << "Paths per second: " << std::fixed << std::setprecision(0) << rays / seconds << 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;
|
return image;
|
||||||
}
|
}
|
|
@ -3,11 +3,12 @@
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include "renderer/renderer.h"
|
#include "renderer/renderer.h"
|
||||||
|
#include <renderer/depthoffieldrenderer.h>
|
||||||
|
|
||||||
class SimpleRenderer : public Renderer {
|
class SimpleRenderer : public Renderer {
|
||||||
static void renderThread(const Scene *scene, Camera const *camera, Texture *image, int width, int widthStep,
|
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<int> *k,
|
int widthOffset, int height, int heightStep, int heightOffset, std::atomic<int> *k,
|
||||||
int const stepSize);
|
const int stepSize);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructor / Destructor
|
// Constructor / Destructor
|
||||||
|
|
Loading…
Reference in a new issue