Skip to content

Commit

Permalink
Merge pull request #12 from fszewczyk/denoising
Browse files Browse the repository at this point in the history
Adaptive Sampling
  • Loading branch information
fszewczyk authored Apr 3, 2023
2 parents 57b5eb8 + ab1bf7c commit 6c94d04
Show file tree
Hide file tree
Showing 7 changed files with 459 additions and 380 deletions.
60 changes: 60 additions & 0 deletions src/core/image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,66 @@ void image::writeColor(std::ostream &out, color pixelColor) const {
color &image::operator()(int x, int y) { return m_data[y][x]; }
color &image::at(int x, int y) { return m_data[y][x]; }

std::shared_ptr<image> image::getBlurred(int size) const {
if (size < 3)
throw std::invalid_argument("Image blur size needs to be at least 3.");

if (size % 2 == 0)
throw std::invalid_argument("Image blur size needs to be odd.");

auto blurred = std::make_shared<image>(m_width, m_height);
for (int y = 0; y < m_height; ++y) {
for (int x = 0; x < m_width; ++x) {
int lowerBoundY = std::max(0, y - size / 2);
int lowerBoundX = std::max(0, x - size / 2);
int upperBoundY = std::min(m_height, y + size / 2 + 1);
int upperBoundX = std::min(m_width, x + size / 2 + 1);

color average(0, 0, 0);
int n = 0;

for (int cy = lowerBoundY; cy < upperBoundY; ++cy) {
for (int cx = lowerBoundX; cx < upperBoundX; ++cx) {
average += m_data[cy][cx];
n++;
}
}

average /= n * 255;
blurred->at(x, y) = average;
}
}

return blurred;
}

std::shared_ptr<image> image::getNoiseMap() const {
auto blurred = getBlurred(3);
auto noise = std::make_shared<image>(m_width, m_height);

for (int y = 0; y < m_height; ++y) {
for (int x = 0; x < m_width; ++x) {
double diff = (blurred->at(x, y) - m_data[y][x]).length();
noise->at(x, y) = color(diff, diff, diff);
}
}

return noise;
}

std::vector<std::pair<size_t, size_t>> image::getPixelsAbove(double threshold) const {
std::vector<std::pair<size_t, size_t>> coords;

for (int y = 0; y < m_height; ++y) {
for (int x = 0; x < m_width; ++x) {
if (m_data[y][x].length() > threshold)
coords.push_back({x, y});
}
}

return coords;
}

void image::saveToPng(std::string path) {
char *data = new char[3 * width() * height()];

Expand Down
5 changes: 5 additions & 0 deletions src/core/image.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ class image {
color &operator()(int x, int y);
color &at(int x, int y);

std::shared_ptr<image> getBlurred(int size) const;
std::shared_ptr<image> getNoiseMap() const;

std::vector<std::pair<size_t, size_t>> getPixelsAbove(double threshold) const;

void saveToPng(std::string path);
void saveToJpg(std::string path);

Expand Down
2 changes: 2 additions & 0 deletions src/core/vec3.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ class vec3 {
double y() const;
double z() const;

vec3 absolute();

vec3 operator-() const;
double operator[](int i) const;
double &operator[](int i);
Expand Down
33 changes: 31 additions & 2 deletions src/ui/renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,17 @@ std::shared_ptr<image> renderer::setupImageToExport(exportSettings settings) {
return m_imageToDraw;
}

void renderer::setDenoiseCoordinates(std::vector<std::pair<size_t, size_t>> coords) { m_denoiseCoordinates = coords; }

bool renderer::isDenoising() const { return !m_denoiseCoordinates.empty(); }

bool renderer::isExporting() const { return m_isExporting; }

std::shared_ptr<image> renderer::stopExporting() {
m_imageToDraw = std::make_shared<image>(m_image->width() / SCALING_FACTOR, m_image->height() / SCALING_FACTOR);
m_isExporting = false;
m_cam->setAspectRatio(static_cast<float>(m_imageToDraw->width()) / m_imageToDraw->height());
m_denoiseCoordinates.clear();

return m_image;
}
Expand All @@ -68,6 +73,21 @@ void renderer::renderRow(int y) {
}
}

void renderer::renderCoordinates(std::vector<std::pair<size_t, size_t>> coords) {
for (auto [x, y] : coords) {
auto u = (x + randomDouble()) / (m_imageToDraw->width() - 1);
auto v = ((m_imageToDraw->height() - y) + randomDouble()) / (m_imageToDraw->height() - 1);

ray r = m_cam->getRay(u, v);
color c = rayColor(r, MAXIMUM_RAY_DEPTH);

color result = m_imageToDraw->at(x, y) * (double(m_samplesTaken) / (m_samplesTaken + 1)) +
(1.0 / (m_samplesTaken + 1)) * c;

m_imageToDraw->at(x, y) = clamp(result, 0, 1);
}
}

void renderer::render() {
const int maxDepth = 5;

Expand All @@ -86,8 +106,17 @@ void renderer::render() {
// Whoever reads this, I'm sorry it's done this way. Nothing else
// worked.
std::vector<std::thread> renderingThreads;
for (int y = 0; y < m_imageToDraw->height(); ++y) {
renderingThreads.push_back(std::thread([this, y] { renderRow(y); }));
if (m_denoiseCoordinates.empty()) {
for (int y = 0; y < m_imageToDraw->height(); ++y) {
renderingThreads.push_back(std::thread([this, y] { renderRow(y); }));
}
} else {
for (size_t i = 0; i < m_denoiseCoordinates.size(); i += 100) {
size_t last = std::min(i + 100, m_denoiseCoordinates.size());
std::vector<std::pair<size_t, size_t>> cords(m_denoiseCoordinates.begin() + i,
m_denoiseCoordinates.begin() + last);
renderingThreads.push_back(std::thread([this, cords] { renderCoordinates(cords); }));
}
}

for (auto &t : renderingThreads) {
Expand Down
4 changes: 4 additions & 0 deletions src/ui/renderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class renderer {
bool renderedImage() const;

std::shared_ptr<image> setupImageToExport(exportSettings settings);
void setDenoiseCoordinates(std::vector<std::pair<size_t, size_t>> coords);
bool isDenoising() const;
bool isExporting() const;
std::shared_ptr<image> stopExporting();

Expand All @@ -36,6 +38,7 @@ class renderer {
private:
void render();
void renderRow(int y);
void renderCoordinates(std::vector<std::pair<size_t, size_t>> coords);
void updateScaledImage();

void clearScene();
Expand All @@ -56,6 +59,7 @@ class renderer {
std::thread m_renderingThread;

bool m_isExporting;
std::vector<std::pair<size_t, size_t>> m_denoiseCoordinates;
};

} // namespace shkyera
Expand Down
2 changes: 1 addition & 1 deletion src/ui/settings/exportSettingsWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ exportSettings exportSettingsWindow::render(RENDER_MODE &mode) {
settings.width = std::max(128, setWidth);
settings.height = std::max(128, setHeight);

ImGui::SliderInt("Rays Per Pixel", &settings.raysPerPixel, 10, 200);
ImGui::SliderInt("Rays Per Pixel", &settings.raysPerPixel, 100, 2000);
if (ImGui::IsItemHovered() && !ImGui::IsItemActive()) {
ImGui::BeginTooltip();
ImGui::TextUnformatted("Rays shot out for every pixel.\nThe higher, the "
Expand Down
Loading

0 comments on commit 6c94d04

Please sign in to comment.