summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeuin <[email protected]>2022-04-13 14:42:59 +0800
committerKeuin <[email protected]>2022-04-13 14:42:59 +0800
commit3caba9694f6e6f0f8b51dcffd7619fa04fbe6c29 (patch)
tree0975252facef9f71931dee7bbd526bcfccf49ad4
parent4ad345447384ae9327cab0977b95d0b67f8bde57 (diff)
Antialiasing. (not parallelized)
-rw-r--r--CMakeLists.txt4
-rw-r--r--aa.h48
-rw-r--r--bitmap.h21
-rw-r--r--main_simple_scanner.cpp28
-rw-r--r--viewport.h4
5 files changed, 91 insertions, 14 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 78eeed9..c531ea9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -12,9 +12,9 @@ set(CMAKE_VERBOSE_MAKEFILE on)
# main executable
-add_executable(rt main.cpp vec.h bitmap.h ray.h bitfont.h hitlist.h object.h sphere.h viewport.h)
+add_executable(rt main.cpp vec.h bitmap.h ray.h bitfont.h hitlist.h object.h sphere.h viewport.h aa.h)
add_executable(image_output main_image_output.cpp vec.h bitmap.h bitfont.h hitlist.h object.h sphere.h viewport.h)
-add_executable(simple_scanner main_simple_scanner.cpp vec.h bitmap.h ray.h timer.h bitfont.h hitlist.h object.h sphere.h viewport.h)
+add_executable(simple_scanner main_simple_scanner.cpp vec.h bitmap.h ray.h timer.h bitfont.h hitlist.h object.h sphere.h viewport.h aa.h)
# googletest
diff --git a/aa.h b/aa.h
new file mode 100644
index 0000000..d226fda
--- /dev/null
+++ b/aa.h
@@ -0,0 +1,48 @@
+//
+// Created by Keuin on 2022/4/13.
+//
+
+#ifndef RT_AA_H
+#define RT_AA_H
+
+#include "vec.h"
+#include "viewport.h"
+#include <vector>
+#include <thread>
+
+
+// Antialiasing viewport
+template<typename T>
+class aa_viewport : public viewport<T> {
+ unsigned samples;
+ std::vector<basic_viewport<T>> subviews;
+
+public:
+ aa_viewport(double width, double height, vec3d viewport_center, unsigned samples) : samples(samples) {
+ assert(samples >= 1);
+ subviews = std::vector<basic_viewport<T>>{samples, {width, height, viewport_center}};
+ }
+
+ virtual bitmap<T> render(const hitlist<T> &world, vec3d viewpoint, uint16_t image_width, uint16_t image_height) {
+// // TODO threaded rendering
+// std::vector<std::thread> workers{samples};
+// for (size_t i = 0; i < samples; ++i) {
+// const auto &th = workers[i];
+// const auto &vw = subviews[i];
+// }
+ const auto seed = 123456789012345678ULL;
+ std::mt19937_64 seedgen{seed}; // generates seeds for workers
+ std::vector<bitmap<T>> images{};
+ for (const auto &view: subviews) {
+ bias_ctx bc{seedgen()};
+ images.push_back(view.render(world, viewpoint, image_width, image_height, bc));
+ }
+ return bitmap<T>::average(images);
+ }
+
+};
+
+using aa_viewport8b = aa_viewport<uint8_t>;
+
+
+#endif //RT_AA_H
diff --git a/bitmap.h b/bitmap.h
index bc1205f..8906ec5 100644
--- a/bitmap.h
+++ b/bitmap.h
@@ -9,6 +9,7 @@
#include <cstdint>
#include <ostream>
#include <cassert>
+#include <vector>
#include "bitfont.h"
@@ -87,6 +88,26 @@ public:
content.resize(width * height, pixel<T>{});
}
+ static bitmap<T> average(const std::vector<bitmap<T>> &images) {
+ assert(!images.empty());
+ bitmap<T> result{images[0].width, images[0].height};
+ const auto m = images.size();
+ const auto n = images[0].content.size();
+ uintmax_t acc_r, acc_g, acc_b;
+ for (size_t i = 0; i < n; ++i) {
+ acc_r = 0;
+ acc_g = 0;
+ acc_b = 0;
+ for (size_t j = 0; j < m; ++j) {
+ acc_r += images[j].content[i].r;
+ acc_g += images[j].content[i].g;
+ acc_b += images[j].content[i].b;
+ }
+ result.content[i] = pixel<T>{(T) (acc_r / m), (T) (acc_g / m), (T) (acc_b / m)};
+ }
+ return result;
+ }
+
void set(unsigned x, unsigned y, const pixel<T> &pixel) {
image(x, y) = pixel;
}
diff --git a/main_simple_scanner.cpp b/main_simple_scanner.cpp
index bcec163..eaaa8b7 100644
--- a/main_simple_scanner.cpp
+++ b/main_simple_scanner.cpp
@@ -13,15 +13,21 @@
#include "viewport.h"
#include "hitlist.h"
#include "sphere.h"
+#include "aa.h"
#define DEMO_BALL
void generate_image(uint16_t image_width, uint16_t image_height, double viewport_width, double focal_length,
- double sphere_z, double sphere_r, const std::string &caption = "", unsigned caption_scale = 1) {
+ double sphere_z, double sphere_r, unsigned samples, const std::string &caption = "",
+ unsigned caption_scale = 1) {
+ if (samples == 1) {
+ std::cerr << "Antialiasing is disabled." << std::endl;
+ } else {
+ std::cerr << "Antialiasing Samples: " << samples << std::endl;
+ }
double r = 1.0 * image_width / image_height;
- basic_viewport8b vp{viewport_width, viewport_width / r, vec3d{0, 0, -focal_length}};
+ aa_viewport8b vp{viewport_width, viewport_width / r, vec3d{0, 0, -focal_length}, samples};
hitlist8b world;
- bias_ctx bias{};
world.add_object(std::make_shared<sphere>(
vec3d{0, -100.5, -1},
100)); // the earth
@@ -29,7 +35,7 @@ void generate_image(uint16_t image_width, uint16_t image_height, double viewport
timer tm;
tm.start_measure();
auto image = vp.render(world, vec3d::zero(),
- image_width, image_height, bias); // camera position as the coordinate origin
+ image_width, image_height); // camera position as the coordinate origin
tm.stop_measure();
if (!caption.empty()) {
image.print(caption,
@@ -44,22 +50,24 @@ void generate_image(uint16_t image_width, uint16_t image_height, double viewport
}
int main(int argc, char **argv) {
- if (argc != 7 && argc != 8) {
- printf("Usage: %s <image_width> <image_height> <viewport_width> <focal_length> <sphere_z> <sphere_r>\n",
+ if (argc != 8 && argc != 9) {
+ printf("Usage: %s <image_width> <image_height> <viewport_width> <focal_length> <sphere_z> <sphere_r> <samples> [<caption>]\n",
argv[0]);
return 0;
}
#ifndef NDEBUG
std::cerr << "Notice: assertion is enabled." << std::endl;
#endif
- std::string iw{argv[1]}, ih{argv[2]}, vw{argv[3]}, fl{argv[4]}, sz{argv[5]}, sr{argv[6]}, cap{};
- if (argc == 8) {
+ std::string iw{argv[1]}, ih{argv[2]}, vw{argv[3]}, fl{argv[4]},
+ sz{argv[5]}, sr{argv[6]}, sp{argv[7]}, cap{};
+ if (argc == 9) {
// with caption
- cap = std::string{argv[7]};
+ cap = std::string{argv[8]};
}
const auto image_width = std::stoul(iw);
generate_image(image_width, std::stoul(ih),
std::stod(vw), std::stod(fl),
- std::stod(sz), std::stod(sr), cap,
+ std::stod(sz), std::stod(sr),
+ std::stoul(sp), cap,
std::max((int) (1.0 * image_width * 0.015 / 8), 1));
} \ No newline at end of file
diff --git a/viewport.h b/viewport.h
index 51159c9..b4e4e56 100644
--- a/viewport.h
+++ b/viewport.h
@@ -88,8 +88,8 @@ public:
assert(bx < 1.0);
assert(by < 1.0);
const vec3d off{
- .x=1.0 * i / img_hw * half_width + bx,
- .y=1.0 * j / img_hh * half_height + by,
+ .x=(1.0 * i + bx) / img_hw * half_width,
+ .y=(1.0 * j + by) / img_hh * half_height,
.z=0.0
}; // offset on screen plane
const auto dir = r + off; // direction vector from camera to current pixel on screen