Bloom shader finished

This commit is contained in:
m.gaedke 2023-01-25 10:20:27 +01:00
parent 9a8d6bcccd
commit 0d4814c901
5 changed files with 100 additions and 108 deletions

View file

@ -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); }
@ -84,61 +85,11 @@ Color Texture::color(Vector2d const &surfacePosition, bool interpolate) const {
return color(surfacePosition.u, surfacePosition.v, interpolate); return color(surfacePosition.u, surfacePosition.v, interpolate);
} }
void Texture::gaussianBlur(int kernelSize, float sigma) { CImg<float> Texture::getImage() {
CImg<float> kernel = computeGaussianKernel(kernelSize, sigma); return image_;
image_ = convolution(image_, kernel);
} }
// Function to compute Gaussian kernel void Texture::setTexture(CImg<float> image){
CImg<float> Texture::computeGaussianKernel(int kernelSize, float sigma) { image_ = std::move(image);
// 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> Texture::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 Texture::scaleBrightness(float scale) {
image_ *= scale;
}

View file

@ -18,12 +18,6 @@ public:
bool load(char const *fileName); bool load(char const *fileName);
bool save(char const *fileName) const; bool save(char const *fileName) const;
// Gaussian blur function
void gaussianBlur(int kernelSize, float sigma);
// Scale function
void scaleBrightness(float scale);
// 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(); }
@ -32,18 +26,16 @@ public:
// 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 functions
Color color(float u, float v, bool interpolate = true) const; Color color(float u, float v, bool interpolate = true) const;
Color color(Vector2d const &surfacePosition, bool interpolate = true) const; Color color(Vector2d const &surfacePosition, bool interpolate = true) const;
CImg<float> getImage();
private: private:
// Function to compute Gaussian kernel
CImg<float> computeGaussianKernel(int kernelSize, float sigma);
// Function to perform convolution
CImg<float> convolution(CImg<float> &img, CImg<float> &kernel);
CImg<float> image_; CImg<float> image_;
}; };

View file

@ -2,43 +2,87 @@
#include <iostream> #include <iostream>
#include "bloomshader.h" #include "bloomshader.h"
Bloomshader::Bloomshader(Texture image, float threshold, int blurRange) : image(image), threshold(threshold), blurRange(blurRange), Bloomshader::Bloomshader(CImg<float> image) : image(image) {}
thresholdImage(Texture(image.width() + 2 * blurRange, image.height() + 2 * blurRange)) {}
void Bloomshader::thresholdshader() {
for(int i = 0; i < image.width(); i++) { CImg<float> Bloomshader::bloom(float threshold, int kernelSize, float sigma, float intensity) {
for(int j = 0; j < image.height(); j++){ // Apply threshold to image
if(luminance(image.getPixelAt(i, j)) < threshold){ //CImg<float> brightPixels = image_.get_threshold(threshold);
thresholdImage.setPixelAt(i + blurRange, j + blurRange, Color(0, 0, 0)); //brightPixels.save("brightpixels.png");
} else {
thresholdImage.setPixelAt(i + blurRange, j + blurRange, image.getPixelAt(i, j)); // 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;
} }
thresholdImage.save("maskResult.png");
image.save("originalPicture.png");
}
Texture Bloomshader::getimage() {
return image; return image;
} }
void Bloomshader::gaussianBlur(int kernelSize, float sigma) {
CImg<float> kernel = computeGaussianKernel(kernelSize, sigma);
image = convolution(image, kernel);
}
void Bloomshader::bloomshader() { // Function to compute Gaussian kernel
CImg<float> Bloomshader::computeGaussianKernel(int kernelSize, float sigma) {
// Create kernel
CImg<float> kernel(kernelSize, kernelSize, 1, 1);
thresholdImage.gaussianBlur(blurRange * 2, 8.5f); // Compute Gaussian kernel
thresholdImage.scaleBrightness(0.3f); float sum = 0.0f;
int i, j;
thresholdImage.save("blurredMaskResult.png"); for (i = 0; i < kernelSize; i++) {
for (j = 0; j < kernelSize; j++) {
for(int i = 0; i < image.width(); i++) { kernel(i, j) = exp(-0.5f * (pow((i - kernelSize / 2.f) / sigma, 2.f) +
for(int j = 0; j < image.height(); j++){ pow((j - kernelSize / 2.f) / sigma, 2.f))) / (2 * M_PI * sigma * sigma);
Color temp = clamped(image.getPixelAt(i, j) + thresholdImage.getPixelAt(i + blurRange, j + blurRange)); sum += kernel(i, j);
image.setPixelAt(i, j, temp);
} }
} }
// Normalize kernel
kernel /= sum;
return kernel;
} }
float Bloomshader::luminance(Color color) { // Function to perform convolution
return dotProduct(Vector3d(color.r, color.g, color.b), Vector3d(0.2126, 0.7152, 0.0722)); CImg<float> Bloomshader::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 Bloomshader::scaleBrightness(float scale) {
image *= scale;
} }

View file

@ -8,19 +8,19 @@
class Bloomshader { class Bloomshader {
public: public:
Bloomshader(Texture image, float threshold, int blurRange); Bloomshader(CImg<float> image);
void thresholdshader(); CImg<float> bloom(float threshold, int kernelSize, float sigma, float intensity);
Texture getimage();
//void gaussianBlur(int x, int y);
void bloomshader();
float luminance(Color color);
private: private:
Texture image; void scaleBrightness(float scale);
Texture thresholdImage; void gaussianBlur(int kernelSize, float sigma);
float threshold;
int blurRange; CImg<float> convolution(CImg<float> &img, CImg<float> &kernel);
CImg<float> computeGaussianKernel(int kernelSize, float sigma);
CImg<float> image;
}; };

View file

@ -76,10 +76,15 @@ Texture SimpleRenderer::renderImage(Scene const &scene, Camera const &camera, in
// Post-processing // Post-processing
// Bloom shader // Bloom shader
Bloomshader bloomshader = Bloomshader(image, 0.68f, 30); //Bloomshader bloomshader = Bloomshader(image, 0.48f, 10);
bloomshader.thresholdshader(); //bloomshader.thresholdshader();
bloomshader.bloomshader();
image = bloomshader.getimage(); image.save("original.png");
Bloomshader bloomEffect = Bloomshader(image.getImage());
image.setTexture(bloomEffect.bloom(0.55f, 5, 10.0f, 0.06f));
//image = bloomshader.getimage();
return image; return image;
} }