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 <iostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void Texture::gaussianBlur(int kernelSize, float sigma) {
|
||||
CImg<float> kernel = computeGaussianKernel(kernelSize, sigma);
|
||||
image_ = convolution(image_, kernel);
|
||||
CImg<float> Texture::getImage() {
|
||||
return image_;
|
||||
}
|
||||
|
||||
// Function to compute Gaussian kernel
|
||||
CImg<float> Texture::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);
|
||||
}
|
||||
void Texture::setTexture(CImg<float> image){
|
||||
image_ = std::move(image);
|
||||
}
|
||||
|
||||
// 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 save(char const *fileName) const;
|
||||
|
||||
// Gaussian blur function
|
||||
void gaussianBlur(int kernelSize, float sigma);
|
||||
|
||||
// Scale function
|
||||
void scaleBrightness(float scale);
|
||||
|
||||
// Get
|
||||
inline bool isNull() const { return this->image_.is_empty(); }
|
||||
inline int width() const { return this->image_.width(); }
|
||||
|
@ -32,18 +26,16 @@ public:
|
|||
|
||||
// Set
|
||||
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 color(Vector2d const &surfacePosition, bool interpolate = true) const;
|
||||
|
||||
CImg<float> getImage();
|
||||
|
||||
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_;
|
||||
};
|
||||
|
||||
|
|
|
@ -2,43 +2,87 @@
|
|||
#include <iostream>
|
||||
#include "bloomshader.h"
|
||||
|
||||
Bloomshader::Bloomshader(Texture image, float threshold, int blurRange) : image(image), threshold(threshold), blurRange(blurRange),
|
||||
thresholdImage(Texture(image.width() + 2 * blurRange, image.height() + 2 * blurRange)) {}
|
||||
Bloomshader::Bloomshader(CImg<float> image) : image(image) {}
|
||||
|
||||
void Bloomshader::thresholdshader() {
|
||||
for(int i = 0; i < image.width(); i++) {
|
||||
for(int j = 0; j < image.height(); j++){
|
||||
if(luminance(image.getPixelAt(i, j)) < threshold){
|
||||
thresholdImage.setPixelAt(i + blurRange, j + blurRange, Color(0, 0, 0));
|
||||
} else {
|
||||
thresholdImage.setPixelAt(i + blurRange, j + blurRange, image.getPixelAt(i, j));
|
||||
}
|
||||
}
|
||||
}
|
||||
thresholdImage.save("maskResult.png");
|
||||
image.save("originalPicture.png");
|
||||
|
||||
CImg<float> Bloomshader::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;
|
||||
}
|
||||
|
||||
Texture Bloomshader::getimage() {
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
void Bloomshader::bloomshader() {
|
||||
|
||||
thresholdImage.gaussianBlur(blurRange * 2, 8.5f);
|
||||
thresholdImage.scaleBrightness(0.3f);
|
||||
|
||||
thresholdImage.save("blurredMaskResult.png");
|
||||
|
||||
for(int i = 0; i < image.width(); i++) {
|
||||
for(int j = 0; j < image.height(); j++){
|
||||
Color temp = clamped(image.getPixelAt(i, j) + thresholdImage.getPixelAt(i + blurRange, j + blurRange));
|
||||
image.setPixelAt(i, j, temp);
|
||||
}
|
||||
}
|
||||
void Bloomshader::gaussianBlur(int kernelSize, float sigma) {
|
||||
CImg<float> kernel = computeGaussianKernel(kernelSize, sigma);
|
||||
image = convolution(image, kernel);
|
||||
}
|
||||
|
||||
float Bloomshader::luminance(Color color) {
|
||||
return dotProduct(Vector3d(color.r, color.g, color.b), Vector3d(0.2126, 0.7152, 0.0722));
|
||||
// Function to compute Gaussian kernel
|
||||
CImg<float> Bloomshader::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> 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 {
|
||||
|
||||
public:
|
||||
Bloomshader(Texture image, float threshold, int blurRange);
|
||||
void thresholdshader();
|
||||
Texture getimage();
|
||||
//void gaussianBlur(int x, int y);
|
||||
void bloomshader();
|
||||
float luminance(Color color);
|
||||
|
||||
Bloomshader(CImg<float> image);
|
||||
CImg<float> bloom(float threshold, int kernelSize, float sigma, float intensity);
|
||||
|
||||
private:
|
||||
Texture image;
|
||||
Texture thresholdImage;
|
||||
float threshold;
|
||||
int blurRange;
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -76,10 +76,15 @@ Texture SimpleRenderer::renderImage(Scene const &scene, Camera const &camera, in
|
|||
|
||||
// Post-processing
|
||||
// Bloom shader
|
||||
Bloomshader bloomshader = Bloomshader(image, 0.68f, 30);
|
||||
bloomshader.thresholdshader();
|
||||
bloomshader.bloomshader();
|
||||
image = bloomshader.getimage();
|
||||
//Bloomshader bloomshader = Bloomshader(image, 0.48f, 10);
|
||||
//bloomshader.thresholdshader();
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue