From b510e1d4d0b5e8960e57631c19ebc838ee533381 Mon Sep 17 00:00:00 2001 From: vonhyou Date: Sun, 17 Mar 2024 23:52:33 -0400 Subject: [PATCH 01/27] fix typo and var names --- src/RayTracer.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/RayTracer.cc b/src/RayTracer.cc index 1209fae..bdd3e3a 100644 --- a/src/RayTracer.cc +++ b/src/RayTracer.cc @@ -45,14 +45,14 @@ void RayTracer::render() { Vector3f cameraPos = Scene::current->center(); Vector3f lookAt = Scene::current->lookAt(); float vpHeight = - 2 * tan(Scene ::current->fov() / 180 * M_PI / 2) * lookAt.norm(); + 2 * tan(Scene::current->fov() / 180 * M_PI / 2) * lookAt.norm(); float vpWidth = vpHeight * width / height; - Vector3f vpU = Vector3f(vpWidth, 0, 0); - Vector3f vpV = Vector3f(0, -vpHeight, 0); - Vector3f du = vpU / width; - Vector3f dv = vpV / height; + Vector3f u = Vector3f(vpWidth, 0, 0); + Vector3f v = Vector3f(0, -vpHeight, 0); + Vector3f du = u / width; + Vector3f dv = v / height; - Vector3f vpUpperLeft = cameraPos + lookAt - vpU / 2.0 - vpV / 2.0; + Vector3f vpUpperLeft = cameraPos + lookAt - u / 2.0 - v / 2.0; Vector3f pxUpperLeft = vpUpperLeft + (du + dv) / 2.0; Output::current = new Output(Scene::current->backgroundColor(), From 2efe817cd7100e7d36da204e6e2f4090c78ab22b Mon Sep 17 00:00:00 2001 From: vonhyou Date: Sun, 17 Mar 2024 23:59:10 -0400 Subject: [PATCH 02/27] delete unused codes --- src/RayTracer.cc | 6 ------ src/RayTracer.h | 1 - 2 files changed, 7 deletions(-) diff --git a/src/RayTracer.cc b/src/RayTracer.cc index bdd3e3a..575585b 100644 --- a/src/RayTracer.cc +++ b/src/RayTracer.cc @@ -1,5 +1,4 @@ #include "RayTracer.h" -#include "../external/simpleppm.h" #include "HitRecord.h" #include "Output.h" #include "Parser.h" @@ -76,11 +75,6 @@ void RayTracer::render() { } } -void RayTracer::output() { - for (auto output : outputs) - output->write(); -} - void RayTracer::run() { parse(); diff --git a/src/RayTracer.h b/src/RayTracer.h index 764bd05..7660665 100644 --- a/src/RayTracer.h +++ b/src/RayTracer.h @@ -24,7 +24,6 @@ private: void parse(); void calculateColor(const HitRecord &, int); void render(); - void output(); }; #endif // !RAY_TRACER_H_ From 4d4c257ef1f8fa7c58d8911e9fd36051732e533d Mon Sep 17 00:00:00 2001 From: vonhyou Date: Mon, 18 Mar 2024 00:15:21 -0400 Subject: [PATCH 03/27] add rays per pixel --- src/RayTracer.cc | 45 ++++++++++++++++++++++++++++++--------------- src/Scene.cc | 2 ++ src/Scene.h | 1 + 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/RayTracer.cc b/src/RayTracer.cc index 575585b..69c55b1 100644 --- a/src/RayTracer.cc +++ b/src/RayTracer.cc @@ -6,6 +6,7 @@ #include #include +#include #include using std::priority_queue; @@ -57,22 +58,36 @@ void RayTracer::render() { Output::current = new Output(Scene::current->backgroundColor(), Scene::current->name(), width, height); - for (int y = 0; y < height; ++y) - for (int x = 0; x < width; ++x) { - Ray ray = getRay(x, y, cameraPos, pxUpperLeft, du, dv); - priority_queue records; - for (auto g : geometries) { - Optional t = g->intersect(ray); - if (t.hasValue()) - records.push(HitRecord(t.value(), ray, g)); - } + int gridWidth = 1, gridHeight = 1, rpp = 1; + Eigen::VectorXi raysPerPixel = Scene::current->raysPerPixel(); - if (!records.empty()) { - HitRecord hit = records.top(); - hit.calcNormal(); - calculateColor(hit, y * width + x); - } - } + if (raysPerPixel.size() == 2) { + gridWidth = gridHeight = raysPerPixel.x(); + rpp = raysPerPixel.y(); + } else if (raysPerPixel.size() == 3) { + gridWidth = raysPerPixel.x(); + gridHeight = raysPerPixel.y(); + rpp = raysPerPixel.z(); + } + + for (int y = 0; y < height; ++y) + for (int x = 0; x < width; ++x) + for (int j = 0; j < gridHeight; ++j) + for (int i = 0; i < gridWidth; ++i) { + Ray ray = getRay(x, y, cameraPos, pxUpperLeft, du, dv); + priority_queue records; + for (auto g : geometries) { + Optional t = g->intersect(ray); + if (t.hasValue()) + records.push(HitRecord(t.value(), ray, g)); + } + + if (!records.empty()) { + HitRecord hit = records.top(); + hit.calcNormal(); + calculateColor(hit, y * width + x); + } + } } void RayTracer::run() { diff --git a/src/Scene.cc b/src/Scene.cc index f9d9840..b51ee11 100644 --- a/src/Scene.cc +++ b/src/Scene.cc @@ -10,6 +10,8 @@ int Scene::height() { return height_; } float Scene::fov() { return fov_; } +Eigen::VectorXi Scene::raysPerPixel() const { return raysPerPixel_; } + Vector3f Scene::ai() const { return ai_; } Vector3f Scene::center() const { return center_; } diff --git a/src/Scene.h b/src/Scene.h index 6775ac2..89eb9d2 100644 --- a/src/Scene.h +++ b/src/Scene.h @@ -41,6 +41,7 @@ public: Vector3f up() const; Vector3f lookAt() const; Vector3f backgroundColor() const; + Eigen::VectorXi raysPerPixel() const; void setRaysPerPixel(const Eigen::VectorXi &); void setAntialiasing(bool); void setTwoSideRender(bool); From 0d450261a74359f0180794e4f3de86c979fdcecf Mon Sep 17 00:00:00 2001 From: vonhyou Date: Mon, 18 Mar 2024 20:36:03 -0400 Subject: [PATCH 04/27] add progress bar --- src/Optional.h | 1 + src/Progress.h | 29 +++++++++++++++++++++++++++++ src/RayTracer.cc | 7 ++++++- 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/Progress.h diff --git a/src/Optional.h b/src/Optional.h index 3b3a7d4..0633df4 100644 --- a/src/Optional.h +++ b/src/Optional.h @@ -1,4 +1,5 @@ #ifndef OPTIONAL_H_ +#define OPTIONAL_H_ namespace utils { diff --git a/src/Progress.h b/src/Progress.h new file mode 100644 index 0000000..6417dfa --- /dev/null +++ b/src/Progress.h @@ -0,0 +1,29 @@ +#ifndef PROGRESS_H_ +#define PROGRESS_H_ + +#include + +namespace utils { + +#define BAR_WIDTH 70 + +class Progress { +public: + static void of(float p) { + std::cout << "["; + int pos = BAR_WIDTH * p; + for (int i = 0; i < BAR_WIDTH; ++i) { + if (i < pos) + std::cout << "="; + else if (i == pos) + std::cout << ">"; + else + std::cout << " "; + } + std::cout << "] " << int(p * 100.0) << " %\r"; + std::cout.flush(); + } +}; +} // namespace utils + +#endif // !PROGRESS_H_ diff --git a/src/RayTracer.cc b/src/RayTracer.cc index 69c55b1..479e6d4 100644 --- a/src/RayTracer.cc +++ b/src/RayTracer.cc @@ -2,6 +2,7 @@ #include "HitRecord.h" #include "Output.h" #include "Parser.h" +#include "Progress.h" #include "Ray.h" #include @@ -70,7 +71,8 @@ void RayTracer::render() { rpp = raysPerPixel.z(); } - for (int y = 0; y < height; ++y) + for (int y = 0; y < height; ++y) { + utils::Progress::of((y + 1.0f) / height); for (int x = 0; x < width; ++x) for (int j = 0; j < gridHeight; ++j) for (int i = 0; i < gridWidth; ++i) { @@ -88,6 +90,9 @@ void RayTracer::render() { calculateColor(hit, y * width + x); } } + } + + std::cout << std::endl; } void RayTracer::run() { From f5936b2ada208c77d6cf527edde52a18dcf5e9ec Mon Sep 17 00:00:00 2001 From: vonhyou Date: Mon, 18 Mar 2024 21:09:16 -0400 Subject: [PATCH 05/27] set for global illum --- src/RayTracer.cc | 57 +++++++++++++++++++++++++++++++----------------- src/Scene.cc | 2 ++ src/Scene.h | 4 +++- 3 files changed, 42 insertions(+), 21 deletions(-) diff --git a/src/RayTracer.cc b/src/RayTracer.cc index 479e6d4..bd1db1e 100644 --- a/src/RayTracer.cc +++ b/src/RayTracer.cc @@ -40,6 +40,18 @@ void RayTracer::calculateColor(const HitRecord &hit, int i) { Output::current->b(i, result.z()); } +int getGridWidth(Eigen::VectorXi data) { + return data.size() != 2 && data.size() != 3 ? 1 : data.x(); +} + +int getGridHeight(Eigen::VectorXi data) { + return data.size() == 2 ? data.x() : (data.size() == 3 ? data.y() : 1); +} + +int getRayNumber(Eigen::VectorXi data) { + return data.size() == 2 ? data.y() : (data.size() == 3 ? data.z() : 1); +} + void RayTracer::render() { int width = Scene::current->width(); int height = Scene::current->height(); @@ -59,35 +71,40 @@ void RayTracer::render() { Output::current = new Output(Scene::current->backgroundColor(), Scene::current->name(), width, height); - int gridWidth = 1, gridHeight = 1, rpp = 1; - Eigen::VectorXi raysPerPixel = Scene::current->raysPerPixel(); + Eigen::VectorXi data = Scene::current->raysPerPixel(); + int gridWidth = getGridWidth(data); + int gridHeight = getGridHeight(data); + int raysPerPixel = getRayNumber(data); - if (raysPerPixel.size() == 2) { - gridWidth = gridHeight = raysPerPixel.x(); - rpp = raysPerPixel.y(); - } else if (raysPerPixel.size() == 3) { - gridWidth = raysPerPixel.x(); - gridHeight = raysPerPixel.y(); - rpp = raysPerPixel.z(); + Vector3f gdu = Vector3f::Zero(); + Vector3f gdv = Vector3f::Zero(); + if (gridWidth > 1 || gridHeight > 1) { + gdu = du / gridWidth; + gdv = dv / gridHeight; } for (int y = 0; y < height; ++y) { utils::Progress::of((y + 1.0f) / height); + for (int x = 0; x < width; ++x) for (int j = 0; j < gridHeight; ++j) for (int i = 0; i < gridWidth; ++i) { - Ray ray = getRay(x, y, cameraPos, pxUpperLeft, du, dv); - priority_queue records; - for (auto g : geometries) { - Optional t = g->intersect(ray); - if (t.hasValue()) - records.push(HitRecord(t.value(), ray, g)); - } + if (Scene::current->globalIllum()) { + // TODO: Path tracing for global illumination + } else { + Ray ray = getRay(x, y, cameraPos, pxUpperLeft, du, dv); + priority_queue records; + for (auto g : geometries) { + Optional t = g->intersect(ray); + if (t.hasValue()) + records.push(HitRecord(t.value(), ray, g)); + } - if (!records.empty()) { - HitRecord hit = records.top(); - hit.calcNormal(); - calculateColor(hit, y * width + x); + if (!records.empty()) { + HitRecord hit = records.top(); + hit.calcNormal(); + calculateColor(hit, y * width + x); + } } } } diff --git a/src/Scene.cc b/src/Scene.cc index b51ee11..7c78821 100644 --- a/src/Scene.cc +++ b/src/Scene.cc @@ -10,6 +10,8 @@ int Scene::height() { return height_; } float Scene::fov() { return fov_; } +bool Scene::globalIllum() { return globalIllum_; } + Eigen::VectorXi Scene::raysPerPixel() const { return raysPerPixel_; } Vector3f Scene::ai() const { return ai_; } diff --git a/src/Scene.h b/src/Scene.h index 89eb9d2..9cc9f5d 100644 --- a/src/Scene.h +++ b/src/Scene.h @@ -32,10 +32,13 @@ private: bool globalIllum_ = false; public: + static Scene *current; + string name() const; int width(); int height(); float fov(); + bool globalIllum(); Vector3f ai() const; Vector3f center() const; Vector3f up() const; @@ -46,7 +49,6 @@ public: void setAntialiasing(bool); void setTwoSideRender(bool); void setGlobalIllum(bool); - static Scene *current; }; #endif // !SCENE_H_ From 05914ac7685eac29234ebc19fbdefacb6d4eb4b0 Mon Sep 17 00:00:00 2001 From: vonhyou Date: Tue, 19 Mar 2024 18:56:58 -0400 Subject: [PATCH 06/27] reformat --- src/Output.h | 8 +++---- src/RayTracer.cc | 60 +++++++++++++++++++++++++++--------------------- src/RayTracer.h | 2 +- 3 files changed, 38 insertions(+), 32 deletions(-) diff --git a/src/Output.h b/src/Output.h index 8cf7b9c..df9c875 100644 --- a/src/Output.h +++ b/src/Output.h @@ -11,11 +11,9 @@ using std::vector; class Output { public: - Output(const Vector3f &bgc, string path, int w, int h) - : red(vector(w * h + 1, bgc.x())), - green(vector(w * h + 1, bgc.y())), - blue(vector(w * h + 1, bgc.z())), path(path), width(w), - height(h) {} + Output(string path, int w, int h) + : red(vector(w * h + 1)), green(vector(w * h + 1)), + blue(vector(w * h + 1)), path(path), width(w), height(h) {} void write(); diff --git a/src/RayTracer.cc b/src/RayTracer.cc index bd1db1e..a9998f2 100644 --- a/src/RayTracer.cc +++ b/src/RayTracer.cc @@ -28,16 +28,19 @@ Ray getRay(int x, int y, const Vector3f &camPos, const Vector3f &pxUpperLeft, return Ray(camPos, pxUpperLeft + x * du + y * dv - camPos); } -void RayTracer::calculateColor(const HitRecord &hit, int i) { +void writeColor(int i, const Vector3f &color) { + Output::current->r(i, color.x()); + Output::current->g(i, color.y()); + Output::current->b(i, color.z()); +} + +Vector3f RayTracer::calculateColor(const HitRecord &hit, int i) const { Vector3f result(0, 0, 0); for (auto light : lights) result += light->isUse() ? light->illumination(hit, geometries) : Vector3f::Zero(); - result = result.cwiseMax(0.0f).cwiseMin(1.0f); - Output::current->r(i, result.x()); - Output::current->g(i, result.y()); - Output::current->b(i, result.z()); + return result.cwiseMax(0.0f).cwiseMin(1.0f); } int getGridWidth(Eigen::VectorXi data) { @@ -52,6 +55,8 @@ int getRayNumber(Eigen::VectorXi data) { return data.size() == 2 ? data.y() : (data.size() == 3 ? data.z() : 1); } +Vector3f trace() { return Vector3f::Zero(); } + void RayTracer::render() { int width = Scene::current->width(); int height = Scene::current->height(); @@ -68,8 +73,7 @@ void RayTracer::render() { Vector3f vpUpperLeft = cameraPos + lookAt - u / 2.0 - v / 2.0; Vector3f pxUpperLeft = vpUpperLeft + (du + dv) / 2.0; - Output::current = new Output(Scene::current->backgroundColor(), - Scene::current->name(), width, height); + Output::current = new Output(Scene::current->name(), width, height); Eigen::VectorXi data = Scene::current->raysPerPixel(); int gridWidth = getGridWidth(data); @@ -84,31 +88,35 @@ void RayTracer::render() { } for (int y = 0; y < height; ++y) { + // print progress bar utils::Progress::of((y + 1.0f) / height); - for (int x = 0; x < width; ++x) - for (int j = 0; j < gridHeight; ++j) - for (int i = 0; i < gridWidth; ++i) { - if (Scene::current->globalIllum()) { - // TODO: Path tracing for global illumination - } else { - Ray ray = getRay(x, y, cameraPos, pxUpperLeft, du, dv); - priority_queue records; - for (auto g : geometries) { - Optional t = g->intersect(ray); - if (t.hasValue()) - records.push(HitRecord(t.value(), ray, g)); - } + for (int x = 0; x < width; ++x) { + Vector3f color = Scene::current->backgroundColor(); - if (!records.empty()) { - HitRecord hit = records.top(); - hit.calcNormal(); - calculateColor(hit, y * width + x); - } + if (Scene::current->globalIllum()) { + for (int j = 0; j < gridHeight; ++j) + for (int i = 0; i < gridWidth; ++i) { + color = trace(); } + } else { + Ray ray = getRay(x, y, cameraPos, pxUpperLeft, du, dv); + priority_queue records; + for (auto g : geometries) { + Optional t = g->intersect(ray); + if (t.hasValue()) + records.push(HitRecord(t.value(), ray, g)); } - } + if (!records.empty()) { + HitRecord hit = records.top(); + hit.calcNormal(); + color = calculateColor(hit, y * width + x); + } + } + writeColor(y * width + x, color); + } + } std::cout << std::endl; } diff --git a/src/RayTracer.h b/src/RayTracer.h index 7660665..e30b8d3 100644 --- a/src/RayTracer.h +++ b/src/RayTracer.h @@ -22,7 +22,7 @@ private: std::vector outputs; void parse(); - void calculateColor(const HitRecord &, int); + Vector3f calculateColor(const HitRecord &, int) const; void render(); }; From 121910877eb540ee1750a8bee83fdc76382e5d33 Mon Sep 17 00:00:00 2001 From: vonhyou Date: Tue, 19 Mar 2024 19:33:38 -0400 Subject: [PATCH 07/27] reformat helper functions --- src/RayTracer.cc | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/src/RayTracer.cc b/src/RayTracer.cc index a9998f2..313e7dc 100644 --- a/src/RayTracer.cc +++ b/src/RayTracer.cc @@ -23,9 +23,17 @@ void RayTracer::parse() { lights.push_back(Parser::getLight(*i)); } -Ray getRay(int x, int y, const Vector3f &camPos, const Vector3f &pxUpperLeft, - const Vector3f &du, const Vector3f &dv) { - return Ray(camPos, pxUpperLeft + x * du + y * dv - camPos); +Ray getRay(int x, int y, const Vector3f &upperLeft, const Vector3f &du, + const Vector3f &dv) { + Vector3f camPos = Scene::current->center(); + return Ray(camPos, upperLeft + x * du + y * dv - camPos); +} + +Ray getRay(int x, int y, int i, int j, const Vector3f &upperLeft, + const Vector3f &du, const Vector3f &gdu, const Vector3f &dv, + const Vector3f &gdv) { + Vector3f camPos = Scene::current->center(); + return Ray(camPos, upperLeft + x * du + i * gdu + y * dv + j * gdv - camPos); } void writeColor(int i, const Vector3f &color) { @@ -43,17 +51,11 @@ Vector3f RayTracer::calculateColor(const HitRecord &hit, int i) const { return result.cwiseMax(0.0f).cwiseMin(1.0f); } -int getGridWidth(Eigen::VectorXi data) { - return data.size() != 2 && data.size() != 3 ? 1 : data.x(); -} +int getGridWidth(Eigen::VectorXi); -int getGridHeight(Eigen::VectorXi data) { - return data.size() == 2 ? data.x() : (data.size() == 3 ? data.y() : 1); -} +int getGridHeight(Eigen::VectorXi); -int getRayNumber(Eigen::VectorXi data) { - return data.size() == 2 ? data.y() : (data.size() == 3 ? data.z() : 1); -} +int getRayNumber(Eigen::VectorXi); Vector3f trace() { return Vector3f::Zero(); } @@ -97,10 +99,11 @@ void RayTracer::render() { if (Scene::current->globalIllum()) { for (int j = 0; j < gridHeight; ++j) for (int i = 0; i < gridWidth; ++i) { + Ray ray = getRay(x, y, i, j, vpUpperLeft, du, gdu, dv, gdv); color = trace(); } } else { - Ray ray = getRay(x, y, cameraPos, pxUpperLeft, du, dv); + Ray ray = getRay(x, y, pxUpperLeft, du, dv); priority_queue records; for (auto g : geometries) { Optional t = g->intersect(ray); @@ -129,3 +132,17 @@ void RayTracer::run() { Output::current->write(); } } + +// helper functions + +int getGridWidth(Eigen::VectorXi data) { + return data.size() != 2 && data.size() != 3 ? 1 : data.x(); +} + +int getGridHeight(Eigen::VectorXi data) { + return data.size() == 2 ? data.x() : (data.size() == 3 ? data.y() : 1); +} + +int getRayNumber(Eigen::VectorXi data) { + return data.size() == 2 ? data.y() : (data.size() == 3 ? data.z() : 1); +} From eb9b6934c01d263dc821478cdb63189913d58278 Mon Sep 17 00:00:00 2001 From: vonhyou Date: Tue, 19 Mar 2024 20:33:17 -0400 Subject: [PATCH 08/27] rearrange --- src/RayTracer.cc | 100 ++++++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 48 deletions(-) diff --git a/src/RayTracer.cc b/src/RayTracer.cc index 313e7dc..18b15f1 100644 --- a/src/RayTracer.cc +++ b/src/RayTracer.cc @@ -10,8 +10,29 @@ #include #include +using Eigen::VectorXi; using std::priority_queue; +// help function declarations +int getGridWidth(VectorXi); +int getGridHeight(VectorXi); +int getRayNumber(VectorXi); +Ray getRay(int, int, const Vector3f &, const Vector3f &, const Vector3f &); +Ray getRay(int, int, int, int, const Vector3f &, const Vector3f &, + const Vector3f &, const Vector3f &, const Vector3f &); +void writeColor(int, const Vector3f &); +Vector3f trace(); + +void RayTracer::run() { + parse(); + + for (auto scene : scenes) { + Scene::current = scene; + render(); + Output::current->write(); + } +} + void RayTracer::parse() { for (auto i = json["output"].begin(); i != json["output"].end(); ++i) scenes.push_back(Parser::getScene(*i)); @@ -23,42 +44,6 @@ void RayTracer::parse() { lights.push_back(Parser::getLight(*i)); } -Ray getRay(int x, int y, const Vector3f &upperLeft, const Vector3f &du, - const Vector3f &dv) { - Vector3f camPos = Scene::current->center(); - return Ray(camPos, upperLeft + x * du + y * dv - camPos); -} - -Ray getRay(int x, int y, int i, int j, const Vector3f &upperLeft, - const Vector3f &du, const Vector3f &gdu, const Vector3f &dv, - const Vector3f &gdv) { - Vector3f camPos = Scene::current->center(); - return Ray(camPos, upperLeft + x * du + i * gdu + y * dv + j * gdv - camPos); -} - -void writeColor(int i, const Vector3f &color) { - Output::current->r(i, color.x()); - Output::current->g(i, color.y()); - Output::current->b(i, color.z()); -} - -Vector3f RayTracer::calculateColor(const HitRecord &hit, int i) const { - Vector3f result(0, 0, 0); - for (auto light : lights) - result += light->isUse() ? light->illumination(hit, geometries) - : Vector3f::Zero(); - - return result.cwiseMax(0.0f).cwiseMin(1.0f); -} - -int getGridWidth(Eigen::VectorXi); - -int getGridHeight(Eigen::VectorXi); - -int getRayNumber(Eigen::VectorXi); - -Vector3f trace() { return Vector3f::Zero(); } - void RayTracer::render() { int width = Scene::current->width(); int height = Scene::current->height(); @@ -77,7 +62,7 @@ void RayTracer::render() { Output::current = new Output(Scene::current->name(), width, height); - Eigen::VectorXi data = Scene::current->raysPerPixel(); + VectorXi data = Scene::current->raysPerPixel(); int gridWidth = getGridWidth(data); int gridHeight = getGridHeight(data); int raysPerPixel = getRayNumber(data); @@ -123,26 +108,45 @@ void RayTracer::render() { std::cout << std::endl; } -void RayTracer::run() { - parse(); +Vector3f RayTracer::calculateColor(const HitRecord &hit, int i) const { + Vector3f result(0, 0, 0); + for (auto light : lights) + result += light->isUse() ? light->illumination(hit, geometries) + : Vector3f::Zero(); - for (auto scene : scenes) { - Scene::current = scene; - render(); - Output::current->write(); - } + return result.cwiseMax(0.0f).cwiseMin(1.0f); } // helper functions - -int getGridWidth(Eigen::VectorXi data) { +int getGridWidth(VectorXi data) { return data.size() != 2 && data.size() != 3 ? 1 : data.x(); } -int getGridHeight(Eigen::VectorXi data) { +int getGridHeight(VectorXi data) { return data.size() == 2 ? data.x() : (data.size() == 3 ? data.y() : 1); } -int getRayNumber(Eigen::VectorXi data) { +int getRayNumber(VectorXi data) { return data.size() == 2 ? data.y() : (data.size() == 3 ? data.z() : 1); } + +Ray getRay(int x, int y, const Vector3f &upperLeft, const Vector3f &du, + const Vector3f &dv) { + Vector3f camPos = Scene::current->center(); + return Ray(camPos, upperLeft + x * du + y * dv - camPos); +} + +Ray getRay(int x, int y, int i, int j, const Vector3f &upperLeft, + const Vector3f &du, const Vector3f &gdu, const Vector3f &dv, + const Vector3f &gdv) { + Vector3f camPos = Scene::current->center(); + return Ray(camPos, upperLeft + x * du + i * gdu + y * dv + j * gdv - camPos); +} + +void writeColor(int i, const Vector3f &color) { + Output::current->r(i, color.x()); + Output::current->g(i, color.y()); + Output::current->b(i, color.z()); +} + +Vector3f trace() { return Vector3f::Zero(); } From 29b87c041e81bd3e670dcb4ec5e8f728446e8c02 Mon Sep 17 00:00:00 2001 From: vonhyou Date: Tue, 19 Mar 2024 20:54:33 -0400 Subject: [PATCH 09/27] create camera --- src/RayTracer.cc | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/src/RayTracer.cc b/src/RayTracer.cc index 18b15f1..f26cd74 100644 --- a/src/RayTracer.cc +++ b/src/RayTracer.cc @@ -23,6 +23,12 @@ Ray getRay(int, int, int, int, const Vector3f &, const Vector3f &, void writeColor(int, const Vector3f &); Vector3f trace(); +namespace camera { +int width, height; + +void init(); +} // namespace camera + void RayTracer::run() { parse(); @@ -45,22 +51,22 @@ void RayTracer::parse() { } void RayTracer::render() { - int width = Scene::current->width(); - int height = Scene::current->height(); + camera::init(); Vector3f cameraPos = Scene::current->center(); Vector3f lookAt = Scene::current->lookAt(); float vpHeight = 2 * tan(Scene::current->fov() / 180 * M_PI / 2) * lookAt.norm(); - float vpWidth = vpHeight * width / height; + float vpWidth = vpHeight * camera::width / camera::height; Vector3f u = Vector3f(vpWidth, 0, 0); Vector3f v = Vector3f(0, -vpHeight, 0); - Vector3f du = u / width; - Vector3f dv = v / height; + Vector3f du = u / camera::width; + Vector3f dv = v / camera::height; Vector3f vpUpperLeft = cameraPos + lookAt - u / 2.0 - v / 2.0; Vector3f pxUpperLeft = vpUpperLeft + (du + dv) / 2.0; - Output::current = new Output(Scene::current->name(), width, height); + Output::current = + new Output(Scene::current->name(), camera::width, camera::height); VectorXi data = Scene::current->raysPerPixel(); int gridWidth = getGridWidth(data); @@ -74,11 +80,11 @@ void RayTracer::render() { gdv = dv / gridHeight; } - for (int y = 0; y < height; ++y) { + for (int y = 0; y < camera::height; ++y) { // print progress bar - utils::Progress::of((y + 1.0f) / height); + utils::Progress::of((y + 1.0f) / camera::height); - for (int x = 0; x < width; ++x) { + for (int x = 0; x < camera::width; ++x) { Vector3f color = Scene::current->backgroundColor(); if (Scene::current->globalIllum()) { @@ -99,10 +105,10 @@ void RayTracer::render() { if (!records.empty()) { HitRecord hit = records.top(); hit.calcNormal(); - color = calculateColor(hit, y * width + x); + color = calculateColor(hit, y * camera::width + x); } } - writeColor(y * width + x, color); + writeColor(y * camera::width + x, color); } } std::cout << std::endl; @@ -150,3 +156,10 @@ void writeColor(int i, const Vector3f &color) { } Vector3f trace() { return Vector3f::Zero(); } + +namespace camera { +void init() { + width = Scene::current->width(); + height = Scene::current->height(); +} +} // namespace camera From 179227420dac9f82ea58dc8d74f920bcfa7b826e Mon Sep 17 00:00:00 2001 From: vonhyou Date: Tue, 19 Mar 2024 21:01:25 -0400 Subject: [PATCH 10/27] update camera namespace --- src/RayTracer.cc | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/RayTracer.cc b/src/RayTracer.cc index f26cd74..1630018 100644 --- a/src/RayTracer.cc +++ b/src/RayTracer.cc @@ -25,6 +25,7 @@ Vector3f trace(); namespace camera { int width, height; +Vector3f position, u, v, du, dv, vpUpperLeft, pxUpperLeft; void init(); } // namespace camera @@ -52,18 +53,6 @@ void RayTracer::parse() { void RayTracer::render() { camera::init(); - Vector3f cameraPos = Scene::current->center(); - Vector3f lookAt = Scene::current->lookAt(); - float vpHeight = - 2 * tan(Scene::current->fov() / 180 * M_PI / 2) * lookAt.norm(); - float vpWidth = vpHeight * camera::width / camera::height; - Vector3f u = Vector3f(vpWidth, 0, 0); - Vector3f v = Vector3f(0, -vpHeight, 0); - Vector3f du = u / camera::width; - Vector3f dv = v / camera::height; - - Vector3f vpUpperLeft = cameraPos + lookAt - u / 2.0 - v / 2.0; - Vector3f pxUpperLeft = vpUpperLeft + (du + dv) / 2.0; Output::current = new Output(Scene::current->name(), camera::width, camera::height); @@ -76,8 +65,8 @@ void RayTracer::render() { Vector3f gdu = Vector3f::Zero(); Vector3f gdv = Vector3f::Zero(); if (gridWidth > 1 || gridHeight > 1) { - gdu = du / gridWidth; - gdv = dv / gridHeight; + gdu = camera::du / gridWidth; + gdv = camera::dv / gridHeight; } for (int y = 0; y < camera::height; ++y) { @@ -90,11 +79,12 @@ void RayTracer::render() { if (Scene::current->globalIllum()) { for (int j = 0; j < gridHeight; ++j) for (int i = 0; i < gridWidth; ++i) { - Ray ray = getRay(x, y, i, j, vpUpperLeft, du, gdu, dv, gdv); + Ray ray = getRay(x, y, i, j, camera::vpUpperLeft, camera::du, gdu, + camera::dv, gdv); color = trace(); } } else { - Ray ray = getRay(x, y, pxUpperLeft, du, dv); + Ray ray = getRay(x, y, camera::pxUpperLeft, camera::du, camera::dv); priority_queue records; for (auto g : geometries) { Optional t = g->intersect(ray); @@ -138,8 +128,7 @@ int getRayNumber(VectorXi data) { Ray getRay(int x, int y, const Vector3f &upperLeft, const Vector3f &du, const Vector3f &dv) { - Vector3f camPos = Scene::current->center(); - return Ray(camPos, upperLeft + x * du + y * dv - camPos); + return Ray(camera::position, upperLeft + x * du + y * dv - camera::position); } Ray getRay(int x, int y, int i, int j, const Vector3f &upperLeft, @@ -161,5 +150,16 @@ namespace camera { void init() { width = Scene::current->width(); height = Scene::current->height(); + position = Scene::current->center(); + Vector3f lookAt = Scene::current->lookAt(); + float vpHeight = + 2 * tan(Scene::current->fov() / 180 * M_PI / 2) * lookAt.norm(); + float vpWidth = vpHeight * camera::width / camera::height; + u = Vector3f(vpWidth, 0, 0); + v = Vector3f(0, -vpHeight, 0); + du = u / camera::width; + dv = v / camera::height; + vpUpperLeft = camera::position + lookAt - u / 2.0 - v / 2.0; + pxUpperLeft = vpUpperLeft + (du + dv) / 2.0; } } // namespace camera From 6863be4658e8814cb51eab2914cd78f9306984b4 Mon Sep 17 00:00:00 2001 From: vonhyou Date: Tue, 19 Mar 2024 21:09:57 -0400 Subject: [PATCH 11/27] update camera namespace --- src/RayTracer.cc | 66 +++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/src/RayTracer.cc b/src/RayTracer.cc index 1630018..721c80e 100644 --- a/src/RayTracer.cc +++ b/src/RayTracer.cc @@ -17,15 +17,14 @@ using std::priority_queue; int getGridWidth(VectorXi); int getGridHeight(VectorXi); int getRayNumber(VectorXi); -Ray getRay(int, int, const Vector3f &, const Vector3f &, const Vector3f &); -Ray getRay(int, int, int, int, const Vector3f &, const Vector3f &, - const Vector3f &, const Vector3f &, const Vector3f &); +Ray getRay(int, int); +Ray getRay(int, int, int, int); void writeColor(int, const Vector3f &); Vector3f trace(); namespace camera { -int width, height; -Vector3f position, u, v, du, dv, vpUpperLeft, pxUpperLeft; +int width, height, gridWidth, gridHeight, raysPerPixel; +Vector3f pos, u, v, du, dv, vpUpperLeft, pxUpperLeft, gdu, gdv; void init(); } // namespace camera @@ -57,18 +56,6 @@ void RayTracer::render() { Output::current = new Output(Scene::current->name(), camera::width, camera::height); - VectorXi data = Scene::current->raysPerPixel(); - int gridWidth = getGridWidth(data); - int gridHeight = getGridHeight(data); - int raysPerPixel = getRayNumber(data); - - Vector3f gdu = Vector3f::Zero(); - Vector3f gdv = Vector3f::Zero(); - if (gridWidth > 1 || gridHeight > 1) { - gdu = camera::du / gridWidth; - gdv = camera::dv / gridHeight; - } - for (int y = 0; y < camera::height; ++y) { // print progress bar utils::Progress::of((y + 1.0f) / camera::height); @@ -77,14 +64,13 @@ void RayTracer::render() { Vector3f color = Scene::current->backgroundColor(); if (Scene::current->globalIllum()) { - for (int j = 0; j < gridHeight; ++j) - for (int i = 0; i < gridWidth; ++i) { - Ray ray = getRay(x, y, i, j, camera::vpUpperLeft, camera::du, gdu, - camera::dv, gdv); + for (int j = 0; j < camera::gridHeight; ++j) + for (int i = 0; i < camera::gridWidth; ++i) { + Ray ray = getRay(x, y, i, j); color = trace(); } } else { - Ray ray = getRay(x, y, camera::pxUpperLeft, camera::du, camera::dv); + Ray ray = getRay(x, y); priority_queue records; for (auto g : geometries) { Optional t = g->intersect(ray); @@ -126,16 +112,14 @@ int getRayNumber(VectorXi data) { return data.size() == 2 ? data.y() : (data.size() == 3 ? data.z() : 1); } -Ray getRay(int x, int y, const Vector3f &upperLeft, const Vector3f &du, - const Vector3f &dv) { - return Ray(camera::position, upperLeft + x * du + y * dv - camera::position); +Ray getRay(int x, int y) { + using namespace camera; + return Ray(pos, pxUpperLeft + x * du + y * dv - pos); } -Ray getRay(int x, int y, int i, int j, const Vector3f &upperLeft, - const Vector3f &du, const Vector3f &gdu, const Vector3f &dv, - const Vector3f &gdv) { - Vector3f camPos = Scene::current->center(); - return Ray(camPos, upperLeft + x * du + i * gdu + y * dv + j * gdv - camPos); +Ray getRay(int x, int y, int i, int j) { + using namespace camera; + return Ray(pos, vpUpperLeft + x * du + i * gdu + y * dv + j * gdv - pos); } void writeColor(int i, const Vector3f &color) { @@ -150,16 +134,28 @@ namespace camera { void init() { width = Scene::current->width(); height = Scene::current->height(); - position = Scene::current->center(); + pos = Scene::current->center(); Vector3f lookAt = Scene::current->lookAt(); float vpHeight = 2 * tan(Scene::current->fov() / 180 * M_PI / 2) * lookAt.norm(); - float vpWidth = vpHeight * camera::width / camera::height; + float vpWidth = vpHeight * width / height; u = Vector3f(vpWidth, 0, 0); v = Vector3f(0, -vpHeight, 0); - du = u / camera::width; - dv = v / camera::height; - vpUpperLeft = camera::position + lookAt - u / 2.0 - v / 2.0; + du = u / width; + dv = v / height; + vpUpperLeft = pos + lookAt - u / 2.0 - v / 2.0; pxUpperLeft = vpUpperLeft + (du + dv) / 2.0; + + VectorXi data = Scene::current->raysPerPixel(); + gridWidth = getGridWidth(data); + gridHeight = getGridHeight(data); + raysPerPixel = getRayNumber(data); + + gdu = Vector3f::Zero(); + gdv = Vector3f::Zero(); + if (gridWidth > 1 || gridHeight > 1) { + gdu = du / gridWidth; + gdv = dv / gridHeight; + } } } // namespace camera From f87f48887770780bfcfeaa8c76f1b12317c130f5 Mon Sep 17 00:00:00 2001 From: vonhyou Date: Tue, 19 Mar 2024 21:16:35 -0400 Subject: [PATCH 12/27] finishcamera namespace --- src/RayTracer.cc | 53 +++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/src/RayTracer.cc b/src/RayTracer.cc index 721c80e..a3e7e0d 100644 --- a/src/RayTracer.cc +++ b/src/RayTracer.cc @@ -14,9 +14,6 @@ using Eigen::VectorXi; using std::priority_queue; // help function declarations -int getGridWidth(VectorXi); -int getGridHeight(VectorXi); -int getRayNumber(VectorXi); Ray getRay(int, int); Ray getRay(int, int, int, int); void writeColor(int, const Vector3f &); @@ -29,12 +26,19 @@ Vector3f pos, u, v, du, dv, vpUpperLeft, pxUpperLeft, gdu, gdv; void init(); } // namespace camera +/** + * Student solution starts here + */ void RayTracer::run() { parse(); for (auto scene : scenes) { + if (Scene::current != nullptr) + delete Scene::current; + Scene::current = scene; render(); + Output::current->write(); } } @@ -53,19 +57,18 @@ void RayTracer::parse() { void RayTracer::render() { camera::init(); - Output::current = - new Output(Scene::current->name(), camera::width, camera::height); + using namespace camera; + Output::current = new Output(Scene::current->name(), width, height); - for (int y = 0; y < camera::height; ++y) { - // print progress bar - utils::Progress::of((y + 1.0f) / camera::height); + for (int y = 0; y < height; ++y) { + utils::Progress::of((y + 1.0f) / height); - for (int x = 0; x < camera::width; ++x) { + for (int x = 0; x < width; ++x) { Vector3f color = Scene::current->backgroundColor(); if (Scene::current->globalIllum()) { - for (int j = 0; j < camera::gridHeight; ++j) - for (int i = 0; i < camera::gridWidth; ++i) { + for (int j = 0; j < gridHeight; ++j) + for (int i = 0; i < gridWidth; ++i) { Ray ray = getRay(x, y, i, j); color = trace(); } @@ -81,10 +84,10 @@ void RayTracer::render() { if (!records.empty()) { HitRecord hit = records.top(); hit.calcNormal(); - color = calculateColor(hit, y * camera::width + x); + color = calculateColor(hit, y * width + x); } } - writeColor(y * camera::width + x, color); + writeColor(y * width + x, color); } } std::cout << std::endl; @@ -100,18 +103,6 @@ Vector3f RayTracer::calculateColor(const HitRecord &hit, int i) const { } // helper functions -int getGridWidth(VectorXi data) { - return data.size() != 2 && data.size() != 3 ? 1 : data.x(); -} - -int getGridHeight(VectorXi data) { - return data.size() == 2 ? data.x() : (data.size() == 3 ? data.y() : 1); -} - -int getRayNumber(VectorXi data) { - return data.size() == 2 ? data.y() : (data.size() == 3 ? data.z() : 1); -} - Ray getRay(int x, int y) { using namespace camera; return Ray(pos, pxUpperLeft + x * du + y * dv - pos); @@ -131,6 +122,18 @@ void writeColor(int i, const Vector3f &color) { Vector3f trace() { return Vector3f::Zero(); } namespace camera { +int getGridWidth(VectorXi data) { + return data.size() != 2 && data.size() != 3 ? 1 : data.x(); +} + +int getGridHeight(VectorXi data) { + return data.size() == 2 ? data.x() : (data.size() == 3 ? data.y() : 1); +} + +int getRayNumber(VectorXi data) { + return data.size() == 2 ? data.y() : (data.size() == 3 ? data.z() : 1); +} + void init() { width = Scene::current->width(); height = Scene::current->height(); From 2a68e2a909b583a8e37441be2ad6bf672fd6cc1c Mon Sep 17 00:00:00 2001 From: vonhyou Date: Tue, 19 Mar 2024 21:32:51 -0400 Subject: [PATCH 13/27] reformat --- src/RayTracer.cc | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/src/RayTracer.cc b/src/RayTracer.cc index a3e7e0d..3437b69 100644 --- a/src/RayTracer.cc +++ b/src/RayTracer.cc @@ -17,7 +17,8 @@ using std::priority_queue; Ray getRay(int, int); Ray getRay(int, int, int, int); void writeColor(int, const Vector3f &); -Vector3f trace(); +Vector3f trace(Ray r); +Vector3f clamp(const Vector3f &); namespace camera { int width, height, gridWidth, gridHeight, raysPerPixel; @@ -28,6 +29,8 @@ void init(); /** * Student solution starts here + * + * The main.cpp provided by instructor will invoke this function */ void RayTracer::run() { parse(); @@ -43,6 +46,11 @@ void RayTracer::run() { } } +/** + * Parse the scene stored in the json file + * + * Example scene files are in `assets` folder + */ void RayTracer::parse() { for (auto i = json["output"].begin(); i != json["output"].end(); ++i) scenes.push_back(Parser::getScene(*i)); @@ -54,6 +62,14 @@ void RayTracer::parse() { lights.push_back(Parser::getLight(*i)); } +/** + * Render the current scene + * + * For direction illumination and anti-aliasing, render by phong model + * for global illumination, use path-tracing method. + * + * (*) Global illumination will not work with anti-aliasing by the requirement + */ void RayTracer::render() { camera::init(); @@ -67,11 +83,15 @@ void RayTracer::render() { Vector3f color = Scene::current->backgroundColor(); if (Scene::current->globalIllum()) { + int success = 0; + Vector3f accumulate = Vector3f::Zero(); for (int j = 0; j < gridHeight; ++j) for (int i = 0; i < gridWidth; ++i) { Ray ray = getRay(x, y, i, j); - color = trace(); + accumulate += trace(ray); } + if (!success) + color = accumulate / success; } else { Ray ray = getRay(x, y); priority_queue records; @@ -87,19 +107,22 @@ void RayTracer::render() { color = calculateColor(hit, y * width + x); } } - writeColor(y * width + x, color); + writeColor(y * width + x, clamp(color)); } } std::cout << std::endl; } +/** + * Calculate color using phong model + */ Vector3f RayTracer::calculateColor(const HitRecord &hit, int i) const { Vector3f result(0, 0, 0); for (auto light : lights) result += light->isUse() ? light->illumination(hit, geometries) : Vector3f::Zero(); - return result.cwiseMax(0.0f).cwiseMin(1.0f); + return result; } // helper functions @@ -113,13 +136,17 @@ Ray getRay(int x, int y, int i, int j) { return Ray(pos, vpUpperLeft + x * du + i * gdu + y * dv + j * gdv - pos); } +Vector3f clamp(const Vector3f &color) { + return color.cwiseMax(0.0f).cwiseMin(1.0f); +} + void writeColor(int i, const Vector3f &color) { Output::current->r(i, color.x()); Output::current->g(i, color.y()); Output::current->b(i, color.z()); } -Vector3f trace() { return Vector3f::Zero(); } +Vector3f trace(Ray r) { return Vector3f::Zero(); } namespace camera { int getGridWidth(VectorXi data) { From 75faed07cc6157e7f18bd5eb838d0da6b9566026 Mon Sep 17 00:00:00 2001 From: vonhyou Date: Tue, 19 Mar 2024 22:21:53 -0400 Subject: [PATCH 14/27] fix for speed node --- src/Geometry.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Geometry.cc b/src/Geometry.cc index 6b544c4..1cd9c5a 100644 --- a/src/Geometry.cc +++ b/src/Geometry.cc @@ -53,7 +53,7 @@ bool isInRectangle(const Vector3f &p, const Vector3f &a, const Vector3f &b, Optional Rectangle::intersect(const Ray &r) const { float denom = normal_.dot(r.direction()); - if (abs(denom) < 1e-6f) + if (std::fabs(denom) < 1e-6f) return Optional::nullopt; float t = -normal_.dot(r.origin() - p1) / denom; From 1c06958238bf34bbf0de02aec3ba2e241b06bece Mon Sep 17 00:00:00 2001 From: vonhyou Date: Tue, 19 Mar 2024 23:15:12 -0400 Subject: [PATCH 15/27] work on global illum --- src/Parser.cc | 2 ++ src/RayTracer.cc | 16 +++++++++++++--- src/Scene.cc | 10 ++++++++++ src/Scene.h | 6 ++++++ 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/Parser.cc b/src/Parser.cc index 126c6b3..fb9fc21 100644 --- a/src/Parser.cc +++ b/src/Parser.cc @@ -40,6 +40,8 @@ Scene *Parser::getScene(const nlohmann::json &j) { sc->setAntialiasing(j.value("antialiasing", false)); sc->setTwoSideRender(j.value("twosiderender", false)); sc->setGlobalIllum(j.value("globalillum", false)); + sc->setMaxBounce(j.value("maxbounce", 3)); + sc->setProbTerminate(j.value("probTerminate", 0.33f)); if (j.contains("raysperpixel")) sc->setRaysPerPixel(getRpp(j["raysperpixel"])); diff --git a/src/RayTracer.cc b/src/RayTracer.cc index 3437b69..3d0e669 100644 --- a/src/RayTracer.cc +++ b/src/RayTracer.cc @@ -17,7 +17,7 @@ using std::priority_queue; Ray getRay(int, int); Ray getRay(int, int, int, int); void writeColor(int, const Vector3f &); -Vector3f trace(Ray r); +utils::Optional trace(Ray r); Vector3f clamp(const Vector3f &); namespace camera { @@ -88,7 +88,11 @@ void RayTracer::render() { for (int j = 0; j < gridHeight; ++j) for (int i = 0; i < gridWidth; ++i) { Ray ray = getRay(x, y, i, j); - accumulate += trace(ray); + utils::Optional result = trace(ray); + if (result.hasValue()) { + accumulate += result.value() * raysPerPixel; + success += raysPerPixel; + } } if (!success) color = accumulate / success; @@ -146,7 +150,13 @@ void writeColor(int i, const Vector3f &color) { Output::current->b(i, color.z()); } -Vector3f trace(Ray r) { return Vector3f::Zero(); } +Vector3f trace(Ray r, int bounce, float prob) {} + +utils::Optional trace(Ray r) { + Vector3f color = + trace(r, Scene::current->maxBounce(), Scene::current->probTerminate()); + return utils::Optional::nullopt; +} namespace camera { int getGridWidth(VectorXi data) { diff --git a/src/Scene.cc b/src/Scene.cc index 7c78821..12c3e27 100644 --- a/src/Scene.cc +++ b/src/Scene.cc @@ -12,6 +12,10 @@ float Scene::fov() { return fov_; } bool Scene::globalIllum() { return globalIllum_; } +int Scene::maxBounce() { return maxBounce_; } + +float Scene::probTerminate() { return probTerminate_; } + Eigen::VectorXi Scene::raysPerPixel() const { return raysPerPixel_; } Vector3f Scene::ai() const { return ai_; } @@ -39,3 +43,9 @@ void Scene::setTwoSideRender(bool twoSideRender) { void Scene::setGlobalIllum(bool globalIllum) { this->globalIllum_ = globalIllum; } + +void Scene::setMaxBounce(int maxBounce) { this->maxBounce_ = maxBounce; } + +void Scene::setProbTerminate(float probTerminate) { + this->probTerminate_ = probTerminate; +} diff --git a/src/Scene.h b/src/Scene.h index 9cc9f5d..fe033da 100644 --- a/src/Scene.h +++ b/src/Scene.h @@ -30,6 +30,8 @@ private: bool antialiasing_ = false; bool twoSideRender_ = false; bool globalIllum_ = false; + int maxBounce_ = 3; + float probTerminate_ = 0.33; public: static Scene *current; @@ -39,6 +41,8 @@ public: int height(); float fov(); bool globalIllum(); + int maxBounce(); + float probTerminate(); Vector3f ai() const; Vector3f center() const; Vector3f up() const; @@ -49,6 +53,8 @@ public: void setAntialiasing(bool); void setTwoSideRender(bool); void setGlobalIllum(bool); + void setMaxBounce(int); + void setProbTerminate(float); }; #endif // !SCENE_H_ From c29cd775671c61efe7a599f29f685e3746f3a3db Mon Sep 17 00:00:00 2001 From: vonhyou Date: Tue, 19 Mar 2024 23:31:04 -0400 Subject: [PATCH 16/27] add random number genreator --- src/Random.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/Random.h diff --git a/src/Random.h b/src/Random.h new file mode 100644 index 0000000..c0d3287 --- /dev/null +++ b/src/Random.h @@ -0,0 +1,23 @@ +#ifndef RANDOM_H_ +#define RANDOM_H_ + +#include +#include +namespace utils { +class Random { +public: + /** + * A way to generate higher quality random number + * since C++ 11 + */ + static float get() { + std::default_random_engine generator( + std::chrono::system_clock::now().time_since_epoch().count()); + std::uniform_real_distribution distribution(0.0f, 1.0f); + + return distribution(generator); + } +}; +} // namespace utils + +#endif // !RANDOM_H_ From a62e5eadc5d10a6a54e5e0ed0550ac19423dce8b Mon Sep 17 00:00:00 2001 From: vonhyou Date: Tue, 19 Mar 2024 23:31:34 -0400 Subject: [PATCH 17/27] add dummy global illum --- src/RayTracer.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/RayTracer.cc b/src/RayTracer.cc index 3d0e669..2953b37 100644 --- a/src/RayTracer.cc +++ b/src/RayTracer.cc @@ -3,6 +3,7 @@ #include "Output.h" #include "Parser.h" #include "Progress.h" +#include "Random.h" #include "Ray.h" #include @@ -150,11 +151,22 @@ void writeColor(int i, const Vector3f &color) { Output::current->b(i, color.z()); } -Vector3f trace(Ray r, int bounce, float prob) {} +Vector3f trace(Ray r, int bounce, float prob) { + float dice = utils::Random::get(); + if (bounce && (dice > prob)) { + return Vector3f(1, 0, 1).array() * trace(r, bounce - 1, prob).array(); + } + + return Vector3f(1, 1, 1); +} utils::Optional trace(Ray r) { Vector3f color = trace(r, Scene::current->maxBounce(), Scene::current->probTerminate()); + + if (color != Vector3f::Zero()) + return utils::Optional(color); + return utils::Optional::nullopt; } From bb7058027477f9c24e5022ba74c45a6ba4b698e1 Mon Sep 17 00:00:00 2001 From: vonhyou Date: Tue, 19 Mar 2024 23:59:11 -0400 Subject: [PATCH 18/27] add default constructors for Optional --- src/HitRecord.h | 2 ++ src/Ray.h | 1 + 2 files changed, 3 insertions(+) diff --git a/src/HitRecord.h b/src/HitRecord.h index 599db5a..7c13aa1 100644 --- a/src/HitRecord.h +++ b/src/HitRecord.h @@ -9,6 +9,8 @@ using Eigen::Vector3f; class HitRecord { public: + HitRecord() + : t(0), ray_(Ray()), normal_(Vector3f::Zero()), geometry_(nullptr) {} HitRecord(float t, const Ray &r, Geometry *g) : t(t), ray_(r), geometry_(g) {} bool operator<(const HitRecord &) const; diff --git a/src/Ray.h b/src/Ray.h index a344e5d..252952f 100644 --- a/src/Ray.h +++ b/src/Ray.h @@ -7,6 +7,7 @@ using Eigen::Vector3f; class Ray { public: + Ray() : origin_(Vector3f::Zero()), direction_(Vector3f::Zero()) {} Ray(const Vector3f &o, const Vector3f &d) : origin_(o), direction_(d) {} private: From 5cf306cbbedd6dc858594115f59d9b54930e9b69 Mon Sep 17 00:00:00 2001 From: vonhyou Date: Wed, 20 Mar 2024 01:07:39 -0400 Subject: [PATCH 19/27] add dummy global illum --- src/Light.cc | 8 ++++- src/Light.h | 8 +++++ src/RayTracer.cc | 83 ++++++++++++++++++++++++++++++++++++------------ src/RayTracer.h | 7 +++- 4 files changed, 84 insertions(+), 22 deletions(-) diff --git a/src/Light.cc b/src/Light.cc index a23cd0c..c2f5fe0 100644 --- a/src/Light.cc +++ b/src/Light.cc @@ -20,6 +20,8 @@ Vector3f Light::is() const { return is_; } bool Light::isUse() const { return use; } +Vector3f PointLight::getCenter() const { return center; } + Vector3f PointLight::illumination(const HitRecord &hit, const vector &geometries) const { Vector3f shadingPoint = hit.point(); @@ -46,6 +48,10 @@ Vector3f PointLight::illumination(const HitRecord &hit, return specular_ + ambient_ + diffuse_; } +Vector3f AreaLight::getCenter() const { + return p1 + (p4 - p1) / 2 + (p2 - p1) / 2; +} + Vector3f AreaLight::illumination(const HitRecord &hit, const vector &geometries) const { Vector3f u = p4 - p1; @@ -54,7 +60,7 @@ Vector3f AreaLight::illumination(const HitRecord &hit, Vector3f color = Vector3f::Zero(); if (useCenter) { - color += PointLight(*this, p1 + (u + v) / 2).illumination(hit, geometries); + color += PointLight(*this, getCenter()).illumination(hit, geometries); } else { for (int y = 0; y < gridSize; ++y) for (int x = 0; x < gridSize; ++x) { diff --git a/src/Light.h b/src/Light.h index 7f21867..b64773b 100644 --- a/src/Light.h +++ b/src/Light.h @@ -18,6 +18,7 @@ public: virtual ~Light() = default; virtual Vector3f illumination(const HitRecord &, const vector &) const = 0; + virtual Vector3f getCenter() const = 0; protected: Light(Type type, const Vector3f &id, const Vector3f &is) @@ -36,6 +37,7 @@ public: void setGridSize(unsigned int); void setUseCenter(bool); void setIsUse(bool); + Type type() const; Vector3f id() const; Vector3f is() const; bool isUse() const; @@ -52,6 +54,9 @@ public: private: Vector3f p1, p2, p3, p4; + +public: + Vector3f getCenter() const override; }; class PointLight : public Light { @@ -67,6 +72,9 @@ public: private: Vector3f center; + +public: + Vector3f getCenter() const override; }; #endif // !LIGHT_H_ diff --git a/src/RayTracer.cc b/src/RayTracer.cc index 2953b37..f4c1835 100644 --- a/src/RayTracer.cc +++ b/src/RayTracer.cc @@ -1,5 +1,6 @@ #include "RayTracer.h" #include "HitRecord.h" +#include "Light.h" #include "Output.h" #include "Parser.h" #include "Progress.h" @@ -7,6 +8,7 @@ #include "Ray.h" #include +#include #include #include #include @@ -89,26 +91,22 @@ void RayTracer::render() { for (int j = 0; j < gridHeight; ++j) for (int i = 0; i < gridWidth; ++i) { Ray ray = getRay(x, y, i, j); - utils::Optional result = trace(ray); - if (result.hasValue()) { - accumulate += result.value() * raysPerPixel; - success += raysPerPixel; + for (int rayNum = 0; rayNum < raysPerPixel; ++rayNum) { + utils::Optional result = trace(ray); + if (result.hasValue()) { + accumulate += result.value(); + success++; + } } } if (!success) color = accumulate / success; } else { Ray ray = getRay(x, y); - priority_queue records; - for (auto g : geometries) { - Optional t = g->intersect(ray); - if (t.hasValue()) - records.push(HitRecord(t.value(), ray, g)); - } + Optional hitRecord = getHitRecord(ray); - if (!records.empty()) { - HitRecord hit = records.top(); - hit.calcNormal(); + if (hitRecord.hasValue()) { + HitRecord hit = hitRecord.value(); color = calculateColor(hit, y * width + x); } } @@ -130,6 +128,33 @@ Vector3f RayTracer::calculateColor(const HitRecord &hit, int i) const { return result; } +/** + * Find the nearest geometry to intersect + */ +Optional RayTracer::getHitRecord(Ray r) const { + priority_queue records; + for (auto g : geometries) { + Optional t = g->intersect(r); + if (t.hasValue()) + records.push(HitRecord(t.value(), r, g)); + } + + if (!records.empty()) { + HitRecord result = records.top(); + result.calcNormal(); + return Optional(result); + } + + return Optional::nullopt; +} + +Light *RayTracer::singleLightSource() const { + for (auto light : lights) + if (light->isUse()) + return light; + return nullptr; +} + // helper functions Ray getRay(int x, int y) { using namespace camera; @@ -151,21 +176,39 @@ void writeColor(int i, const Vector3f &color) { Output::current->b(i, color.z()); } -Vector3f trace(Ray r, int bounce, float prob) { +Vector3f RayTracer::trace(HitRecord hit, int bounce, float prob) const { float dice = utils::Random::get(); if (bounce && (dice > prob)) { - return Vector3f(1, 0, 1).array() * trace(r, bounce - 1, prob).array(); + return Vector3f(1, 0, 1).array() * trace(hit, bounce - 1, prob).array(); + } else { + Light *light = singleLightSource(); + Vector3f point = hit.point(); + Vector3f direction = (light->getCenter() - point).normalized(); + Ray shadowRay(point, direction); + + Geometry *geometry = hit.geometry(); + + for (auto g : geometries) + if (g != geometry && g->intersect(shadowRay).hasValue() && + g->type() == Geometry::Type::SPHERE) + return Vector3f::Zero(); + + return geometry->cd().array() * light->id().array() * + std::max(0.0f, hit.normal().dot(direction)); } return Vector3f(1, 1, 1); } -utils::Optional trace(Ray r) { - Vector3f color = - trace(r, Scene::current->maxBounce(), Scene::current->probTerminate()); +utils::Optional RayTracer::trace(Ray r) const { + Optional hitRecord = getHitRecord(r); + if (hitRecord.hasValue()) { + Vector3f color = trace(hitRecord.value(), Scene::current->maxBounce(), + Scene::current->probTerminate()); - if (color != Vector3f::Zero()) - return utils::Optional(color); + if (color != Vector3f::Zero()) + return utils::Optional(color); + } return utils::Optional::nullopt; } diff --git a/src/RayTracer.h b/src/RayTracer.h index e30b8d3..a92e763 100644 --- a/src/RayTracer.h +++ b/src/RayTracer.h @@ -3,6 +3,7 @@ #include "../external/json.hpp" #include "Geometry.h" +#include "HitRecord.h" #include "Light.h" #include "Output.h" #include "Scene.h" @@ -22,8 +23,12 @@ private: std::vector outputs; void parse(); - Vector3f calculateColor(const HitRecord &, int) const; void render(); + Optional getHitRecord(Ray) const; + Vector3f calculateColor(const HitRecord &, int) const; + Light *singleLightSource() const; + Optional trace(Ray) const; + Vector3f trace(HitRecord, int, float) const; }; #endif // !RAY_TRACER_H_ From b0fcb58741319a9bb5bd1677f84a874e750871b4 Mon Sep 17 00:00:00 2001 From: vonhyou Date: Wed, 20 Mar 2024 02:40:45 -0400 Subject: [PATCH 20/27] add dummy global illum --- src/RayTracer.cc | 47 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/src/RayTracer.cc b/src/RayTracer.cc index f4c1835..d6bac9c 100644 --- a/src/RayTracer.cc +++ b/src/RayTracer.cc @@ -99,7 +99,8 @@ void RayTracer::render() { } } } - if (!success) + + if (success) color = accumulate / success; } else { Ray ray = getRay(x, y); @@ -176,28 +177,48 @@ void writeColor(int i, const Vector3f &color) { Output::current->b(i, color.z()); } +Vector3f getRandomDirection() { +RETRY_RANDOM: + float x = utils::Random::get(); + float y = utils::Random::get(); + if (x * x + y * y > 1) + goto RETRY_RANDOM; + + return Vector3f(x, y, std::sqrt(1 - x * x - y * y)); +} + Vector3f RayTracer::trace(HitRecord hit, int bounce, float prob) const { - float dice = utils::Random::get(); - if (bounce && (dice > prob)) { - return Vector3f(1, 0, 1).array() * trace(hit, bounce - 1, prob).array(); + bool notFinish = bounce && (utils::Random::get() > prob); + Vector3f point = hit.point(); + Light *light = singleLightSource(); + Vector3f direction; + Geometry *geometry = hit.geometry(); + + if (notFinish) { + direction = point + getRandomDirection(); } else { - Light *light = singleLightSource(); - Vector3f point = hit.point(); - Vector3f direction = (light->getCenter() - point).normalized(); - Ray shadowRay(point, direction); - - Geometry *geometry = hit.geometry(); + direction = light->getCenter() - point; + } + direction.normalize(); + Ray ray(point, direction); + if (notFinish) { + Optional hitRecord = getHitRecord(ray); + if (hitRecord.hasValue()) { + Vector3f traceColor = trace(hitRecord.value(), bounce - 1, prob); + return traceColor.array() * geometry->cd().array() * + std::max(0.0f, hit.normal().dot(direction)); + } + return Vector3f::Zero(); + } else { for (auto g : geometries) - if (g != geometry && g->intersect(shadowRay).hasValue() && + if (g != geometry && g->intersect(ray).hasValue() && g->type() == Geometry::Type::SPHERE) return Vector3f::Zero(); return geometry->cd().array() * light->id().array() * std::max(0.0f, hit.normal().dot(direction)); } - - return Vector3f(1, 1, 1); } utils::Optional RayTracer::trace(Ray r) const { From bdbd81091c2b3c66e943b0ba22bdc955b66d4e2b Mon Sep 17 00:00:00 2001 From: vonhyou Date: Wed, 20 Mar 2024 03:27:01 -0400 Subject: [PATCH 21/27] add dummy global illum --- src/RayTracer.cc | 47 +++++++++++++++++++++++++---------------------- src/RayTracer.h | 2 ++ 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/RayTracer.cc b/src/RayTracer.cc index d6bac9c..2631274 100644 --- a/src/RayTracer.cc +++ b/src/RayTracer.cc @@ -1,6 +1,7 @@ #include "RayTracer.h" #include "HitRecord.h" #include "Light.h" +#include "Optional.h" #include "Output.h" #include "Parser.h" #include "Progress.h" @@ -132,12 +133,14 @@ Vector3f RayTracer::calculateColor(const HitRecord &hit, int i) const { /** * Find the nearest geometry to intersect */ -Optional RayTracer::getHitRecord(Ray r) const { +Optional RayTracer::getHitRecord(Ray r, const Geometry *self, + bool notSphere) const { priority_queue records; for (auto g : geometries) { Optional t = g->intersect(r); - if (t.hasValue()) - records.push(HitRecord(t.value(), r, g)); + if (t.hasValue() && g != self) + if (!notSphere || notSphere && g->type() != Geometry::Type::SPHERE) + records.push(HitRecord(t.value(), r, g)); } if (!records.empty()) { @@ -149,6 +152,14 @@ Optional RayTracer::getHitRecord(Ray r) const { return Optional::nullopt; } +Optional RayTracer::getHitRecord(Ray r, const Geometry *g) const { + return getHitRecord(r, g, false); +} + +Optional RayTracer::getHitRecord(Ray r) const { + return getHitRecord(r, nullptr, false); +} + Light *RayTracer::singleLightSource() const { for (auto light : lights) if (light->isUse()) @@ -194,31 +205,23 @@ Vector3f RayTracer::trace(HitRecord hit, int bounce, float prob) const { Vector3f direction; Geometry *geometry = hit.geometry(); - if (notFinish) { + if (notFinish) direction = point + getRandomDirection(); - } else { + else direction = light->getCenter() - point; - } + direction.normalize(); Ray ray(point, direction); - if (notFinish) { - Optional hitRecord = getHitRecord(ray); - if (hitRecord.hasValue()) { - Vector3f traceColor = trace(hitRecord.value(), bounce - 1, prob); - return traceColor.array() * geometry->cd().array() * - std::max(0.0f, hit.normal().dot(direction)); - } - return Vector3f::Zero(); - } else { - for (auto g : geometries) - if (g != geometry && g->intersect(ray).hasValue() && - g->type() == Geometry::Type::SPHERE) - return Vector3f::Zero(); + Optional hitRecord = getHitRecord(ray, geometry, !notFinish); + Vector3f traceColor = Vector3f::Zero(); + if (notFinish && hitRecord.hasValue()) + traceColor = trace(hitRecord.value(), bounce - 1, prob); + else if (!notFinish) + traceColor = light->id(); - return geometry->cd().array() * light->id().array() * - std::max(0.0f, hit.normal().dot(direction)); - } + return traceColor.array() * geometry->cd().array() * + std::max(0.0f, hit.normal().dot(direction)); } utils::Optional RayTracer::trace(Ray r) const { diff --git a/src/RayTracer.h b/src/RayTracer.h index a92e763..d3c635a 100644 --- a/src/RayTracer.h +++ b/src/RayTracer.h @@ -24,6 +24,8 @@ private: void parse(); void render(); + Optional getHitRecord(Ray, const Geometry *, bool) const; + Optional getHitRecord(Ray, const Geometry *) const; Optional getHitRecord(Ray) const; Vector3f calculateColor(const HitRecord &, int) const; Light *singleLightSource() const; From ebae7ccfafe7b12e763d0368b66ca162041da949 Mon Sep 17 00:00:00 2001 From: vonhyou Date: Wed, 20 Mar 2024 06:33:05 -0400 Subject: [PATCH 22/27] file update --- src/Random.h | 23 ----------------------- src/RayTracer.cc | 29 +++++++++++++++++------------ 2 files changed, 17 insertions(+), 35 deletions(-) delete mode 100644 src/Random.h diff --git a/src/Random.h b/src/Random.h deleted file mode 100644 index c0d3287..0000000 --- a/src/Random.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef RANDOM_H_ -#define RANDOM_H_ - -#include -#include -namespace utils { -class Random { -public: - /** - * A way to generate higher quality random number - * since C++ 11 - */ - static float get() { - std::default_random_engine generator( - std::chrono::system_clock::now().time_since_epoch().count()); - std::uniform_real_distribution distribution(0.0f, 1.0f); - - return distribution(generator); - } -}; -} // namespace utils - -#endif // !RANDOM_H_ diff --git a/src/RayTracer.cc b/src/RayTracer.cc index 2631274..f89f31c 100644 --- a/src/RayTracer.cc +++ b/src/RayTracer.cc @@ -5,12 +5,12 @@ #include "Output.h" #include "Parser.h" #include "Progress.h" -#include "Random.h" #include "Ray.h" #include #include #include +#include #include #include @@ -91,6 +91,9 @@ void RayTracer::render() { Vector3f accumulate = Vector3f::Zero(); for (int j = 0; j < gridHeight; ++j) for (int i = 0; i < gridWidth; ++i) { + + if (x != width / 2 || y != height / 2 || i || j) + ; // goto DEBUG_COLOR; Ray ray = getRay(x, y, i, j); for (int rayNum = 0; rayNum < raysPerPixel; ++rayNum) { utils::Optional result = trace(ray); @@ -112,6 +115,7 @@ void RayTracer::render() { color = calculateColor(hit, y * width + x); } } + DEBUG_COLOR: writeColor(y * width + x, clamp(color)); } } @@ -134,12 +138,13 @@ Vector3f RayTracer::calculateColor(const HitRecord &hit, int i) const { * Find the nearest geometry to intersect */ Optional RayTracer::getHitRecord(Ray r, const Geometry *self, - bool notSphere) const { + bool notRectangle) const { priority_queue records; for (auto g : geometries) { Optional t = g->intersect(r); if (t.hasValue() && g != self) - if (!notSphere || notSphere && g->type() != Geometry::Type::SPHERE) + if (!notRectangle || + notRectangle && g->type() != Geometry::Type::RECTANGLE) records.push(HitRecord(t.value(), r, g)); } @@ -190,8 +195,8 @@ void writeColor(int i, const Vector3f &color) { Vector3f getRandomDirection() { RETRY_RANDOM: - float x = utils::Random::get(); - float y = utils::Random::get(); + float x = (float)rand() / RAND_MAX; + float y = (float)rand() / RAND_MAX; if (x * x + y * y > 1) goto RETRY_RANDOM; @@ -199,25 +204,25 @@ RETRY_RANDOM: } Vector3f RayTracer::trace(HitRecord hit, int bounce, float prob) const { - bool notFinish = bounce && (utils::Random::get() > prob); + bool finish = !bounce || ((float)rand() / RAND_MAX < prob); Vector3f point = hit.point(); Light *light = singleLightSource(); Vector3f direction; Geometry *geometry = hit.geometry(); - if (notFinish) - direction = point + getRandomDirection(); - else + if (finish) direction = light->getCenter() - point; + else + direction = point + getRandomDirection(); direction.normalize(); Ray ray(point, direction); - Optional hitRecord = getHitRecord(ray, geometry, !notFinish); + Optional hitRecord = getHitRecord(ray, geometry, finish); Vector3f traceColor = Vector3f::Zero(); - if (notFinish && hitRecord.hasValue()) + if (!finish && hitRecord.hasValue()) traceColor = trace(hitRecord.value(), bounce - 1, prob); - else if (!notFinish) + else if (finish && !hitRecord.hasValue()) traceColor = light->id(); return traceColor.array() * geometry->cd().array() * From 87d3c2788e287b1e8811053dab07573f9696a2f3 Mon Sep 17 00:00:00 2001 From: vonhyou Date: Wed, 20 Mar 2024 16:53:55 -0400 Subject: [PATCH 23/27] fix area light illumination --- src/Light.cc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Light.cc b/src/Light.cc index c2f5fe0..ce29101 100644 --- a/src/Light.cc +++ b/src/Light.cc @@ -57,11 +57,10 @@ Vector3f AreaLight::illumination(const HitRecord &hit, Vector3f u = p4 - p1; Vector3f v = p2 - p1; - Vector3f color = Vector3f::Zero(); - if (useCenter) { - color += PointLight(*this, getCenter()).illumination(hit, geometries); + return PointLight(*this, getCenter()).illumination(hit, geometries); } else { + Vector3f color = Vector3f::Zero(); for (int y = 0; y < gridSize; ++y) for (int x = 0; x < gridSize; ++x) { Vector3f contribution = @@ -69,7 +68,6 @@ Vector3f AreaLight::illumination(const HitRecord &hit, .illumination(hit, geometries); color += contribution; } + return color / gridSize / gridSize; } - - return color / gridSize / gridSize; } From e59c6dbea4298bdba842ff420a68b462ee6839af Mon Sep 17 00:00:00 2001 From: vonhyou Date: Wed, 20 Mar 2024 20:11:32 -0400 Subject: [PATCH 24/27] update dummy global illum --- src/RayTracer.cc | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/RayTracer.cc b/src/RayTracer.cc index f89f31c..6b88d7b 100644 --- a/src/RayTracer.cc +++ b/src/RayTracer.cc @@ -8,6 +8,7 @@ #include "Ray.h" #include +#include #include #include #include @@ -102,6 +103,9 @@ void RayTracer::render() { success++; } } + + // std::cout << accumulate.transpose() << " (" << success << + // std::endl; } if (success) @@ -203,7 +207,23 @@ RETRY_RANDOM: return Vector3f(x, y, std::sqrt(1 - x * x - y * y)); } +Vector3f getGlobalRandDirection(Vector3f normal) { + Vector3f tangent = normal.cross(Vector3f::UnitX()); + if (tangent.norm() < 1e-6f) + tangent = normal.cross(Vector3f::UnitY()); + + tangent.normalize(); + Vector3f binormal = normal.cross(tangent); + Eigen::Matrix3f local2World; + local2World.col(0) = tangent; + local2World.col(1) = binormal.normalized(); + local2World.col(2) = normal.normalized(); + + return local2World * getRandomDirection(); +} + Vector3f RayTracer::trace(HitRecord hit, int bounce, float prob) const { +RETRY_TRACING: bool finish = !bounce || ((float)rand() / RAND_MAX < prob); Vector3f point = hit.point(); Light *light = singleLightSource(); @@ -213,15 +233,17 @@ Vector3f RayTracer::trace(HitRecord hit, int bounce, float prob) const { if (finish) direction = light->getCenter() - point; else - direction = point + getRandomDirection(); + direction = getGlobalRandDirection(hit.normal()); direction.normalize(); - Ray ray(point, direction); + Ray ray(point + hit.normal() * 1e-6, direction); Optional hitRecord = getHitRecord(ray, geometry, finish); Vector3f traceColor = Vector3f::Zero(); if (!finish && hitRecord.hasValue()) traceColor = trace(hitRecord.value(), bounce - 1, prob); + else if (!finish && !hitRecord.hasValue()) + goto RETRY_TRACING; else if (finish && !hitRecord.hasValue()) traceColor = light->id(); From a63aedc3238669bed69ba1c2ad4e1d284a09b729 Mon Sep 17 00:00:00 2001 From: vonhyou Date: Wed, 20 Mar 2024 23:37:20 -0400 Subject: [PATCH 25/27] finish global illumination --- src/Geometry.cc | 4 ++++ src/Geometry.h | 3 +++ src/Light.cc | 10 +++++++--- src/RayTracer.cc | 43 +++++++++++++++++++++++++++---------------- src/RayTracer.h | 1 - 5 files changed, 41 insertions(+), 20 deletions(-) diff --git a/src/Geometry.cc b/src/Geometry.cc index 1cd9c5a..6bc61bb 100644 --- a/src/Geometry.cc +++ b/src/Geometry.cc @@ -40,6 +40,8 @@ Vector3f Sphere::normal(const Vector3f &p) const { return (p - center).normalized(); } +Vector3f Sphere::sample() const { return center + Vector3f(radius, 0, 0); } + bool isInRectangle(const Vector3f &p, const Vector3f &a, const Vector3f &b, const Vector3f &c, const Vector3f &d, const Vector3f &n) { float s1 = (b - a).cross(p - a).dot(n); @@ -67,3 +69,5 @@ Optional Rectangle::intersect(const Ray &r) const { } Vector3f Rectangle::normal(const Vector3f &p) const { return normal_; } + +Vector3f Rectangle::sample() const { return p1; } diff --git a/src/Geometry.h b/src/Geometry.h index 2b8c947..e9e4d0f 100644 --- a/src/Geometry.h +++ b/src/Geometry.h @@ -20,6 +20,7 @@ public: virtual ~Geometry() = default; virtual Optional intersect(const Ray &) const = 0; virtual Vector3f normal(const Vector3f &) const = 0; + virtual Vector3f sample() const = 0; protected: Geometry(Type type, float ka, float kd, float ks, const Vector3f &ca, @@ -54,6 +55,7 @@ public: Optional intersect(const Ray &) const override; Vector3f normal(const Vector3f &) const override; + Vector3f sample() const override; private: float radius; @@ -70,6 +72,7 @@ public: Optional intersect(const Ray &) const override; Vector3f normal(const Vector3f &) const override; + Vector3f sample() const override; private: Vector3f p1, p2, p3, p4; diff --git a/src/Light.cc b/src/Light.cc index ce29101..c5d8b40 100644 --- a/src/Light.cc +++ b/src/Light.cc @@ -22,6 +22,10 @@ bool Light::isUse() const { return use; } Vector3f PointLight::getCenter() const { return center; } +bool lightOnSurface(Vector3f center, Geometry *g) { + return (g->sample() - center).dot(g->normal(center)) < 1e-5; +} + Vector3f PointLight::illumination(const HitRecord &hit, const vector &geometries) const { Vector3f shadingPoint = hit.point(); @@ -30,9 +34,9 @@ Vector3f PointLight::illumination(const HitRecord &hit, Ray shadowRay(shadingPoint, rayDirection); for (auto g : geometries) - if (g != geometry && g->intersect(shadowRay).hasValue() && - g->type() == Geometry::Type::SPHERE) - return Vector3f::Zero(); + if (g != geometry && g->intersect(shadowRay).hasValue()) + if (g->type() == Geometry::Type::SPHERE || !lightOnSurface(center, g)) + return Vector3f::Zero(); Vector3f ambient_ = geometry->ka() * geometry->ca().array() * Scene::current->ai().array(); diff --git a/src/RayTracer.cc b/src/RayTracer.cc index 6b88d7b..a403a4b 100644 --- a/src/RayTracer.cc +++ b/src/RayTracer.cc @@ -67,6 +67,11 @@ void RayTracer::parse() { lights.push_back(Parser::getLight(*i)); } +Vector3f gammaCorrection(Vector3f color, float gammaInv) { + return Vector3f(std::pow(color.x(), gammaInv), std::pow(color.y(), gammaInv), + std::pow(color.z(), gammaInv)); +} + /** * Render the current scene * @@ -109,7 +114,7 @@ void RayTracer::render() { } if (success) - color = accumulate / success; + color = gammaCorrection(accumulate / success, 1.0f / 2.1f); } else { Ray ray = getRay(x, y); Optional hitRecord = getHitRecord(ray); @@ -141,15 +146,12 @@ Vector3f RayTracer::calculateColor(const HitRecord &hit, int i) const { /** * Find the nearest geometry to intersect */ -Optional RayTracer::getHitRecord(Ray r, const Geometry *self, - bool notRectangle) const { +Optional RayTracer::getHitRecord(Ray r, const Geometry *self) const { priority_queue records; for (auto g : geometries) { Optional t = g->intersect(r); if (t.hasValue() && g != self) - if (!notRectangle || - notRectangle && g->type() != Geometry::Type::RECTANGLE) - records.push(HitRecord(t.value(), r, g)); + records.push(HitRecord(t.value(), r, g)); } if (!records.empty()) { @@ -161,12 +163,8 @@ Optional RayTracer::getHitRecord(Ray r, const Geometry *self, return Optional::nullopt; } -Optional RayTracer::getHitRecord(Ray r, const Geometry *g) const { - return getHitRecord(r, g, false); -} - Optional RayTracer::getHitRecord(Ray r) const { - return getHitRecord(r, nullptr, false); + return getHitRecord(r, nullptr); } Light *RayTracer::singleLightSource() const { @@ -199,8 +197,8 @@ void writeColor(int i, const Vector3f &color) { Vector3f getRandomDirection() { RETRY_RANDOM: - float x = (float)rand() / RAND_MAX; - float y = (float)rand() / RAND_MAX; + float x = ((float)rand() / RAND_MAX) * 2 - 1; + float y = ((float)rand() / RAND_MAX) * 2 - 1; if (x * x + y * y > 1) goto RETRY_RANDOM; @@ -222,6 +220,17 @@ Vector3f getGlobalRandDirection(Vector3f normal) { return local2World * getRandomDirection(); } +bool lightOnSurface(HitRecord hit, const Light *l) { + Vector3f center = l->getCenter(); + Geometry *g = hit.geometry(); + Geometry::Type type = g->type(); + if (type == Geometry::Type::RECTANGLE) { + return (g->sample() - center).dot(g->normal(center)) < 1e-5; + } + + return false; +} + Vector3f RayTracer::trace(HitRecord hit, int bounce, float prob) const { RETRY_TRACING: bool finish = !bounce || ((float)rand() / RAND_MAX < prob); @@ -238,14 +247,16 @@ RETRY_TRACING: direction.normalize(); Ray ray(point + hit.normal() * 1e-6, direction); - Optional hitRecord = getHitRecord(ray, geometry, finish); + Optional hitRecord = getHitRecord(ray, geometry); Vector3f traceColor = Vector3f::Zero(); if (!finish && hitRecord.hasValue()) traceColor = trace(hitRecord.value(), bounce - 1, prob); else if (!finish && !hitRecord.hasValue()) goto RETRY_TRACING; - else if (finish && !hitRecord.hasValue()) - traceColor = light->id(); + else if (finish) + if (!hitRecord.hasValue() || + (hitRecord.hasValue() && lightOnSurface(hitRecord.value(), light))) + traceColor = light->id(); return traceColor.array() * geometry->cd().array() * std::max(0.0f, hit.normal().dot(direction)); diff --git a/src/RayTracer.h b/src/RayTracer.h index d3c635a..d6ff470 100644 --- a/src/RayTracer.h +++ b/src/RayTracer.h @@ -24,7 +24,6 @@ private: void parse(); void render(); - Optional getHitRecord(Ray, const Geometry *, bool) const; Optional getHitRecord(Ray, const Geometry *) const; Optional getHitRecord(Ray) const; Vector3f calculateColor(const HitRecord &, int) const; From c60e4da2925988e874e90749729b93cc43c6eff8 Mon Sep 17 00:00:00 2001 From: vonhyou Date: Wed, 20 Mar 2024 23:46:51 -0400 Subject: [PATCH 26/27] reformat --- src/RayTracer.cc | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/RayTracer.cc b/src/RayTracer.cc index a403a4b..13d5ad8 100644 --- a/src/RayTracer.cc +++ b/src/RayTracer.cc @@ -8,12 +8,11 @@ #include "Ray.h" #include -#include #include #include -#include #include #include +#include using Eigen::VectorXi; using std::priority_queue; @@ -195,10 +194,16 @@ void writeColor(int i, const Vector3f &color) { Output::current->b(i, color.z()); } +float getRandomNumber() { + static std::uniform_real_distribution distribution(0.0, 1.0); + static std::mt19937 generator; + return distribution(generator); +} + Vector3f getRandomDirection() { RETRY_RANDOM: - float x = ((float)rand() / RAND_MAX) * 2 - 1; - float y = ((float)rand() / RAND_MAX) * 2 - 1; + float x = getRandomNumber() * 2 - 1; + float y = getRandomNumber() * 2 - 1; if (x * x + y * y > 1) goto RETRY_RANDOM; @@ -233,7 +238,7 @@ bool lightOnSurface(HitRecord hit, const Light *l) { Vector3f RayTracer::trace(HitRecord hit, int bounce, float prob) const { RETRY_TRACING: - bool finish = !bounce || ((float)rand() / RAND_MAX < prob); + bool finish = !bounce || (getRandomNumber() < prob); Vector3f point = hit.point(); Light *light = singleLightSource(); Vector3f direction; From e0ea2211376c914491618a9f871ac34f08fa302d Mon Sep 17 00:00:00 2001 From: vonhyou Date: Thu, 21 Mar 2024 16:44:36 -0400 Subject: [PATCH 27/27] small fix --- src/Parser.cc | 3 +-- src/RayTracer.cc | 12 +++++++++--- src/RayTracer.h | 10 ++++++---- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/Parser.cc b/src/Parser.cc index fb9fc21..abca50e 100644 --- a/src/Parser.cc +++ b/src/Parser.cc @@ -18,9 +18,8 @@ const Vector3f getVector3f(const nlohmann::json &j) { const VectorXi getRpp(const nlohmann::json &j) { VectorXi rpp(j.size()); - for (int i = 0; i < j.size(); ++i) { + for (int i = 0; i < j.size(); ++i) rpp[i] = j[i].get(); - } return rpp; } diff --git a/src/RayTracer.cc b/src/RayTracer.cc index 13d5ad8..c8244b8 100644 --- a/src/RayTracer.cc +++ b/src/RayTracer.cc @@ -173,7 +173,6 @@ Light *RayTracer::singleLightSource() const { return nullptr; } -// helper functions Ray getRay(int x, int y) { using namespace camera; return Ray(pos, pxUpperLeft + x * du + y * dv - pos); @@ -194,12 +193,14 @@ void writeColor(int i, const Vector3f &color) { Output::current->b(i, color.z()); } +// This should generate a higher quality random number float getRandomNumber() { static std::uniform_real_distribution distribution(0.0, 1.0); static std::mt19937 generator; return distribution(generator); } +// Generate a randon point on a unit hemisphere Vector3f getRandomDirection() { RETRY_RANDOM: float x = getRandomNumber() * 2 - 1; @@ -225,13 +226,13 @@ Vector3f getGlobalRandDirection(Vector3f normal) { return local2World * getRandomDirection(); } +// Check if a light source in on a surface (or really near) bool lightOnSurface(HitRecord hit, const Light *l) { Vector3f center = l->getCenter(); Geometry *g = hit.geometry(); Geometry::Type type = g->type(); - if (type == Geometry::Type::RECTANGLE) { + if (type == Geometry::Type::RECTANGLE) return (g->sample() - center).dot(g->normal(center)) < 1e-5; - } return false; } @@ -293,6 +294,11 @@ int getRayNumber(VectorXi data) { return data.size() == 2 ? data.y() : (data.size() == 3 ? data.z() : 1); } +/** + * Initialize camera parameters + * + * Construct the surface for viewing the world + */ void init() { width = Scene::current->width(); height = Scene::current->height(); diff --git a/src/RayTracer.h b/src/RayTracer.h index d6ff470..2da4613 100644 --- a/src/RayTracer.h +++ b/src/RayTracer.h @@ -10,6 +10,8 @@ #include +using std::vector; + class RayTracer { public: RayTracer(const nlohmann::json &j) : json(j) {} @@ -17,10 +19,10 @@ public: private: nlohmann::json json; - std::vector scenes; - std::vector lights; - std::vector geometries; - std::vector outputs; + vector scenes; + vector lights; + vector geometries; + vector outputs; void parse(); void render();