diff --git a/assets/cornell_box_demo.json b/assets/cornell_box_demo.json new file mode 100644 index 0000000..2d46105 --- /dev/null +++ b/assets/cornell_box_demo.json @@ -0,0 +1,365 @@ +{ + "geometry": [ + { + "comment": "back_wall", + "type": "rectangle", + "p2": [ + 556, + 0, + -559 + ], + "p1": [ + 0, + 0, + -559 + ], + "p4": [ + 0, + 548.8, + -559 + ], + "p3": [ + 556, + 548.8, + -559 + ], + "ac": [ + 1, + 1, + 1 + ], + "dc": [ + 1, + 1, + 1 + ], + "sc": [ + 0, + 0, + 0 + ], + "ka": 0, + "kd": 0.5, + "ks": 0, + "pc": 0 + }, + { + "comment": "right_wall", + "type": "rectangle", + "p1": [ + 556, + 0, + -559 + ], + "p2": [ + 556, + 0, + 0 + ], + "p3": [ + 556, + 548.8, + 0 + ], + "p4": [ + 556, + 548.8, + -559 + ], + "ac": [ + 1, + 0, + 0 + ], + "dc": [ + 1, + 0, + 0 + ], + "sc": [ + 0, + 0, + 0 + ], + "ka": 0, + "kd": 0.5, + "ks": 0, + "pc": 0 + }, + { + "comment": "left_wall", + "type": "rectangle", + "p2": [ + 0, + 0, + -559 + ], + "p1": [ + 0, + 0, + 0 + ], + "p4": [ + 0, + 548.8, + 0 + ], + "p3": [ + 0, + 548.8, + -559 + ], + "ac": [ + 0, + 1, + 0 + ], + "dc": [ + 0, + 1, + 0 + ], + "sc": [ + 0, + 0, + 0 + ], + "ka": 0, + "kd": 0.5, + "ks": 0, + "pc": 0 + }, + { + "comment": "ceiling", + "type": "rectangle", + "p1": [ + 0, + 548.8, + 0 + ], + "p2": [ + 0, + 548.8, + -559 + ], + "p3": [ + 556, + 548.8, + -559.0 + ], + "p4": [ + 556, + 548.8, + 0 + ], + "ac": [ + 1, + 1, + 1 + ], + "dc": [ + 1, + 1, + 1 + ], + "sc": [ + 0, + 0, + 0 + ], + "ka": 0, + "kd": 1, + "ks": 0, + "pc": 0 + }, + { + "comment": "floor", + "type": "rectangle", + "p1": [ + 0, + 0, + 0 + ], + "p4": [ + 0, + 0, + -559 + ], + "p3": [ + 556, + 0, + -559.0 + ], + "p2": [ + 556, + 0, + 0 + ], + "ac": [ + 1, + 1, + 1 + ], + "dc": [ + 1, + 1, + 1 + ], + "sc": [ + 0, + 0, + 0 + ], + "ka": 0, + "kd": 0.5, + "ks": 0, + "pc": 0 + }, + { + "type": "sphere", + "centre": [ + 300, + 228, + -228 + ], + "radius": 80, + "ac": [ + 1, + 1, + 1 + ], + "dc": [ + 0, + 0, + 1 + ], + "sc": [ + 1, + 1, + 1 + ], + "ka": 0, + "kd": 1, + "ks": 1, + "pc": 100 + }, + { + "type": "sphere", + "centre": [ + 140, + 228, + -228 + ], + "radius": 80, + "ac": [ + 1, + 1, + 1 + ], + "dc": [ + 1, + 1, + 1 + ], + "sc": [ + 1, + 1, + 1 + ], + "ka": 0, + "kd": 1, + "ks": 1, + "pc": 100 + }, + { + "type": "sphere", + "centre": [ + 460, + 228, + -228 + ], + "radius": 80, + "ac": [ + 1, + 1, + 1 + ], + "dc": [ + 1, + 1, + 1 + ], + "sc": [ + 1, + 1, + 1 + ], + "ka": 0, + "kd": 1, + "ks": 1, + "pc": 100 + } + ], + "light": [ + { + "type": "point", + "centre": [ + 278, + 540, + -279.5 + ], + "id": [ + 1, + 1, + 1 + ], + "is": [ + 1, + 1, + 1 + ] + } + ], + "output": [ + { + "filename": "cornell_box_demo.ppm", + "size": [ + 500, + 500 + ], + "lookat": [ + 0, + 0, + -1 + ], + "up": [ + 0, + 1, + 0 + ], + "fov": 40, + "centre": [ + 278, + 273, + 800 + ], + "ai": [ + 1, + 1, + 1 + ], + "bkc": [ + 0.5, + 0.5, + 0.5 + ], + "globalillum": true, + "raysperpixel": [ + 10, + 10 + ], + "maxbounces": 3, + "probterminate": 0.3333 + } + ] +} diff --git a/src/Parser.cc b/src/Parser.cc index abca50e..3fee6ef 100644 --- a/src/Parser.cc +++ b/src/Parser.cc @@ -39,8 +39,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)); + sc->setMaxBounce(j.value("maxbounces", 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 c8244b8..155ab2f 100644 --- a/src/RayTracer.cc +++ b/src/RayTracer.cc @@ -18,7 +18,6 @@ using Eigen::VectorXi; using std::priority_queue; // help function declarations -Ray getRay(int, int); Ray getRay(int, int, int, int); void writeColor(int, const Vector3f &); utils::Optional trace(Ray r); @@ -27,6 +26,7 @@ Vector3f clamp(const Vector3f &); namespace camera { int width, height, gridWidth, gridHeight, raysPerPixel; Vector3f pos, u, v, du, dv, vpUpperLeft, pxUpperLeft, gdu, gdv; +bool globalIllum, antiAliasing; void init(); } // namespace camera @@ -91,39 +91,27 @@ void RayTracer::render() { for (int x = 0; x < width; ++x) { 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) { - - if (x != width / 2 || y != height / 2 || i || j) - ; // goto DEBUG_COLOR; + int success = 0; + Vector3f accumulate = Vector3f::Zero(); + for (int j = 0; j < gridHeight; ++j) + for (int i = 0; i < gridWidth; ++i) { + for (int rayNum = 0; rayNum < raysPerPixel; ++rayNum) { Ray ray = getRay(x, y, i, j); - for (int rayNum = 0; rayNum < raysPerPixel; ++rayNum) { - utils::Optional result = trace(ray); - if (result.hasValue()) { - accumulate += result.value(); - success++; - } + Optional result = trace(ray); + if (result.hasValue()) { + accumulate += result.value(); + success++; } - - // std::cout << accumulate.transpose() << " (" << success << - // std::endl; } - - if (success) - color = gammaCorrection(accumulate / success, 1.0f / 2.1f); - } else { - Ray ray = getRay(x, y); - Optional hitRecord = getHitRecord(ray); - - if (hitRecord.hasValue()) { - HitRecord hit = hitRecord.value(); - color = calculateColor(hit, y * width + x); } + + if (success) { + if (globalIllum) + color = gammaCorrection(accumulate / success, 1.0f / 2.1f); + else + color = accumulate / success; } - DEBUG_COLOR: + writeColor(y * width + x, clamp(color)); } } @@ -133,7 +121,7 @@ void RayTracer::render() { /** * Calculate color using phong model */ -Vector3f RayTracer::calculateColor(const HitRecord &hit, int i) const { +Vector3f RayTracer::calculateColor(const HitRecord &hit) const { Vector3f result(0, 0, 0); for (auto light : lights) result += light->isUse() ? light->illumination(hit, geometries) @@ -173,14 +161,22 @@ Light *RayTracer::singleLightSource() const { return nullptr; } -Ray getRay(int x, int y) { - using namespace camera; - return Ray(pos, pxUpperLeft + x * du + y * dv - pos); +// 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); } 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); + Vector3f offset = Vector3f::Zero(); + + if (globalIllum || antiAliasing) + offset = getRandomNumber() * gdu + getRandomNumber() * gdv; + + return Ray(pos, + vpUpperLeft + x * du + i * gdu + y * dv + j * gdv + offset - pos); } Vector3f clamp(const Vector3f &color) { @@ -193,13 +189,6 @@ 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: @@ -268,17 +257,23 @@ RETRY_TRACING: std::max(0.0f, hit.normal().dot(direction)); } -utils::Optional RayTracer::trace(Ray r) const { +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 (!camera::globalIllum) { + if (hitRecord.hasValue()) + return Optional(calculateColor(hitRecord.value())); + else if (camera::antiAliasing) + return Optional(Scene::current->backgroundColor()); + } else { + if (hitRecord.hasValue()) { + Vector3f color = trace(hitRecord.value(), Scene::current->maxBounce(), + Scene::current->probTerminate()); - if (color != Vector3f::Zero()) - return utils::Optional(color); + return Optional(color); + } } - return utils::Optional::nullopt; + return Optional::nullopt; } namespace camera { @@ -314,7 +309,12 @@ void init() { vpUpperLeft = pos + lookAt - u / 2.0 - v / 2.0; pxUpperLeft = vpUpperLeft + (du + dv) / 2.0; - VectorXi data = Scene::current->raysPerPixel(); + globalIllum = Scene::current->globalIllum(); + antiAliasing = Scene::current->antiAliasing(); + + VectorXi data = !(globalIllum || antiAliasing) + ? VectorXi(1) + : Scene::current->raysPerPixel(); gridWidth = getGridWidth(data); gridHeight = getGridHeight(data); raysPerPixel = getRayNumber(data); diff --git a/src/RayTracer.h b/src/RayTracer.h index 2da4613..06bf7b1 100644 --- a/src/RayTracer.h +++ b/src/RayTracer.h @@ -28,7 +28,7 @@ private: void render(); Optional getHitRecord(Ray, const Geometry *) const; Optional getHitRecord(Ray) const; - Vector3f calculateColor(const HitRecord &, int) const; + Vector3f calculateColor(const HitRecord &) const; Light *singleLightSource() const; Optional trace(Ray) const; Vector3f trace(HitRecord, int, float) const; diff --git a/src/Scene.cc b/src/Scene.cc index 12c3e27..f8f561e 100644 --- a/src/Scene.cc +++ b/src/Scene.cc @@ -12,6 +12,8 @@ float Scene::fov() { return fov_; } bool Scene::globalIllum() { return globalIllum_; } +bool Scene::antiAliasing() { return antialiasing_; } + int Scene::maxBounce() { return maxBounce_; } float Scene::probTerminate() { return probTerminate_; } diff --git a/src/Scene.h b/src/Scene.h index fe033da..53b0ccf 100644 --- a/src/Scene.h +++ b/src/Scene.h @@ -41,6 +41,7 @@ public: int height(); float fov(); bool globalIllum(); + bool antiAliasing(); int maxBounce(); float probTerminate(); Vector3f ai() const;