diff --git a/.gitignore b/.gitignore index ead2c23..5194dce 100644 --- a/.gitignore +++ b/.gitignore @@ -6,8 +6,11 @@ build/ /data/* !/data/README.txt +!/data/fireplace +!/data/subdiv +!/data/parallax +!/data/fractal.obj /result* -/cmake-build-debug # Latex stuff *.aux @@ -17,4 +20,9 @@ build/ *.out *.pdf *.synctex.gz -*.json \ No newline at end of file +*.json +*__latexindent_temp.tex + +# Mac Stuff +.DS_Store + diff --git a/CMakeLists.txt b/CMakeLists.txt index 621f203..b37baeb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) project(CG1_Tracer LANGUAGES CXX) -set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) if(NOT WIN32) @@ -38,3 +38,7 @@ target_link_libraries(tracey_ex1 tracey) add_executable(tracey_ex2 ex2.cpp) target_link_libraries(tracey_ex2 tracey) + + + + diff --git a/README.md b/README.md index c472a1d..8f01e7d 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +# Build / Setup Prozess +Anweisungen ausgelagert in [BUILD_INSTRUCTIONS.md](BUILD_INSTRUCTIONS.md) + # Git Grundlagen / Workflow Git Spickzettel: https://files.morr.cc/git-spickzettel.png @@ -8,7 +11,7 @@ Angepasst von https://medium.com/@topspinj/how-to-git-rebase-into-a-forked-repo- Das Musterlösungs-Repository als remote mit Namen _upstream_ (oder ähnlich) hinzufügen: -`git remote add upstream gogs@git.cg.cs.tu-bs.de:CG1/WS2021.git` +`git remote add upstream gogs@git.cg.cs.tu-bs.de:CG1_WS2223/Base.git` Alle Branches von _upstream_ und deren Änderungen herunterladen @@ -32,4 +35,4 @@ hier kann man dann noch ggf. selbst Hand anlegen und die Änderungen dann wieder `git push origin master` -evtl. muss noch `--force` angegeben werden \ No newline at end of file +evtl. muss noch `--force` angegeben werden diff --git a/camera/perspectivecamera.cpp b/camera/perspectivecamera.cpp index 03ef4aa..63bc9a1 100644 --- a/camera/perspectivecamera.cpp +++ b/camera/perspectivecamera.cpp @@ -1,20 +1,8 @@ #include "camera/perspectivecamera.h" -#include -PerspectiveCamera::PerspectiveCamera() : forwardDirection(0, 0, 1), upDirection(0, 1, 0), fovAngle(70) {} +PerspectiveCamera::PerspectiveCamera() : forwardDirection(0, 0, 1), upDirection(0, 1, 0), rightDirection(1, 0, 0) { setFovAngle(70); } Ray PerspectiveCamera::createRay(float x, float y) const { - // Set up a left-handed coordinate system, - // in which the camera looks along the positive z-Axis - - Vector3d normalVector = normalized(crossProduct(upDirection, forwardDirection)); - - // Orthogonolize upDirection, to avoid skewing the image - Vector3d orthogonalUpDirection = -crossProduct(normalVector, forwardDirection); - - Vector3d normalVector_fov = normalVector * std::abs(tan(this->fovAngle / 360.0f * PI)); - Vector3d upVector_fov = orthogonalUpDirection * std::abs(tan(this->fovAngle / 360.0f * PI)); - Vector3d directionVector = normalized(forwardDirection + x * normalVector_fov + y * upVector_fov); - - return Ray {this->position, directionVector}; + // Create the ray + return Ray(this->position, x * this->rightDirection + y * this->upDirection + focus * this->forwardDirection); } diff --git a/camera/perspectivecamera.h b/camera/perspectivecamera.h index 5b18bea..638f392 100644 --- a/camera/perspectivecamera.h +++ b/camera/perspectivecamera.h @@ -12,9 +12,26 @@ public: // Set void setPosition(Vector3d const &position) { this->position = position; } - void setForwardDirection(Vector3d const &forwardDirection) { this->forwardDirection = normalized(forwardDirection); } - void setUpDirection(Vector3d const &upDirection) { this->upDirection = normalized(upDirection); } - void setFovAngle(float fovAngle) { this->fovAngle = fovAngle; } + void setForwardDirection(Vector3d const &forwardDirection) { + // IMPLEMENT ME + // Set up a left-handed coordinate system, + // in which the camera looks along the positive z-Axis + // Set up a left-handed coordinate system, + // in which the camera looks along the positive z-Axis + std::tie(this->forwardDirection, this->upDirection, this->rightDirection) = orthoNormalized(forwardDirection, this->upDirection, crossProduct(this->upDirection, forwardDirection)); + } + void setUpDirection(Vector3d const &upDirection) { + // IMPLEMENT ME + // Set up a left-handed coordinate system, + // in which the camera looks along the positive z-Axis + // Set up a left-handed coordinate system, + // in which the camera looks along the positive z-Axis + std::tie(this->forwardDirection, this->upDirection, this->rightDirection) = orthoNormalized(this->forwardDirection, upDirection, crossProduct(upDirection, this->forwardDirection)); + } + void setFovAngle(float fovAngle) { + // Calculate the focus + this->focus = 1.0f / std::tan((fovAngle * PI / 180) / 2.0f); + } // Camera functions Ray createRay(float x, float y) const override; @@ -23,7 +40,8 @@ protected: Vector3d position; Vector3d forwardDirection; Vector3d upDirection; - float fovAngle; + Vector3d rightDirection; + float focus; }; #endif diff --git a/common/common.h b/common/common.h index 3d47b8f..08f92c8 100644 --- a/common/common.h +++ b/common/common.h @@ -4,7 +4,23 @@ #include #ifndef EPSILON -#define EPSILON 1E-4f +#define EPSILON 1E-6f +#endif + +#ifndef SPLT_EPS +#define SPLT_EPS 4 * EPSILON +#endif + +#ifndef LGT_EPS +#define LGT_EPS 5E-5f +#endif + +#ifndef REFR_EPS +#define REFR_EPS 1E-4f +#endif + +#ifndef NORM_EPS +#define NORM_EPS 1E-12f #endif #ifndef INFINITY diff --git a/common/ray.cpp b/common/ray.cpp new file mode 100644 index 0000000..2ec18a8 --- /dev/null +++ b/common/ray.cpp @@ -0,0 +1,3 @@ +#include "ray.h" + +int Ray::rayCount = 0; diff --git a/common/ray.h b/common/ray.h index a7ab68a..060e290 100644 --- a/common/ray.h +++ b/common/ray.h @@ -23,10 +23,14 @@ struct Ray { Vector3d bitangent; // Constructor - Ray(Vector3d const &origin = Vector3d(0, 0, 0), Vector3d const &direction = Vector3d(0, 0, 1)) - : origin(origin), direction(normalized(direction)) { + Ray(Vector3d const &origin = Vector3d(0, 0, 0), Vector3d const &direction = Vector3d(0, 0, 1)) : origin(origin), direction(normalized(direction)) { + ++rayCount; } + inline int getRemainingBounces() const { return remainingBounces; } + + static inline void resetRayCount() { rayCount = 0; } + static inline int getRayCount() { return rayCount; } private: #ifndef ICG_RAY_BOUNCES @@ -35,6 +39,7 @@ private: int remainingBounces = ICG_RAY_BOUNCES; #endif + static int rayCount; }; #endif diff --git a/common/vector2d.cpp b/common/vector2d.cpp index 540b804..201ac00 100644 --- a/common/vector2d.cpp +++ b/common/vector2d.cpp @@ -1,6 +1,7 @@ #include "common/vector2d.h" +#include "common/common.h" +#include #include -#include // Access operators //////////////////////////////////////////////////////////// @@ -76,18 +77,14 @@ Vector2d &operator/=(Vector2d &left, float right) { // Useful functions //////////////////////////////////////////////////////////// -Vector2d componentProduct(const Vector2d &left, const Vector2d &right) { - return Vector2d(left.u * right.u, left.v * right.v); -} +Vector2d componentProduct(const Vector2d &left, const Vector2d &right) { return Vector2d(left.u * right.u, left.v * right.v); } -Vector2d componentQuotient(const Vector2d &left, const Vector2d &right) { - return Vector2d(left.u / right.u, left.v / right.v); -} +Vector2d componentQuotient(const Vector2d &left, const Vector2d &right) { return Vector2d(left.u / right.u, left.v / right.v); } float dotProduct(Vector2d const &left, Vector2d const &right) { return left.u * right.u + left.v * right.v; } float length(Vector2d const &c) { return std::sqrt(dotProduct(c, c)); } -Vector2d normalized(Vector2d const &v) { return v / length(v); } +Vector2d normalized(Vector2d const &v) { return v / std::max(length(v), NORM_EPS); } void normalize(Vector2d *v) { *v = normalized(*v); } diff --git a/common/vector3d.cpp b/common/vector3d.cpp index cc301ba..fe48669 100644 --- a/common/vector3d.cpp +++ b/common/vector3d.cpp @@ -1,6 +1,7 @@ #include "common/vector3d.h" +#include "common/common.h" +#include #include -#include // Access operators //////////////////////////////////////////////////////////// @@ -34,35 +35,27 @@ float const &Vector3d::operator[](int const dimension) const { // Comparison operators //////////////////////////////////////////////////////// -bool operator==(Vector3d const &left, Vector3d const &right) { - return (left.x == right.x && left.y == right.y && left.z == right.z); -} +bool operator==(Vector3d const &left, Vector3d const &right) { return (left.x == right.x && left.y == right.y && left.z == right.z); } bool operator!=(Vector3d const &left, Vector3d const &right) { return !(left == right); } // Arithmetic operators //////////////////////////////////////////////////////// -Vector3d operator+(Vector3d const &left, Vector3d const &right) { - return Vector3d(left.x + right.x, left.y + right.y, left.z + right.z); -} +Vector3d operator+(Vector3d const &left, Vector3d const &right) { return Vector3d(left.x + right.x, left.y + right.y, left.z + right.z); } Vector3d operator-(Vector3d const &right) { return Vector3d(-right.x, -right.y, -right.z); } -Vector3d operator-(Vector3d const &left, Vector3d const &right) { - return Vector3d(left.x - right.x, left.y - right.y, left.z - right.z); -} +Vector3d operator-(Vector3d const &left, Vector3d const &right) { return Vector3d(left.x - right.x, left.y - right.y, left.z - right.z); } -Vector3d operator*(Vector3d const &left, float right) { - return Vector3d(left.x * right, left.y * right, left.z * right); -} +Vector3d operator*(Vector3d const &left, float right) { return Vector3d(left.x * right, left.y * right, left.z * right); } -Vector3d operator*(float left, Vector3d const &right) { - return Vector3d(left * right.x, left * right.y, left * right.z); -} +Vector3d operator*(float left, Vector3d const &right) { return Vector3d(left * right.x, left * right.y, left * right.z); } -Vector3d operator/(Vector3d const &left, float right) { - return Vector3d(left.x / right, left.y / right, left.z / right); -} +Vector3d operator*(Vector3d const &left, Vector3d const &right) { return Vector3d(left.x * right.x, left.y * right.y, left.z * right.z); } + +Vector3d operator/(Vector3d const &left, float right) { return Vector3d(left.x / right, left.y / right, left.z / right); } + +Vector3d operator/(Vector3d const &left, Vector3d const &right) { return Vector3d(left.x / right.x, left.y / right.y, left.z / right.z); } // Assignment operators //////////////////////////////////////////////////////// @@ -87,6 +80,13 @@ Vector3d &operator*=(Vector3d &left, float right) { return left; } +Vector3d &operator*=(Vector3d &left, Vector3d const &right) { + left.x *= right.x; + left.y *= right.y; + left.z *= right.z; + return left; +} + Vector3d &operator/=(Vector3d &left, float right) { left.x /= right; left.y /= right; @@ -94,27 +94,34 @@ Vector3d &operator/=(Vector3d &left, float right) { return left; } +Vector3d &operator/=(Vector3d &left, Vector3d const &right) { + left.x /= right.x; + left.y /= right.y; + left.z /= right.z; + return left; +} + // Useful functions //////////////////////////////////////////////////////////// -Vector3d componentProduct(const Vector3d &left, const Vector3d &right) { - return Vector3d(left.x * right.x, left.y * right.y, left.z * right.z); -} +Vector3d componentProduct(const Vector3d &left, const Vector3d &right) { return Vector3d(left.x * right.x, left.y * right.y, left.z * right.z); } -Vector3d componentQuotient(const Vector3d &left, const Vector3d &right) { - return Vector3d(left.x / right.x, left.y / right.y, left.z / right.z); -} +Vector3d componentQuotient(const Vector3d &left, const Vector3d &right) { return Vector3d(left.x / right.x, left.y / right.y, left.z / right.z); } -Vector3d crossProduct(Vector3d const &left, Vector3d const &right) { - return Vector3d(left.y * right.z - left.z * right.y, left.z * right.x - left.x * right.z, - left.x * right.y - left.y * right.x); -} +Vector3d crossProduct(Vector3d const &left, Vector3d const &right) { return Vector3d(left.y * right.z - left.z * right.y, left.z * right.x - left.x * right.z, left.x * right.y - left.y * right.x); } -float dotProduct(Vector3d const &left, Vector3d const &right) { - return left.x * right.x + left.y * right.y + left.z * right.z; -} +float dotProduct(Vector3d const &left, Vector3d const &right) { return left.x * right.x + left.y * right.y + left.z * right.z; } float length(Vector3d const &v) { return std::sqrt(dotProduct(v, v)); } -Vector3d normalized(Vector3d const &v) { return v / length(v); } +Vector3d normalized(Vector3d const &v) { return v / std::max(length(v), NORM_EPS); } void normalize(Vector3d *v) { *v = normalized(*v); } + +std::tuple orthoNormalized(Vector3d const &u, Vector3d const &v, Vector3d const &w) { + // using gram-schmidt orthonormalization + auto ret_u = normalized(u); + auto ret_v = normalized(v - dotProduct(ret_u, v) * ret_u); + auto ret_w = normalized(w - dotProduct(ret_u, w) * ret_u - dotProduct(ret_v, w) * ret_v); + + return std::make_tuple(ret_u, ret_v, ret_w); +} \ No newline at end of file diff --git a/common/vector3d.h b/common/vector3d.h index da1746d..f4baf83 100644 --- a/common/vector3d.h +++ b/common/vector3d.h @@ -1,6 +1,8 @@ #ifndef VECTOR3D_H #define VECTOR3D_H +#include + struct Vector3d { // Components float x, y, z; @@ -27,13 +29,17 @@ Vector3d operator-(Vector3d const &right); Vector3d operator-(Vector3d const &left, Vector3d const &right); Vector3d operator*(Vector3d const &left, float right); Vector3d operator*(float left, Vector3d const &right); +Vector3d operator*(Vector3d const &left, Vector3d const &right); Vector3d operator/(Vector3d const &left, float right); +Vector3d operator/(Vector3d const &left, Vector3d const &right); // Assignment operators Vector3d &operator+=(Vector3d &left, Vector3d const &right); Vector3d &operator-=(Vector3d &left, Vector3d const &right); Vector3d &operator*=(Vector3d &left, float right); +Vector3d &operator*=(Vector3d &left, Vector3d const &right); Vector3d &operator/=(Vector3d &left, float right); +Vector3d &operator/=(Vector3d &left, Vector3d const &right); // Useful functions Vector3d componentProduct(Vector3d const &left, Vector3d const &right); @@ -43,5 +49,6 @@ float dotProduct(Vector3d const &left, Vector3d const &right); float length(Vector3d const &v); Vector3d normalized(Vector3d const &v); void normalize(Vector3d *v); +std::tuple orthoNormalized(Vector3d const &u, Vector3d const &v, Vector3d const &w); #endif diff --git a/ex1.cpp b/ex1.cpp index 0461208..37bd7f0 100644 --- a/ex1.cpp +++ b/ex1.cpp @@ -11,42 +11,42 @@ #include "shader/flatshader.h" int main() { - // Let's create a simple cornell box scene... - SimpleScene scene; + // Let's create a simple cornell box scene... + SimpleScene scene; - // Add shaders for the walls - auto red = std::make_shared(Color(1.0f, 0.3f, 0.2f)); - auto white = std::make_shared(Color(1.0f, 1.0f, 1.0f)); - auto blue = std::make_shared(Color(0.2f, 0.3f, 1.0f)); + // Add shaders for the walls + auto red = std::make_shared(Color(1.0f, 0.3f, 0.2f)); + auto white = std::make_shared(Color(1.0f, 1.0f, 1.0f)); + auto blue = std::make_shared(Color(0.2f, 0.3f, 1.0f)); - // Add shaders for the objects - auto green = std::make_shared(Color(0.0f, 1.0f, 0.0f)); - auto purple = std::make_shared(Color(0.5f, 0.2f, 1.0f)); - auto orange = std::make_shared(Color(1.0f, 0.5f, 0.0f)); + // Add shaders for the objects + auto green = std::make_shared(Color(0.0f, 1.0f, 0.0f)); + auto purple = std::make_shared(Color(0.5f, 0.2f, 1.0f)); + auto orange = std::make_shared(Color(1.0f, 0.5f, 0.0f)); - // Set up the cornell box walls - scene.add(std::make_shared(Vector3d(0.0f, 0.0f, +5.0f), Vector3d(0.0f, 0.0f, -1.0f), purple)); - scene.add(std::make_shared(Vector3d(0.0f, 0.0f, -5.0f), Vector3d(0.0f, 0.0f, +1.0f), purple)); - scene.add(std::make_shared(Vector3d(0.0f, +5.0f, 0.0f), Vector3d(0.0f, -1.0f, 0.0f), white)); - scene.add(std::make_shared(Vector3d(0.0f, -5.0f, 0.0f), Vector3d(0.0f, +1.0f, 0.0f), white)); - scene.add(std::make_shared(Vector3d(+5.0f, 0.0f, 0.0f), Vector3d(-1.0f, 0.0f, 0.0f), blue)); - scene.add(std::make_shared(Vector3d(-5.0f, 0.0f, 0.0f), Vector3d(+1.0f, 0.0f, 0.0f), red)); + // Set up the cornell box walls + scene.add(std::make_shared(Vector3d(0.0f, 0.0f, +5.0f), Vector3d(0.0f, 0.0f, -1.0f), purple)); + scene.add(std::make_shared(Vector3d(0.0f, 0.0f, -5.0f), Vector3d(0.0f, 0.0f, +1.0f), purple)); + scene.add(std::make_shared(Vector3d(0.0f, +5.0f, 0.0f), Vector3d(0.0f, -1.0f, 0.0f), white)); + scene.add(std::make_shared(Vector3d(0.0f, -5.0f, 0.0f), Vector3d(0.0f, +1.0f, 0.0f), white)); + scene.add(std::make_shared(Vector3d(+5.0f, 0.0f, 0.0f), Vector3d(-1.0f, 0.0f, 0.0f), blue)); + scene.add(std::make_shared(Vector3d(-5.0f, 0.0f, 0.0f), Vector3d(+1.0f, 0.0f, 0.0f), red)); - // Add a sphere - scene.add(std::make_shared(Vector3d(-3.0f, 0.0f, 0.0f), 1.5f, green)); - scene.add(std::make_shared(Vector3d(0.0f, -5.0f, -4.0f), Vector3d(0.0f, -3.0f, 0.0f), - Vector3d(5.0f, -2.0f, -3.0f), orange)); + // Add a sphere + scene.add(std::make_shared(Vector3d(-3.0f, 0.0f, 0.0f), 1.5f, green)); + scene.add(std::make_shared(Vector3d(0.0f, -5.0f, -4.0f), Vector3d(0.0f, -3.0f, 0.0f), + Vector3d(5.0f, -2.0f, -3.0f), orange)); - // Set up the camera - PerspectiveCamera camera; - camera.setFovAngle(70); - camera.setPosition(Vector3d(-2.5f, 2.5f, -10.0f)); - camera.setForwardDirection(Vector3d(0.25f, -0.33f, 1.0f)); - camera.setUpDirection(Vector3d(0.2f, 1.0f, 0.0f)); + // Set up the camera + PerspectiveCamera camera; + camera.setFovAngle(70); + camera.setPosition(Vector3d(-2.5f, 2.5f, -10.0f)); + camera.setForwardDirection(Vector3d(0.25f, -0.33f, 1.0f)); + camera.setUpDirection(Vector3d(0.2f, 1.0f, 0.0f)); - // Render the scene - SimpleRenderer renderer; - renderer.renderImage(scene, camera, 512, 512).save("result.png"); + // Render the scene + SimpleRenderer renderer; + renderer.renderImage(scene, camera, 512, 512).save("result.png"); - return 0; + return 0; } diff --git a/ex2.cpp b/ex2.cpp index 637dba9..53c46c7 100644 --- a/ex2.cpp +++ b/ex2.cpp @@ -15,43 +15,42 @@ #include "light/pointlight.h" -int main() -{ - // Let's create a simple cornell box scene... - SimpleScene scene; - scene.setEnvironmentMap(std::make_shared("data/lion_env.png")); +int main() { + // Let's create a simple cornell box scene... + SimpleScene scene; + scene.setEnvironmentMap(std::make_shared("data/lion_env.png")); - auto mirror = std::make_shared(); - auto glass = std::make_shared(1.31f, 1.0f); + auto mirror = std::make_shared(); + auto glass = std::make_shared(1.31f, 1.0f); - // add some lights - scene.add(std::make_shared(Vector3d(0.0f, 10.0f, -10.0f), 250.f, Color(1.0f, 1.0f, 1.0f))); - scene.add(std::make_shared(Vector3d(0.0f, 10.0f, 10.0f), 250.f, Color(1.0f, 1.0f, 1.0f))); + // add some lights + scene.add(std::make_shared(Vector3d(0.0f, 10.0f, -10.0f), 250.f, Color(1.0f, 1.0f, 1.0f))); + scene.add(std::make_shared(Vector3d(0.0f, 10.0f, 10.0f), 250.f, Color(1.0f, 1.0f, 1.0f))); - // Add shaders for the objects - auto orange = std::make_shared(Color(1.0f, 0.5f, 0.0f)); - auto red = std::make_shared(Color(1.0f, 0.3f, 0.2f)); + // Add shaders for the objects + auto orange = std::make_shared(Color(1.0f, 0.5f, 0.0f)); + auto red = std::make_shared(Color(1.0f, 0.3f, 0.2f)); - // Add objects - scene.add(std::make_shared(Vector3d(-3.0f, 0.0f, 0.0f), 1.5f, glass)); - scene.add(std::make_shared(Vector3d(3.5f, -1.0f, 0.0f), Vector3d(3.0f, 3.0f, 3.0f), mirror)); - scene.add(std::make_shared(Vector3d(5.0f, -5.0f, 5.0f), Vector3d(-10.0f, -5.0f, 10.0f), - Vector3d(-2.0f, -5.0f, -2.0f), orange)); - scene.add(std::make_shared(Vector3d(-2.0f, -5.0f, -2.0f), Vector3d(10.0f, -5.0f, -10.0f), - Vector3d(5.0f, -5.0f, 5.0f), orange)); - scene.add(std::make_shared(Vector3d(0.0f, -2.0f, 0.0f), Vector3d(2.0f, -2.0f, 0.0f), - Vector3d(0.0f, 0.0f, 0.0f), red)); + // Add objects + scene.add(std::make_shared(Vector3d(-3.0f, 0.0f, 0.0f), 1.5f, glass)); + scene.add(std::make_shared(Vector3d(3.5f, -1.0f, 0.0f), Vector3d(3.0f, 3.0f, 3.0f), mirror)); + scene.add(std::make_shared(Vector3d(5.0f, -5.0f, 5.0f), Vector3d(-10.0f, -5.0f, 10.0f), + Vector3d(-2.0f, -5.0f, -2.0f), orange)); + scene.add(std::make_shared(Vector3d(-2.0f, -5.0f, -2.0f), Vector3d(10.0f, -5.0f, -10.0f), + Vector3d(5.0f, -5.0f, 5.0f), orange)); + scene.add(std::make_shared(Vector3d(0.0f, -2.0f, 0.0f), Vector3d(2.0f, -2.0f, 0.0f), + Vector3d(0.0f, 0.0f, 0.0f), red)); - // Set up the camera - PerspectiveCamera camera; - camera.setFovAngle(70.0f); - camera.setPosition(Vector3d(-2.5f, 2.5f, -10.0f)); - camera.setForwardDirection(Vector3d(0.4f, -0.33f, 1.0f)); - camera.setUpDirection(Vector3d(0.0f, 1.0f, 0.0f)); + // Set up the camera + PerspectiveCamera camera; + camera.setFovAngle(70.0f); + camera.setPosition(Vector3d(-2.5f, 2.5f, -10.0f)); + camera.setForwardDirection(Vector3d(0.4f, -0.33f, 1.0f)); + camera.setUpDirection(Vector3d(0.0f, 1.0f, 0.0f)); - // Render the scene - SimpleRenderer renderer; - renderer.renderImage(scene, camera, 1024, 768).save("result.png"); + // Render the scene + SimpleRenderer renderer; + renderer.renderImage(scene, camera, 1024, 768).save("result.png"); - return 0; + return 0; } diff --git a/light/pointlight.cpp b/light/pointlight.cpp index 936ea7a..b443f85 100644 --- a/light/pointlight.cpp +++ b/light/pointlight.cpp @@ -3,22 +3,21 @@ PointLight::PointLight(Vector3d const &position, float intensity, Color const &color) : Light(intensity, color), position(position) {} -Light::Illumination PointLight::illuminate(Scene const &scene, Ray const &ray) const -{ - // IMPLEMENT ME - // Get the point on the surface +Light::Illumination PointLight::illuminate(Scene const &scene, Ray const &ray) const { + // IMPLEMENT ME + // Get the point on the surface - // Create an instance of the Illumination object, fill in the direction (from - // surface point to light source) - Light::Illumination illum; + // Create an instance of the Illumination object, fill in the direction (from + // surface point to light source) + Light::Illumination illum; - // Define a secondary ray from the surface point to the light source. + // Define a secondary ray from the surface point to the light source. - // If the target is not in shadow... (use scene.findOcclusion()) + // If the target is not in shadow... (use scene.findOcclusion()) - // Compute the brightness-color of this light using inverse squared distance - // to light source (i.e. 1/(d^2)), the color of this light source and the - // intensity + // Compute the brightness-color of this light using inverse squared distance + // to light source (i.e. 1/(d^2)), the color of this light source and the + // intensity - return illum; + return illum; } diff --git a/light/pointlight.h b/light/pointlight.h index e50d88e..04c8fad 100644 --- a/light/pointlight.h +++ b/light/pointlight.h @@ -3,20 +3,19 @@ #include "light/light.h" -class PointLight : public Light -{ +class PointLight : public Light { public: - PointLight(Vector3d const &position, float intensity, Color const &color = Color(1, 1, 1)); + PointLight(Vector3d const &position, float intensity, Color const &color = Color(1, 1, 1)); - // Set - void setPosition(Vector3d const &position) { this->position = position; } + // Set + void setPosition(Vector3d const &position) { this->position = position; } - // Light functions - Illumination illuminate(Scene const &scene, Ray const &ray) const override; + // Light functions + Illumination illuminate(Scene const &scene, Ray const &ray) const override; protected: - Vector3d position; + Vector3d position; }; #endif diff --git a/primitive/box.cpp b/primitive/box.cpp index 9780b85..83a2c75 100644 --- a/primitive/box.cpp +++ b/primitive/box.cpp @@ -10,84 +10,22 @@ Box::Box(std::shared_ptr const &shader) : Primitive(shader), size(Vector Box::Box(Vector3d const ¢er, Vector3d const &size, std::shared_ptr const &shader) : Primitive(shader), center(center), size(size) {} -// Helper functions ///////////////////////////////////////////////////////// - -float intersectionParameterDimension(Vector3d bounds, Ray &ray, int dimension) -{ - return (bounds[dimension] - ray.origin[dimension]) / ray.direction[dimension]; -} - -Vector3d intersectionParameter(Vector3d bounds, Ray &ray) -{ - return Vector3d(intersectionParameterDimension(bounds, ray, 0), - intersectionParameterDimension(bounds, ray, 1), - intersectionParameterDimension(bounds, ray, 2)); -} - // Primitive functions ///////////////////////////////////////////////////////// -bool Box::intersect(Ray &ray) const -{ - // IMPLEMENT ME! +bool Box::intersect(Ray &ray) const { + // IMPLEMENT ME! - // Determine whether the ray intersects the box + // Determine whether the ray intersects the box - Vector3d minBounds(this->minimumBounds(0), this->minimumBounds(1), this->minimumBounds(2)); - Vector3d maxBounds(this->maximumBounds(0), this->maximumBounds(1), this->maximumBounds(2)); + // Test whether this is the foremost primitive in front of the camera - Vector3d tMin = intersectionParameter(minBounds, ray); - Vector3d tMax = intersectionParameter(maxBounds, ray); + // (Optional for now) Calculate the normal - Vector3d tInAll = Vector3d(std::min(tMin[0], tMax[0]), std::min(tMin[1], tMax[1]), std::min(tMin[2], tMax[2])); - Vector3d tOutAll = Vector3d(std::max(tMin[0], tMax[0]), std::max(tMin[1], tMax[1]), std::max(tMin[2], tMax[2])); + // (Optional for now) Calculate the surface position - float tIn = std::max(std::max(tInAll[0], tInAll[1]), tInAll[2]); - float tOut = std::min(std::min(tOutAll[0], tOutAll[1]), tOutAll[2]); + // Set the new length and the current primitive - if (tIn > tOut || tOut < 0) - { - return false; - } - - float t = tIn; - - // Test whether this is the foremost primitive in front of the camera - if (t >= ray.length) - { - return false; - } - - // (Optional for now) Calculate the normal - // On what side of the box did the ray hit? - Vector3d normal; - if (tInAll[0] == tIn) - { - normal = Vector3d(1, 0, 0); - } - else if (tInAll[1] == tIn) - { - normal = Vector3d(0, 1, 0); - } - else // tInAll[2] == tIn - { - normal = Vector3d(0, 0, 1); - } - - // Make sure sign is correct - if (dotProduct(ray.direction, normal) > 0) - { - normal = -normal; - } - - ray.normal = normalized(normal); - - // (Optional for now) Calculate the surface position - - // Set the new length and the current primitive - ray.length = t; - ray.primitive = this; - - return false; + return false; } // Bounding box //////////////////////////////////////////////////////////////// diff --git a/primitive/box.h b/primitive/box.h index 6d171e0..f1987b1 100644 --- a/primitive/box.h +++ b/primitive/box.h @@ -3,28 +3,27 @@ #include "primitive/primitive.h" -class Box : public Primitive -{ +class Box : public Primitive { public: - // Constructor - Box(std::shared_ptr const &shader); - Box(Vector3d const ¢er, Vector3d const &size, std::shared_ptr const &shader); + // Constructor + Box(std::shared_ptr const &shader); + Box(Vector3d const ¢er, Vector3d const &size, std::shared_ptr const &shader); - // Set - void setCenter(Vector3d const ¢er) { this->center = center; } - void setSize(Vector3d const &size) { this->size = size; } + // Set + void setCenter(Vector3d const ¢er) { this->center = center; } + void setSize(Vector3d const &size) { this->size = size; } - // Primitive functions - bool intersect(Ray &ray) const override; + // Primitive functions + bool intersect(Ray &ray) const override; - // Bounding box - float minimumBounds(int dimension) const override; - float maximumBounds(int dimension) const override; + // Bounding box + float minimumBounds(int dimension) const override; + float maximumBounds(int dimension) const override; protected: - Vector3d center; - Vector3d size; + Vector3d center; + Vector3d size; }; #endif diff --git a/primitive/infiniteplane.cpp b/primitive/infiniteplane.cpp index d48bc75..cc02f31 100644 --- a/primitive/infiniteplane.cpp +++ b/primitive/infiniteplane.cpp @@ -3,72 +3,52 @@ // Constructor ///////////////////////////////////////////////////////////////// -InfinitePlane::InfinitePlane(std::shared_ptr const &shader) : Primitive(shader), normal(0, 1, 0) -{} +InfinitePlane::InfinitePlane(std::shared_ptr const &shader) : Primitive(shader), normal(0, 1, 0) {} InfinitePlane::InfinitePlane(Vector3d const &origin, Vector3d const &normal, std::shared_ptr const &shader) - : Primitive(shader), origin(origin), normal(normal) -{} + : Primitive(shader), origin(origin), normal(normal) {} // Primitive functions ///////////////////////////////////////////////////////// -bool InfinitePlane::intersect(Ray &ray) const -{ - float directionDotNormal = dotProduct(ray.direction, this->normal); +bool InfinitePlane::intersect(Ray &ray) const { + float const cosine = dotProduct(ray.direction, this->normal); - // Make sure the ray is not coming from the other side (backface culling). - // Note: We only use backface culling for InfinitePlanes, because we have - // some special features planned that rely on backfaces for other primitives. + // Make sure the ray is not coming from the other side (backface culling). + // Note: We only use backface culling for InfinitePlanes, because we have + // some special features planned that rely on backfaces for other primitives. + if (cosine > 0) + return false; - /** - * If the dot product is 0, the ray is orthogonal to the normal => parallel to the plane => no intersection. - * If the dot product is negative, the ray is coming from the wrong side. - */ - if (directionDotNormal <= 0) - { - return false; - } + // Determine the distance at which the ray intersects the plane + float const t = dotProduct(this->origin - ray.origin, this->normal) / cosine; - // Basic formular to calculate intersection between ray and plane - float t = (length(this->origin) - dotProduct(ray.origin,this->normal)) / directionDotNormal; + // Test whether this is the foremost primitive in front of the camera + if (t < EPSILON || ray.length < t) + return false; - // If t negative, collision happens behind the camera - if (t < 0) - { - return false; - } + // Set the normal + // IMPLEMENT ME - // Test whether this is the foremost primitive in front of the camera - if (t >= ray.length) - { - // Is bigger, so further away - return false; - } + // Set the new length and the current primitive + ray.length = t; + ray.primitive = this; - // (Optional for now) Set the normal - ray.normal = this->normal; - - // Set the new length and the current primitive - ray.primitive = this; - ray.length = t; - - return true; + // True, because the primitive was hit + return true; } // Bounding box //////////////////////////////////////////////////////////////// -float InfinitePlane::minimumBounds(int dimension) const -{ - if (this->normal[dimension] == 1.0f) // plane is orthogonal to the axis - return this->origin[dimension] - EPSILON; - else - return -INFINITY; +float InfinitePlane::minimumBounds(int dimension) const { + if (this->normal[dimension] == 1.0f) // plane is orthogonal to the axis + return this->origin[dimension] - EPSILON; + else + return -INFINITY; } -float InfinitePlane::maximumBounds(int dimension) const -{ - if (this->normal[dimension] == 1.0f) // plane is orthogonal to the axis - return this->origin[dimension] + EPSILON; - else - return +INFINITY; +float InfinitePlane::maximumBounds(int dimension) const { + if (this->normal[dimension] == 1.0f) // plane is orthogonal to the axis + return this->origin[dimension] + EPSILON; + else + return +INFINITY; } diff --git a/primitive/sphere.cpp b/primitive/sphere.cpp index d4f91fc..fc4e76e 100644 --- a/primitive/sphere.cpp +++ b/primitive/sphere.cpp @@ -1,6 +1,5 @@ #include "common/ray.h" #include "primitive/sphere.h" -#include // Constructor ///////////////////////////////////////////////////////////////// @@ -12,69 +11,45 @@ Sphere::Sphere(Vector3d const ¢er, float radius, std::shared_ptr con // Primitive functions ///////////////////////////////////////////////////////// bool Sphere::intersect(Ray &ray) const { - auto origin = ray.origin - this->center; + // Use the definitions from the lecture + Vector3d const difference = ray.origin - this->center; + float const a = 1.0f; + float const b = 2.0f * dotProduct(ray.direction, difference); + float const c = dotProduct(difference, difference) - this->radius * this->radius; + float const discriminant = b * b - 4 * a * c; - // Determine whether the ray intersects the sphere - float A = pow(ray.direction[Vector3d::Dimension::X], 2) + - pow(ray.direction[Vector3d::Dimension::Y], 2) + - pow(ray.direction[Vector3d::Dimension::Z], 2); - float B = 2 * ( - ray.direction[Vector3d::Dimension::X] * origin[Vector3d::Dimension::X] + - ray.direction[Vector3d::Dimension::Y] * origin[Vector3d::Dimension::Y] + - ray.direction[Vector3d::Dimension::Z] * origin[Vector3d::Dimension::Z] - ); - float C = pow(origin[Vector3d::Dimension::X], 2) + - pow(origin[Vector3d::Dimension::Y], 2) + - pow(origin[Vector3d::Dimension::Z], 2) - - pow(this->radius, 2); + // Test whether the ray could intersect at all + if (discriminant < 0) + return false; + float const root = std::sqrt(discriminant); - float t = INFINITY; + // Stable solution + float const q = -0.5f * (b < 0 ? (b - root) : (b + root)); + float const t0 = q / a; + float const t1 = c / q; + float t = std::min(t0, t1); + if (t < EPSILON) + t = std::max(t0, t1); - float discriminant = B * B - 4 * A * C; - if (discriminant < 0) { - return false; - } else if (discriminant == 0) { - t = -B / (2 * A); - } else { // discriminant > 0 - float q {static_cast([B, discriminant](){ - if (B < 0) { - return -0.5f * (B - sqrt(discriminant)); - } else { - return -0.5f * (B + sqrt(discriminant)); - } - }())}; - float t0 = q / A; - float t1 = C / q; - - if (t0 < 0 && t1 < 0) { - return false; - } - - if (t0 < 0) { - t = t1; - } else if (t1 < 0) { - t = t0; - } else { - t = std::min(t0, t1); - } - } // Test whether this is the foremost primitive in front of the camera + if (t < EPSILON || ray.length < t) + return false; - if (t >= ray.length) { - return false; - } - - // (Optional for now) Calculate the normal - auto intersectPoint = ray.origin + ray.direction * t; - auto normalDirection = intersectPoint - this->center; // Point of intersect - origin of sphere creates a line along the normal, pointing outwards - ray.normal = normalized(normalDirection); - - // (Optional for now) Calculate the surface position + // Calculate the normal + // IMPLEMENT ME + // Calculate the surface position and tangent vector + float const phi = std::acos(ray.normal.y); + float const rho = std::atan2(ray.normal.z, ray.normal.x) + PI; + ray.surface = Vector2d(rho / (2 * PI), phi / PI); + ray.tangent = Vector3d(std::sin(rho), 0, std::cos(rho)); + ray.bitangent = normalized(crossProduct(ray.normal, ray.tangent)); // Set the new length and the current primitive ray.length = t; ray.primitive = this; + + // True, because the primitive was hit return true; } diff --git a/primitive/triangle.cpp b/primitive/triangle.cpp index 169800b..ae98206 100644 --- a/primitive/triangle.cpp +++ b/primitive/triangle.cpp @@ -3,102 +3,118 @@ // Constructor ///////////////////////////////////////////////////////////////// -Triangle::Triangle(std::shared_ptr const &shader) : Primitive(shader) -{} +Triangle::Triangle(std::shared_ptr const &shader) : Primitive(shader) {} -Triangle::Triangle(Vector3d const &a, Vector3d const &b, Vector3d const &c, std::shared_ptr const &shader) - : Primitive(shader), vertex{a, b, c} -{} +Triangle::Triangle(Vector3d const &a, Vector3d const &b, Vector3d const &c, std::shared_ptr const &shader) : Primitive(shader), vertex{a, b, c} {} -Triangle::Triangle(Vector3d const &a, Vector3d const &b, Vector3d const &c, Vector3d const &na, Vector3d const &nb, - Vector3d const &nc, std::shared_ptr const &shader) - : Primitive(shader), vertex{a, b, c}, normal{na, nb, nc} -{} +Triangle::Triangle(Vector3d const &a, Vector3d const &b, Vector3d const &c, Vector3d const &na, Vector3d const &nb, Vector3d const &nc, std::shared_ptr const &shader) : Primitive(shader), vertex{a, b, c}, normal{na, nb, nc} {} -Triangle::Triangle(Vector3d const &a, Vector3d const &b, Vector3d const &c, Vector3d const &na, Vector3d const &nb, - Vector3d const &nc, Vector2d const &ta, Vector2d const &tb, Vector2d const &tc, - std::shared_ptr const &shader) - : Primitive(shader), vertex{a, b, c}, normal{na, nb, nc}, surface{ta, tb, tc} -{} +Triangle::Triangle(Vector3d const &a, Vector3d const &b, Vector3d const &c, Vector3d const &na, Vector3d const &nb, Vector3d const &nc, Vector2d const &ta, Vector2d const &tb, Vector2d const &tc, std::shared_ptr const &shader) + : Primitive(shader), vertex{a, b, c}, normal{na, nb, nc}, surface{ta, tb, tc} {} + +Triangle::Triangle(Vector3d const &a, Vector3d const &b, Vector3d const &c, Vector3d const &na, Vector3d const &nb, Vector3d const &nc, Vector3d const &tana, Vector3d const &tanb, Vector3d const &tanc, Vector3d const &ba, + Vector3d const &bb, Vector3d const &bc, Vector2d const &ta, Vector2d const &tb, Vector2d const &tc, std::shared_ptr const &shader) + : Primitive(shader), vertex{a, b, c}, normal{na, nb, nc}, tangent{tana, tanb, tanc}, bitangent{ba, bb, bc}, surface{ta, tb, tc} {} // Primitive functions ///////////////////////////////////////////////////////// - -bool Triangle::intersect(Ray &ray) const -{ - Vector3d edge1 = this->vertex[0] - this->vertex[2]; - Vector3d edge2 = this->vertex[1] - this->vertex[2]; - Vector3d normalVector = normalized(crossProduct(edge1, edge2)); - float d = dotProduct(this->vertex[0], normalVector) / length(normalVector); - - // catch divided by 0, in case the triangle plane is not hit - float dotDirectionNormalVector = dotProduct(ray.direction, normalVector); - if (dotDirectionNormalVector == 0) - { - return false; +bool Triangle::intersectArea(Ray &ray) const { + // alternative triangle test + // "signed" triangle area with respect to triangle normal + auto triangleArea = [](Vector3d const &v0, Vector3d const &v1, Vector3d const &v2, Vector3d const &normal = Vector3d(0, 0, 0)) { + if (length(normal) < EPSILON) { + return length(crossProduct(v2 - v0, v1 - v0)) / 2.0f; + } else { + Vector3d const cp = crossProduct(v2 - v0, v1 - v0); + return dotProduct(cp, normal) > 0.0f ? length(cp) / 2.0f : -length(cp) / 2.0f; } + }; - float t = (d - dotProduct(ray.origin, normalVector)) / dotDirectionNormalVector; - Vector3d p = ray.origin + t * ray.direction; + // begin ray-plane intersection ---------------------------- + Vector3d normal = normalized(crossProduct(vertex[2] - vertex[0], vertex[1] - vertex[0])); - // Barycentric Coordinates a,b to determine if intersect with Triangle - float triangleArea = length(crossProduct(this->vertex[2] - this->vertex[0], this->vertex[1] - this->vertex[0])) / 2; + float const cosine = dotProduct(ray.direction, normal); - Vector3d rightSide = crossProduct(p - this->vertex[1], this->vertex[2] - this->vertex[1]); - Vector3d leftSide = crossProduct(p - this->vertex[2], this->vertex[0] - this->vertex[2]); + if (abs(cosine) < EPSILON) + return false; - float triangleAreaRightSide = length(rightSide) / 2; - float triangleAreaLeftSide = length(leftSide) / 2; + float const t = dotProduct(vertex[0] - ray.origin, normal) / cosine; - float a = triangleAreaRightSide / triangleArea; + if (t < EPSILON || ray.length < t) + return false; - float b = triangleAreaLeftSide / triangleArea; + Vector3d const p = ray.origin + t * ray.direction; + // end ray-plane intersection ---------------------------- - // Determine whether the ray intersects the triangle + float const fullArea = triangleArea(vertex[0], vertex[1], vertex[2]); + float const a = triangleArea(p, vertex[0], vertex[1], normal) / fullArea; + float const b = triangleArea(p, vertex[2], vertex[0], normal) / fullArea; + if ((a < 0.0f) || (a > 1.0f) || (b < 0.0f) || (a + b > 1.0f)) + return false; - if (a < 0 || a > 1 || b < 0 || a+b > 1) - { - return false; - } + // Set the surface position (barycentric coordinates) and tangent Vector + ray.surface = a * this->surface[1] + b * this->surface[2] + (1 - a - b) * this->surface[0]; - if (dotProduct(normalVector, leftSide) > 0) - { - return false; - } + // Set the new length and the current primitive + ray.length = t; + ray.primitive = this; - if (dotProduct(normalVector, rightSide) > 0) - { - return false; - } + // True, because the primitive was hit + return true; +} - // Test whether this is the foremost primitive in front of the camera - if (t >= ray.length) - { - //it is bigger so further away - return false; - } +bool Triangle::intersect(Ray &ray) const { + // We use the Möller–Trumbore intersection algorithm - // (Optional for now) Calculate the normal - ray.normal = normalVector; // Should be the correct one, I assume + // Determine two neighboring edge vectors + Vector3d const edge1 = this->vertex[1] - this->vertex[0]; + Vector3d const edge2 = this->vertex[2] - this->vertex[0]; - // (Optional for now) Calculate the surface position + // Begin calculating determinant + Vector3d const pVec = crossProduct(ray.direction, edge2); - // Set the new length and the current primitive - ray.length = t; - ray.primitive = this; + // Make sure the ray is not parallel to the triangle + float const det = dotProduct(edge1, pVec); + if (fabs(det) < EPSILON) + return false; + float const inv_det = 1.0f / det; - return true; + // Calculate u and test bound + Vector3d const tVec = ray.origin - this->vertex[0]; + float const u = dotProduct(tVec, pVec) * inv_det; + // Test whether the intersection lies outside the triangle + if (0.0f > u || u > 1.0f) + return false; + + // Calculate v and test bound + Vector3d const qVec = crossProduct(tVec, edge1); + float const v = dotProduct(ray.direction, qVec) * inv_det; + // Test whether the intersection lies outside the triangle + if (0.0f > v || u + v > 1.0f) + return false; + + // Test whether this is the foremost primitive in front of the camera + float const t = dotProduct(edge2, qVec) * inv_det; + if (t < EPSILON || ray.length < t) + return false; + + // Calculate the normal + // IMPLEMENT ME + + // Calculate the surface position + ray.surface = u * this->surface[1] + v * this->surface[2] + (1 - u - v) * this->surface[0]; + + // Set the new length and the current primitive + ray.length = t; + ray.primitive = this; + + // True, because the primitive was hit + return true; } // Bounding box //////////////////////////////////////////////////////////////// -float Triangle::minimumBounds(int dimension) const -{ - return std::min(this->vertex[0][dimension], std::min(this->vertex[1][dimension], this->vertex[2][dimension])); -} +float Triangle::minimumBounds(int dimension) const { return std::min(this->vertex[0][dimension], std::min(this->vertex[1][dimension], this->vertex[2][dimension])); } -float Triangle::maximumBounds(int dimension) const -{ - return std::max(this->vertex[0][dimension], std::max(this->vertex[1][dimension], this->vertex[2][dimension])); -} +float Triangle::maximumBounds(int dimension) const { return std::max(this->vertex[0][dimension], std::max(this->vertex[1][dimension], this->vertex[2][dimension])); } diff --git a/primitive/triangle.h b/primitive/triangle.h index 93bfebb..68591e2 100644 --- a/primitive/triangle.h +++ b/primitive/triangle.h @@ -9,22 +9,28 @@ public: // Constructor Triangle(std::shared_ptr const &shader); Triangle(Vector3d const &a, Vector3d const &b, Vector3d const &c, std::shared_ptr const &shader); - Triangle(Vector3d const &a, Vector3d const &b, Vector3d const &c, Vector3d const &na, Vector3d const &nb, - Vector3d const &nc, std::shared_ptr const &shader); - Triangle(Vector3d const &a, Vector3d const &b, Vector3d const &c, Vector3d const &na, Vector3d const &nb, - Vector3d const &nc, Vector2d const &ta, Vector2d const &tb, Vector2d const &tc, - std::shared_ptr const &shader); + Triangle(Vector3d const &a, Vector3d const &b, Vector3d const &c, Vector3d const &na, Vector3d const &nb, Vector3d const &nc, std::shared_ptr const &shader); + Triangle(Vector3d const &a, Vector3d const &b, Vector3d const &c, Vector3d const &na, Vector3d const &nb, Vector3d const &nc, Vector2d const &ta, Vector2d const &tb, Vector2d const &tc, std::shared_ptr const &shader); + Triangle(Vector3d const &a, Vector3d const &b, Vector3d const &c, Vector3d const &na, Vector3d const &nb, Vector3d const &nc, Vector3d const &tana, Vector3d const &tanb, Vector3d const &tanc, Vector3d const &ba, Vector3d const &bb, + Vector3d const &bc, Vector2d const &ta, Vector2d const &tb, Vector2d const &tc, std::shared_ptr const &shader); // Set void setVertex(int index, Vector3d const &vertex) { this->vertex[index] = vertex; } void setNormal(int index, Vector3d const &normal) { this->normal[index] = normalized(normal); } - Vector3d getNormal(int index){return this->normal[index];} void setTangent(int index, Vector3d const &tangent) { this->tangent[index] = normalized(tangent); } void setBitangent(int index, Vector3d const &bitangent) { this->bitangent[index] = normalized(bitangent); } void setSurface(int index, Vector2d const &surface) { this->surface[index] = surface; } + // Get + Vector3d getPosition(size_t index) { return this->vertex[index]; } + Vector3d getNormal(size_t index) { return this->normal[index]; } + Vector3d getTangent(size_t index) { return this->tangent[index]; } + Vector3d getBitangent(size_t index) { return this->bitangent[index]; } + Vector2d getTexCoord(size_t index) { return this->surface[index]; } + // Primitive functions bool intersect(Ray &ray) const override; + bool intersectArea(Ray &ray) const; // Bounding box float minimumBounds(int dimension) const override; diff --git a/renderer/simplerenderer.cpp b/renderer/simplerenderer.cpp index c1258ba..d455107 100644 --- a/renderer/simplerenderer.cpp +++ b/renderer/simplerenderer.cpp @@ -8,18 +8,54 @@ Texture SimpleRenderer::renderImage(Scene const &scene, Camera const &camera, int width, int height) { Texture image(width, height); - // Calculate the aspect ratio - float max_x = std::min(1.0f, static_cast(width) / height); - float max_y = std::min(1.0f, static_cast(height) / width); + // Setup timer + std::chrono::steady_clock::time_point start, stop; - // Create the image by casting one ray into the scene for each pixel - float pixel_step_x = 2 * max_x / width; - float pixel_step_y = 2 * max_y / height; - for (int x = 0; x < width; x++) { - for (int y = 0; y < height; y++) { - Ray ray = camera.createRay((x - width/2) * pixel_step_x, (y - height/2) * pixel_step_y); - image.setPixelAt(x, height - 1 - y, scene.traceRay(ray)); + // Reset Ray counting + Ray::resetRayCount(); + + // Super-hacky progress bar! + std::cout << "(SimpleRenderer): Begin rendering..." << std::endl; + std::cout << "| 0%"; + int const barSize = 50; + int const stepSize = (width * height) / barSize; + for (int i = 0; i < barSize - 3 - 5; ++i) + std::cout << " "; + std::cout << "100% |" << std::endl << "|"; + int k = 0; + + // Start timer + start = std::chrono::steady_clock::now(); + + float const aspectRatio = static_cast(height) / width; + for (int x = 0; x < image.width(); ++x) { + for (int y = 0; y < image.height(); ++y) { + Ray ray = camera.createRay((static_cast(x) / width * 2 - 1), -(static_cast(y) / height * 2 - 1) * aspectRatio); + image.setPixelAt(x, y, clamped(scene.traceRay(ray))); + + // Super hacky progress bar! + if (++k % stepSize == 0) { + std::cout << "=" << std::flush; } + } } + + // Stop timer + stop = std::chrono::steady_clock::now(); + + std::cout << "| Done!" << std::endl; + + // Calculate the Time taken in seconds + double seconds = std::chrono::duration_cast>(stop - start).count(); + + std::cout << "Time: " << seconds << "s" << std::endl; + + // Get the number of seconds per ray + int rays = Ray::getRayCount(); + + std::cout << "Paths: " << rays << std::endl; + std::cout << "Paths per second: " << std::fixed << std::setprecision(0) << rays / seconds << std::endl; + + return image; } diff --git a/scene/scene.cpp b/scene/scene.cpp index dbe96cf..d9e183b 100644 --- a/scene/scene.cpp +++ b/scene/scene.cpp @@ -9,6 +9,19 @@ #include #include +const std::string WHITESPACE = " \n\r\t\f\v"; +std::string ltrim(const std::string &s) { + size_t start = s.find_first_not_of(WHITESPACE); + return (start == std::string::npos) ? "" : s.substr(start); +} + +std::string rtrim(const std::string &s) { + size_t end = s.find_last_not_of(WHITESPACE); + return (end == std::string::npos) ? "" : s.substr(0, end + 1); +} + +std::string trim(const std::string &s) { return rtrim(ltrim(s)); } + void Scene::add(const std::shared_ptr &light) { this->lights_.push_back(light); } void Scene::add(const std::shared_ptr &primitive) { diff --git a/scene/scene.h b/scene/scene.h index 5b5ccc4..2851914 100644 --- a/scene/scene.h +++ b/scene/scene.h @@ -11,7 +11,6 @@ // Forward declarations class Light; -class Primitive; class Shader; class Scene { diff --git a/shader/mirrorshader.cpp b/shader/mirrorshader.cpp index 8c035a7..201a532 100644 --- a/shader/mirrorshader.cpp +++ b/shader/mirrorshader.cpp @@ -3,11 +3,10 @@ MirrorShader::MirrorShader() {} -Color MirrorShader::shade(Scene const &scene, Ray const &ray) const -{ - // IMPLEMENT ME - // Calculate the reflection vector - // Create a new reflection ray - // Send the new ray out into the scene and return the result - return Color(0, 0, 1); +Color MirrorShader::shade(Scene const &scene, Ray const &ray) const { + // IMPLEMENT ME + // Calculate the reflection vector + // Create a new reflection ray + // Send the new ray out into the scene and return the result + return Color(0, 0, 1); } diff --git a/shader/mirrorshader.h b/shader/mirrorshader.h index 1424043..962b110 100644 --- a/shader/mirrorshader.h +++ b/shader/mirrorshader.h @@ -3,15 +3,14 @@ #include "shader/shader.h" -class MirrorShader : public Shader -{ +class MirrorShader : public Shader { public: - // Constructor - MirrorShader(); + // Constructor + MirrorShader(); - // Shader functions - Color shade(Scene const &scene, Ray const &ray) const override; + // Shader functions + Color shade(Scene const &scene, Ray const &ray) const override; }; #endif diff --git a/shader/refractionshader.cpp b/shader/refractionshader.cpp index 86917e6..1dacc1b 100644 --- a/shader/refractionshader.cpp +++ b/shader/refractionshader.cpp @@ -3,14 +3,13 @@ RefractionShader::RefractionShader(float indexInside, float indexOutside) : indexInside(indexInside), indexOutside(indexOutside) {} -Color RefractionShader::shade(Scene const &scene, Ray const &ray) const -{ - // IMPLEMENT ME - // Calculate the refracted ray using the surface normal vector and - // indexInside, indexOutside - // Also check for total internal reflection - // Send out a new refracted ray into the scene; recursively call traceRay() - return Color(1, 0, 0); +Color RefractionShader::shade(Scene const &scene, Ray const &ray) const { + // IMPLEMENT ME + // Calculate the refracted ray using the surface normal vector and + // indexInside, indexOutside + // Also check for total internal reflection + // Send out a new refracted ray into the scene; recursively call traceRay() + return Color(1, 0, 0); } bool RefractionShader::isTransparent() const { return true; } diff --git a/shader/refractionshader.h b/shader/refractionshader.h index 449bd2c..5c1043e 100644 --- a/shader/refractionshader.h +++ b/shader/refractionshader.h @@ -3,20 +3,19 @@ #include "shader/shader.h" -class RefractionShader : public Shader -{ +class RefractionShader : public Shader { public: - // Constructor - RefractionShader(float indexInside, float indexOutside); + // Constructor + RefractionShader(float indexInside, float indexOutside); - // Shader functions - Color shade(Scene const &scene, Ray const &ray) const override; - bool isTransparent() const override; + // Shader functions + Color shade(Scene const &scene, Ray const &ray) const override; + bool isTransparent() const override; private: - float indexInside; - float indexOutside; + float indexInside; + float indexOutside; }; #endif diff --git a/shader/simpleshadowshader.cpp b/shader/simpleshadowshader.cpp index d725e1b..ee456c5 100644 --- a/shader/simpleshadowshader.cpp +++ b/shader/simpleshadowshader.cpp @@ -4,10 +4,9 @@ SimpleShadowShader::SimpleShadowShader(Color const &objectColor) : objectColor(objectColor) {} -Color SimpleShadowShader::shade(Scene const &scene, Ray const &ray) const -{ - // IMPLEMENT ME - // loop over all light sources to check for visibility and multiply "light - // strength" with this objects albedo (color) - return Color(0, 1, 0); +Color SimpleShadowShader::shade(Scene const &scene, Ray const &ray) const { + // IMPLEMENT ME + // loop over all light sources to check for visibility and multiply "light + // strength" with this objects albedo (color) + return Color(0, 1, 0); } diff --git a/shader/simpleshadowshader.h b/shader/simpleshadowshader.h index de77c12..2922fd9 100644 --- a/shader/simpleshadowshader.h +++ b/shader/simpleshadowshader.h @@ -3,18 +3,17 @@ #include "shader/shader.h" -class SimpleShadowShader : public Shader -{ +class SimpleShadowShader : public Shader { public: - // Constructor - SimpleShadowShader(Color const &objectColor); + // Constructor + SimpleShadowShader(Color const &objectColor); - // Shader functions - Color shade(Scene const &scene, Ray const &ray) const override; + // Shader functions + Color shade(Scene const &scene, Ray const &ray) const override; private: - Color objectColor; + Color objectColor; }; #endif