Bloom shader finished
This commit is contained in:
parent
9a8d6bcccd
commit
0d4814c901
5 changed files with 100 additions and 108 deletions
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue