aboutsummaryrefslogtreecommitdiff
path: root/src/aliasing
diff options
context:
space:
mode:
authorsotech117 <michael_foiani@brown.edu>2023-12-07 16:23:20 -0500
committersotech117 <michael_foiani@brown.edu>2023-12-07 16:23:20 -0500
commitcaa765bff49d54217b75aaf0e7acf4e5392a11e4 (patch)
tree9b92914dfb88b99599e8e60e4512e9e9ea9a25db /src/aliasing
parenta9274459443f1d560d7580a162deb581549980cb (diff)
upload base code
Diffstat (limited to 'src/aliasing')
-rw-r--r--src/aliasing/filter.cpp114
-rw-r--r--src/aliasing/supersample.cpp119
2 files changed, 233 insertions, 0 deletions
diff --git a/src/aliasing/filter.cpp b/src/aliasing/filter.cpp
new file mode 100644
index 0000000..1732dc4
--- /dev/null
+++ b/src/aliasing/filter.cpp
@@ -0,0 +1,114 @@
+#include "raytracer/raytracer.h"
+
+/**
+ * Extra credit.
+ * Code from filter project to offer antialiasing.
+ * FilterBlur at bottom of file used in raytracer.
+ */
+
+enum KERNEL_CHANNEL {
+ RED,
+ GREEN,
+ BLUE,
+ NONE=-1,
+};
+
+struct Kernel1D {
+ std::function<double(double, KERNEL_CHANNEL)> getWeight;
+ double radius;
+};
+
+enum CONVOLVE_DIRECTION {
+ HORIZONTAL,
+ VERTICAL
+};
+
+RGBA getPixelWrapped(std::vector<RGBA> &data, int width, int height, int x, int y) {
+ int newX = (x < 0) ? x + width : x % width;
+ int newY = (y < 0) ? y + height : y % height;
+ return data[width * newY + newX];
+}
+
+std::uint8_t floatToUint8(float x) {
+ x = std::min(255.f, x);
+ return round(x * 255.f);
+}
+
+std::vector<RGBA> convolve1D(std::vector<RGBA> data, int width, int height, Kernel1D kernel, CONVOLVE_DIRECTION direction) {
+ // need to assign then set, since the direction could be either way
+ std::vector<RGBA> result;
+ result.assign(width*height, RGBA{0, 0, 0, 255});
+
+ // get the order of the for loop, based on the bound
+ int outerBound = direction == CONVOLVE_DIRECTION::HORIZONTAL ? height : width;
+ int innerBound = direction == CONVOLVE_DIRECTION::HORIZONTAL ? width : height;
+
+ for (int i = 0; i < outerBound; i++) {
+ for (int j = 0; j < innerBound; j++) {
+ float redAcc = 0.f, greenAcc = 0.f, blueAcc = 0.f;
+ for (int k = -kernel.radius; k <= kernel.radius; k++) {
+ // get the weight for each channel, at this kernel index
+ double rWeight = kernel.getWeight(k, KERNEL_CHANNEL::RED);
+ double gWeight = kernel.getWeight(k, KERNEL_CHANNEL::GREEN);
+ double bWeight = kernel.getWeight(k, KERNEL_CHANNEL::BLUE);
+
+ // determine the pixel location on the canvas
+ int pixelX = direction == CONVOLVE_DIRECTION::HORIZONTAL ? j + k : i;
+ int pixelY = direction == CONVOLVE_DIRECTION::HORIZONTAL ? i : j + k;
+
+ // get the pixel to compute this inner index of convolution.
+ // if out of bounds, get the wrapped
+ RGBA pixel;
+ if (pixelX < 0 || pixelX >= width || pixelY < 0 || pixelY >= height)
+ pixel = getPixelWrapped(data, width, height, pixelX, pixelY);
+ else
+ pixel = data.at(width * pixelY + pixelX);
+
+ // sum the weights on each channel
+ redAcc += rWeight * pixel.r/255.f;
+ greenAcc += gWeight * pixel.g/255.f;
+ blueAcc += bWeight * pixel.b/255.f;
+ }
+
+ // get location then set the pixel into the result
+ int pixelOnCanvas = direction == CONVOLVE_DIRECTION::HORIZONTAL ? width * i + j : width * j + i;
+ result[pixelOnCanvas] = RGBA{floatToUint8(redAcc), floatToUint8(greenAcc), floatToUint8(blueAcc), 255};
+ }
+ }
+
+ return result;
+}
+
+double triangleFilter(double x, double a) {
+ double radius;
+ if (a < 1) {
+ radius = 1/a;
+ } else {
+ radius = 1;
+ }
+
+ if (x < -radius || x > radius)
+ return 0;
+
+ return (1 - std::fabs(x)/radius) / radius;
+}
+
+void RayTracer::filterBlur(RGBA *imageData, int width, int height, float blurRadius) {
+ // make triangle filter
+ // note: 1/blurRadius for the "radius" of the filter will normalize the area under it to 1
+ Kernel1D triangleKernel;
+ triangleKernel.radius = blurRadius;
+ triangleKernel.getWeight = [blurRadius](double x, int c) { return triangleFilter(x, 1/blurRadius); };
+
+ std::vector<RGBA> data{};
+ for (int i = 0; i < width*height; i++) {
+ data.push_back(imageData[i]);
+ }
+
+ std::vector<RGBA> res = convolve1D(data, width, height, triangleKernel, HORIZONTAL);
+ res = convolve1D(res, width,height, triangleKernel, VERTICAL);
+
+ for (int i = 0; i < res.size(); i++) {
+ imageData[i] = res[i];
+ }
+}
diff --git a/src/aliasing/supersample.cpp b/src/aliasing/supersample.cpp
new file mode 100644
index 0000000..aa8e9d3
--- /dev/null
+++ b/src/aliasing/supersample.cpp
@@ -0,0 +1,119 @@
+#include "raytracer/raytracer.h"
+
+/**
+ * Extra credit -> Super Sampling
+ */
+
+const float SUPERSAMPLE_DISTANCE_FROM_CENTER = .25f; // note: max of .5f, unless overlapping with other pixels
+bool SUPER_SAMPLE = false;
+bool ADAPTIVE_SUPER_SAMPLING = false;
+
+RGBA RayTracer::superSample(
+ glm::vec4 eyeCamera,
+ glm::vec4 pixelDirCamera,
+ const RayTraceScene &scene) {
+ // get the color value at value between center and four corners
+ float x_delta = SUPERSAMPLE_DISTANCE_FROM_CENTER / (scene.width());
+ float y_delta = SUPERSAMPLE_DISTANCE_FROM_CENTER / (scene.height());
+ // TL == TOP LEFT
+ // BR = BOTTOM RIGHT, not Battle Royale :)
+ glm::vec4 pixelTL = getPixelFromRay(
+ eyeCamera,
+ glm::vec4(pixelDirCamera.x - x_delta, pixelDirCamera.y - y_delta, pixelDirCamera.z, 0.f),
+ scene);
+ glm::vec4 pixelTR = getPixelFromRay(
+ eyeCamera,
+ glm::vec4(pixelDirCamera.x + x_delta, pixelDirCamera.y - y_delta, pixelDirCamera.z, 0.f),
+ scene);
+ glm::vec4 pixelBL = getPixelFromRay(
+ eyeCamera,
+ glm::vec4(pixelDirCamera.x - x_delta, pixelDirCamera.y + y_delta, pixelDirCamera.z, 0.f),
+ scene);
+ glm::vec4 pixelBR = getPixelFromRay(
+ eyeCamera,
+ glm::vec4(pixelDirCamera.x + x_delta, pixelDirCamera.y + y_delta, pixelDirCamera.z, 0.f),
+ scene);
+
+ if (!ADAPTIVE_SUPER_SAMPLING) {
+ return toRGBA((pixelTL + pixelTR + pixelBL + pixelBR) / 4.f);
+ }
+
+ // ADAPTIVE SUPER SAMPLING
+ // make the region from the center of pixel smaller until we hit something
+ RGBA nohit = {0, 0, 0, 0}; // just here to say that a is 0 if no hit...
+ float TRAVERSE_DISTANCE = .025f;
+ float num_pixels = 4.f;
+ if (pixelTL.a == 0) {
+ num_pixels--;
+ float smallerDist = SUPERSAMPLE_DISTANCE_FROM_CENTER - TRAVERSE_DISTANCE;
+ while (smallerDist < TRAVERSE_DISTANCE) {
+ float x_delta = smallerDist / (scene.width());
+ float y_delta = smallerDist / (scene.height());
+ pixelTL = getPixelFromRay(
+ eyeCamera,
+ glm::vec4(pixelDirCamera.x - x_delta, pixelDirCamera.y - y_delta, pixelDirCamera.z, 0.f),
+ scene);
+ if (pixelTL.a != 0) {
+ num_pixels++;
+ break;
+ }
+ smallerDist -= TRAVERSE_DISTANCE;
+ }
+ }
+ if (pixelTR.a == 0) {
+ num_pixels--;
+ float smallerDist = SUPERSAMPLE_DISTANCE_FROM_CENTER - TRAVERSE_DISTANCE;
+ while (smallerDist < TRAVERSE_DISTANCE) {
+ float x_delta = smallerDist / (scene.width());
+ float y_delta = smallerDist / (scene.height());
+ pixelTR = getPixelFromRay(
+ eyeCamera,
+ glm::vec4(pixelDirCamera.x - x_delta, pixelDirCamera.y - y_delta, pixelDirCamera.z, 0.f),
+ scene);
+ if (pixelTR.a != 0) {
+ num_pixels += 1;
+ break;
+ }
+ smallerDist -= TRAVERSE_DISTANCE;
+ }
+ }
+ if (pixelBL.a == 0) {
+ num_pixels--;
+ float smallerDist = SUPERSAMPLE_DISTANCE_FROM_CENTER - TRAVERSE_DISTANCE;
+ while (smallerDist < TRAVERSE_DISTANCE) {
+ float x_delta = smallerDist / (scene.width());
+ float y_delta = smallerDist / (scene.height());
+ pixelBL = getPixelFromRay(
+ eyeCamera,
+ glm::vec4(pixelDirCamera.x - x_delta, pixelDirCamera.y - y_delta, pixelDirCamera.z, 0.f),
+ scene);
+ if (pixelBL.a != 0) {
+ num_pixels += 1;
+ break;
+ }
+ smallerDist -= TRAVERSE_DISTANCE;
+ }
+ }
+ if (pixelBR.a == 0) {
+ num_pixels--;
+ float smallerDist = SUPERSAMPLE_DISTANCE_FROM_CENTER - TRAVERSE_DISTANCE;
+ while (smallerDist < TRAVERSE_DISTANCE) {
+ float x_delta = smallerDist / (scene.width());
+ float y_delta = smallerDist / (scene.height());
+ pixelBR = getPixelFromRay(
+ eyeCamera,
+ glm::vec4(pixelDirCamera.x - x_delta, pixelDirCamera.y - y_delta, pixelDirCamera.z, 0.f),
+ scene);
+ if (pixelBR.a != 0) {
+ num_pixels += 1;
+ break;
+ }
+ smallerDist -= TRAVERSE_DISTANCE;
+ }
+ }
+
+ if (num_pixels == 0.f) {
+ return nohit;
+ }
+ return toRGBA((pixelTL + pixelTR + pixelBL + pixelBR) / num_pixels);
+}