added ex01 solution
This commit is contained in:
parent
e5891e0c09
commit
69a1566a1a
18 changed files with 331 additions and 94 deletions
11
.gitignore
vendored
11
.gitignore
vendored
|
@ -6,6 +6,10 @@ build/
|
||||||
|
|
||||||
/data/*
|
/data/*
|
||||||
!/data/README.txt
|
!/data/README.txt
|
||||||
|
!/data/fireplace
|
||||||
|
!/data/subdiv
|
||||||
|
!/data/parallax
|
||||||
|
!/data/fractal.obj
|
||||||
/result*
|
/result*
|
||||||
|
|
||||||
# Latex stuff
|
# Latex stuff
|
||||||
|
@ -16,4 +20,9 @@ build/
|
||||||
*.out
|
*.out
|
||||||
*.pdf
|
*.pdf
|
||||||
*.synctex.gz
|
*.synctex.gz
|
||||||
*.json
|
*.json
|
||||||
|
*__latexindent_temp.tex
|
||||||
|
|
||||||
|
# Mac Stuff
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
project(CG1_Tracer LANGUAGES CXX)
|
project(CG1_Tracer LANGUAGES CXX)
|
||||||
set(CMAKE_CXX_STANDARD 14)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
if(NOT WIN32)
|
if(NOT WIN32)
|
||||||
|
@ -37,3 +37,5 @@ target_link_libraries(tracey_ex1 tracey)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
# Build / Setup Prozess
|
||||||
|
Anweisungen ausgelagert in [BUILD_INSTRUCTIONS.md](BUILD_INSTRUCTIONS.md)
|
||||||
|
|
||||||
# Git Grundlagen / Workflow
|
# Git Grundlagen / Workflow
|
||||||
Git Spickzettel: https://files.morr.cc/git-spickzettel.png
|
Git Spickzettel: https://files.morr.cc/git-spickzettel.png
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
#include "camera/perspectivecamera.h"
|
#include "camera/perspectivecamera.h"
|
||||||
|
|
||||||
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 {
|
Ray PerspectiveCamera::createRay(float x, float y) const {
|
||||||
// IMPLEMENT ME!
|
// Create the ray
|
||||||
// Set up a left-handed coordinate system,
|
return Ray(this->position, x * this->rightDirection + y * this->upDirection + focus * this->forwardDirection);
|
||||||
// in which the camera looks along the positive z-Axis
|
|
||||||
return Ray();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,26 @@ public:
|
||||||
|
|
||||||
// Set
|
// Set
|
||||||
void setPosition(Vector3d const &position) { this->position = position; }
|
void setPosition(Vector3d const &position) { this->position = position; }
|
||||||
void setForwardDirection(Vector3d const &forwardDirection) { this->forwardDirection = normalized(forwardDirection); }
|
void setForwardDirection(Vector3d const &forwardDirection) {
|
||||||
void setUpDirection(Vector3d const &upDirection) { this->upDirection = normalized(upDirection); }
|
// IMPLEMENT ME
|
||||||
void setFovAngle(float fovAngle) { this->fovAngle = fovAngle; }
|
// 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
|
// Camera functions
|
||||||
Ray createRay(float x, float y) const override;
|
Ray createRay(float x, float y) const override;
|
||||||
|
@ -23,7 +40,8 @@ protected:
|
||||||
Vector3d position;
|
Vector3d position;
|
||||||
Vector3d forwardDirection;
|
Vector3d forwardDirection;
|
||||||
Vector3d upDirection;
|
Vector3d upDirection;
|
||||||
float fovAngle;
|
Vector3d rightDirection;
|
||||||
|
float focus;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,7 +4,23 @@
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
#ifndef EPSILON
|
#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
|
#endif
|
||||||
|
|
||||||
#ifndef INFINITY
|
#ifndef INFINITY
|
||||||
|
|
3
common/ray.cpp
Normal file
3
common/ray.cpp
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
#include "ray.h"
|
||||||
|
|
||||||
|
int Ray::rayCount = 0;
|
|
@ -23,10 +23,14 @@ struct Ray {
|
||||||
Vector3d bitangent;
|
Vector3d bitangent;
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
Ray(Vector3d const &origin = Vector3d(0, 0, 0), Vector3d const &direction = Vector3d(0, 0, 1))
|
Ray(Vector3d const &origin = Vector3d(0, 0, 0), Vector3d const &direction = Vector3d(0, 0, 1)) : origin(origin), direction(normalized(direction)) {
|
||||||
: 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:
|
private:
|
||||||
#ifndef ICG_RAY_BOUNCES
|
#ifndef ICG_RAY_BOUNCES
|
||||||
|
@ -35,6 +39,7 @@ private:
|
||||||
int remainingBounces = ICG_RAY_BOUNCES;
|
int remainingBounces = ICG_RAY_BOUNCES;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int rayCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "common/vector2d.h"
|
#include "common/vector2d.h"
|
||||||
|
#include "common/common.h"
|
||||||
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
// Access operators ////////////////////////////////////////////////////////////
|
// Access operators ////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -76,18 +77,14 @@ Vector2d &operator/=(Vector2d &left, float right) {
|
||||||
|
|
||||||
// Useful functions ////////////////////////////////////////////////////////////
|
// Useful functions ////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Vector2d componentProduct(const Vector2d &left, const Vector2d &right) {
|
Vector2d componentProduct(const Vector2d &left, const Vector2d &right) { return Vector2d(left.u * right.u, left.v * right.v); }
|
||||||
return Vector2d(left.u * right.u, left.v * right.v);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector2d componentQuotient(const Vector2d &left, const Vector2d &right) {
|
Vector2d componentQuotient(const Vector2d &left, const Vector2d &right) { return Vector2d(left.u / right.u, left.v / right.v); }
|
||||||
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 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)); }
|
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); }
|
void normalize(Vector2d *v) { *v = normalized(*v); }
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "common/vector3d.h"
|
#include "common/vector3d.h"
|
||||||
|
#include "common/common.h"
|
||||||
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
// Access operators ////////////////////////////////////////////////////////////
|
// Access operators ////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -34,35 +35,27 @@ float const &Vector3d::operator[](int const dimension) const {
|
||||||
|
|
||||||
// Comparison operators ////////////////////////////////////////////////////////
|
// Comparison operators ////////////////////////////////////////////////////////
|
||||||
|
|
||||||
bool operator==(Vector3d const &left, Vector3d const &right) {
|
bool operator==(Vector3d const &left, Vector3d const &right) { return (left.x == right.x && left.y == right.y && left.z == right.z); }
|
||||||
return (left.x == right.x && left.y == right.y && left.z == right.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(Vector3d const &left, Vector3d const &right) { return !(left == right); }
|
bool operator!=(Vector3d const &left, Vector3d const &right) { return !(left == right); }
|
||||||
|
|
||||||
// Arithmetic operators ////////////////////////////////////////////////////////
|
// Arithmetic operators ////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Vector3d operator+(Vector3d const &left, Vector3d const &right) {
|
Vector3d operator+(Vector3d const &left, Vector3d const &right) { return Vector3d(left.x + right.x, left.y + right.y, left.z + right.z); }
|
||||||
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 &right) { return Vector3d(-right.x, -right.y, -right.z); }
|
||||||
|
|
||||||
Vector3d operator-(Vector3d const &left, Vector3d const &right) {
|
Vector3d operator-(Vector3d const &left, Vector3d const &right) { return Vector3d(left.x - right.x, left.y - right.y, left.z - right.z); }
|
||||||
return Vector3d(left.x - right.x, left.y - right.y, left.z - right.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector3d operator*(Vector3d const &left, float right) {
|
Vector3d operator*(Vector3d const &left, float right) { return Vector3d(left.x * right, left.y * right, left.z * right); }
|
||||||
return Vector3d(left.x * right, left.y * right, left.z * right);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector3d operator*(float left, Vector3d const &right) {
|
Vector3d operator*(float left, Vector3d const &right) { return Vector3d(left * right.x, left * right.y, left * right.z); }
|
||||||
return Vector3d(left * right.x, left * right.y, left * right.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector3d operator/(Vector3d const &left, float right) {
|
Vector3d operator*(Vector3d const &left, Vector3d const &right) { return Vector3d(left.x * right.x, left.y * right.y, left.z * right.z); }
|
||||||
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/(Vector3d const &left, Vector3d const &right) { return Vector3d(left.x / right.x, left.y / right.y, left.z / right.z); }
|
||||||
|
|
||||||
// Assignment operators ////////////////////////////////////////////////////////
|
// Assignment operators ////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -87,6 +80,13 @@ Vector3d &operator*=(Vector3d &left, float right) {
|
||||||
return left;
|
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) {
|
Vector3d &operator/=(Vector3d &left, float right) {
|
||||||
left.x /= right;
|
left.x /= right;
|
||||||
left.y /= right;
|
left.y /= right;
|
||||||
|
@ -94,27 +94,34 @@ Vector3d &operator/=(Vector3d &left, float right) {
|
||||||
return left;
|
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 ////////////////////////////////////////////////////////////
|
// Useful functions ////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Vector3d componentProduct(const Vector3d &left, const Vector3d &right) {
|
Vector3d componentProduct(const Vector3d &left, const Vector3d &right) { return Vector3d(left.x * right.x, left.y * right.y, left.z * right.z); }
|
||||||
return Vector3d(left.x * right.x, left.y * right.y, left.z * right.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector3d componentQuotient(const Vector3d &left, const Vector3d &right) {
|
Vector3d componentQuotient(const Vector3d &left, const Vector3d &right) { return Vector3d(left.x / right.x, left.y / right.y, left.z / right.z); }
|
||||||
return Vector3d(left.x / right.x, left.y / right.y, left.z / right.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector3d crossProduct(Vector3d const &left, Vector3d const &right) {
|
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); }
|
||||||
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) {
|
float dotProduct(Vector3d const &left, Vector3d const &right) { return left.x * right.x + left.y * right.y + left.z * right.z; }
|
||||||
return left.x * right.x + left.y * right.y + left.z * right.z;
|
|
||||||
}
|
|
||||||
|
|
||||||
float length(Vector3d const &v) { return std::sqrt(dotProduct(v, v)); }
|
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); }
|
void normalize(Vector3d *v) { *v = normalized(*v); }
|
||||||
|
|
||||||
|
std::tuple<Vector3d, Vector3d, Vector3d> 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);
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef VECTOR3D_H
|
#ifndef VECTOR3D_H
|
||||||
#define VECTOR3D_H
|
#define VECTOR3D_H
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
struct Vector3d {
|
struct Vector3d {
|
||||||
// Components
|
// Components
|
||||||
float x, y, z;
|
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, Vector3d const &right);
|
||||||
Vector3d operator*(Vector3d const &left, float right);
|
Vector3d operator*(Vector3d const &left, float right);
|
||||||
Vector3d operator*(float left, Vector3d const &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, float right);
|
||||||
|
Vector3d operator/(Vector3d const &left, Vector3d const &right);
|
||||||
|
|
||||||
// Assignment operators
|
// Assignment operators
|
||||||
Vector3d &operator+=(Vector3d &left, Vector3d const &right);
|
Vector3d &operator+=(Vector3d &left, Vector3d const &right);
|
||||||
Vector3d &operator-=(Vector3d &left, Vector3d const &right);
|
Vector3d &operator-=(Vector3d &left, Vector3d const &right);
|
||||||
Vector3d &operator*=(Vector3d &left, float right);
|
Vector3d &operator*=(Vector3d &left, float right);
|
||||||
|
Vector3d &operator*=(Vector3d &left, Vector3d const &right);
|
||||||
Vector3d &operator/=(Vector3d &left, float right);
|
Vector3d &operator/=(Vector3d &left, float right);
|
||||||
|
Vector3d &operator/=(Vector3d &left, Vector3d const &right);
|
||||||
|
|
||||||
// Useful functions
|
// Useful functions
|
||||||
Vector3d componentProduct(Vector3d const &left, Vector3d const &right);
|
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);
|
float length(Vector3d const &v);
|
||||||
Vector3d normalized(Vector3d const &v);
|
Vector3d normalized(Vector3d const &v);
|
||||||
void normalize(Vector3d *v);
|
void normalize(Vector3d *v);
|
||||||
|
std::tuple<Vector3d, Vector3d, Vector3d> orthoNormalized(Vector3d const &u, Vector3d const &v, Vector3d const &w);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -11,21 +11,30 @@ InfinitePlane::InfinitePlane(Vector3d const &origin, Vector3d const &normal, std
|
||||||
// Primitive functions /////////////////////////////////////////////////////////
|
// Primitive functions /////////////////////////////////////////////////////////
|
||||||
|
|
||||||
bool InfinitePlane::intersect(Ray &ray) const {
|
bool InfinitePlane::intersect(Ray &ray) const {
|
||||||
// IMPLEMENT ME!
|
float const cosine = dotProduct(ray.direction, this->normal);
|
||||||
|
|
||||||
// Make sure the ray is not coming from the other side (backface culling).
|
// Make sure the ray is not coming from the other side (backface culling).
|
||||||
// Note: We only use backface culling for InfinitePlanes, because we have
|
// Note: We only use backface culling for InfinitePlanes, because we have
|
||||||
// some special features planned that rely on backfaces for other primitives.
|
// some special features planned that rely on backfaces for other primitives.
|
||||||
|
if (cosine > 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
// Determine whether the ray intersects the plane
|
// Determine the distance at which the ray intersects the plane
|
||||||
|
float const t = dotProduct(this->origin - ray.origin, this->normal) / cosine;
|
||||||
|
|
||||||
// Test whether this is the foremost primitive in front of the camera
|
// Test whether this is the foremost primitive in front of the camera
|
||||||
|
if (t < EPSILON || ray.length < t)
|
||||||
|
return false;
|
||||||
|
|
||||||
// (Optional for now) Set the normal
|
// Set the normal
|
||||||
|
// IMPLEMENT ME
|
||||||
|
|
||||||
// Set the new length and the current primitive
|
// Set the new length and the current primitive
|
||||||
|
ray.length = t;
|
||||||
|
ray.primitive = this;
|
||||||
|
|
||||||
return false;
|
// True, because the primitive was hit
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bounding box ////////////////////////////////////////////////////////////////
|
// Bounding box ////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -11,19 +11,46 @@ Sphere::Sphere(Vector3d const ¢er, float radius, std::shared_ptr<Shader> con
|
||||||
// Primitive functions /////////////////////////////////////////////////////////
|
// Primitive functions /////////////////////////////////////////////////////////
|
||||||
|
|
||||||
bool Sphere::intersect(Ray &ray) const {
|
bool Sphere::intersect(Ray &ray) const {
|
||||||
// IMPLEMENT ME!
|
// 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
|
// Test whether the ray could intersect at all
|
||||||
|
if (discriminant < 0)
|
||||||
|
return false;
|
||||||
|
float const root = std::sqrt(discriminant);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
// Test whether this is the foremost primitive in front of the camera
|
// Test whether this is the foremost primitive in front of the camera
|
||||||
|
if (t < EPSILON || ray.length < t)
|
||||||
|
return false;
|
||||||
|
|
||||||
// (Optional for now) Calculate the normal
|
// Calculate the normal
|
||||||
|
// IMPLEMENT ME
|
||||||
|
|
||||||
// (Optional for now) Calculate the surface position
|
// 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
|
// Set the new length and the current primitive
|
||||||
|
ray.length = t;
|
||||||
|
ray.primitive = this;
|
||||||
|
|
||||||
return false;
|
// True, because the primitive was hit
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bounding box ////////////////////////////////////////////////////////////////
|
// Bounding box ////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -5,43 +5,116 @@
|
||||||
|
|
||||||
Triangle::Triangle(std::shared_ptr<Shader> const &shader) : Primitive(shader) {}
|
Triangle::Triangle(std::shared_ptr<Shader> const &shader) : Primitive(shader) {}
|
||||||
|
|
||||||
Triangle::Triangle(Vector3d const &a, Vector3d const &b, Vector3d const &c, std::shared_ptr<Shader> const &shader)
|
Triangle::Triangle(Vector3d const &a, Vector3d const &b, Vector3d const &c, std::shared_ptr<Shader> const &shader) : Primitive(shader), vertex{a, b, c} {}
|
||||||
: Primitive(shader), vertex{a, b, c} {}
|
|
||||||
|
|
||||||
Triangle::Triangle(Vector3d const &a, Vector3d const &b, Vector3d const &c, Vector3d const &na, Vector3d const &nb,
|
Triangle::Triangle(Vector3d const &a, Vector3d const &b, Vector3d const &c, Vector3d const &na, Vector3d const &nb, Vector3d const &nc, std::shared_ptr<Shader> const &shader) : Primitive(shader), vertex{a, b, c}, normal{na, nb, nc} {}
|
||||||
Vector3d const &nc, std::shared_ptr<Shader> 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,
|
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<Shader> const &shader)
|
||||||
Vector3d const &nc, Vector2d const &ta, Vector2d const &tb, Vector2d const &tc,
|
|
||||||
std::shared_ptr<Shader> const &shader)
|
|
||||||
: Primitive(shader), vertex{a, b, c}, normal{na, nb, nc}, surface{ta, tb, tc} {}
|
: 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<Shader> 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 /////////////////////////////////////////////////////////
|
// Primitive functions /////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
bool Triangle::intersect(Ray &ray) const {
|
// begin ray-plane intersection ----------------------------
|
||||||
// IMPLEMENT ME!
|
Vector3d normal = normalized(crossProduct(vertex[2] - vertex[0], vertex[1] - vertex[0]));
|
||||||
|
|
||||||
// Determine whether the ray intersects the triangle
|
float const cosine = dotProduct(ray.direction, normal);
|
||||||
|
|
||||||
// Test whether this is the foremost primitive in front of the camera
|
if (abs(cosine) < EPSILON)
|
||||||
|
return false;
|
||||||
|
|
||||||
// (Optional for now) Calculate the normal
|
float const t = dotProduct(vertex[0] - ray.origin, normal) / cosine;
|
||||||
|
|
||||||
// (Optional for now) Calculate the surface position
|
if (t < EPSILON || ray.length < t)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Vector3d const p = ray.origin + t * ray.direction;
|
||||||
|
// end ray-plane intersection ----------------------------
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// 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];
|
||||||
|
|
||||||
// Set the new length and the current primitive
|
// Set the new length and the current primitive
|
||||||
|
ray.length = t;
|
||||||
|
ray.primitive = this;
|
||||||
|
|
||||||
return false;
|
// True, because the primitive was hit
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Triangle::intersect(Ray &ray) const {
|
||||||
|
// We use the Möller–Trumbore intersection algorithm
|
||||||
|
|
||||||
|
// Determine two neighboring edge vectors
|
||||||
|
Vector3d const edge1 = this->vertex[1] - this->vertex[0];
|
||||||
|
Vector3d const edge2 = this->vertex[2] - this->vertex[0];
|
||||||
|
|
||||||
|
// Begin calculating determinant
|
||||||
|
Vector3d const pVec = crossProduct(ray.direction, edge2);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// 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 ////////////////////////////////////////////////////////////////
|
// Bounding box ////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
float Triangle::minimumBounds(int dimension) const {
|
float Triangle::minimumBounds(int dimension) const { return std::min(this->vertex[0][dimension], std::min(this->vertex[1][dimension], this->vertex[2][dimension])); }
|
||||||
return std::min(this->vertex[0][dimension], std::min(this->vertex[1][dimension], this->vertex[2][dimension]));
|
|
||||||
}
|
|
||||||
|
|
||||||
float Triangle::maximumBounds(int dimension) const {
|
float Triangle::maximumBounds(int dimension) const { return std::max(this->vertex[0][dimension], std::max(this->vertex[1][dimension], this->vertex[2][dimension])); }
|
||||||
return std::max(this->vertex[0][dimension], std::max(this->vertex[1][dimension], this->vertex[2][dimension]));
|
|
||||||
}
|
|
||||||
|
|
|
@ -9,22 +9,28 @@ public:
|
||||||
// Constructor
|
// Constructor
|
||||||
Triangle(std::shared_ptr<Shader> const &shader);
|
Triangle(std::shared_ptr<Shader> const &shader);
|
||||||
Triangle(Vector3d const &a, Vector3d const &b, Vector3d const &c, std::shared_ptr<Shader> const &shader);
|
Triangle(Vector3d const &a, Vector3d const &b, Vector3d const &c, std::shared_ptr<Shader> const &shader);
|
||||||
Triangle(Vector3d const &a, Vector3d const &b, Vector3d const &c, Vector3d const &na, Vector3d const &nb,
|
Triangle(Vector3d const &a, Vector3d const &b, Vector3d const &c, Vector3d const &na, Vector3d const &nb, Vector3d const &nc, std::shared_ptr<Shader> const &shader);
|
||||||
Vector3d const &nc, std::shared_ptr<Shader> 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<Shader> const &shader);
|
||||||
Triangle(Vector3d const &a, Vector3d const &b, Vector3d const &c, Vector3d const &na, Vector3d const &nb,
|
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 &nc, Vector2d const &ta, Vector2d const &tb, Vector2d const &tc,
|
Vector3d const &bc, Vector2d const &ta, Vector2d const &tb, Vector2d const &tc, std::shared_ptr<Shader> const &shader);
|
||||||
std::shared_ptr<Shader> const &shader);
|
|
||||||
|
|
||||||
// Set
|
// Set
|
||||||
void setVertex(int index, Vector3d const &vertex) { this->vertex[index] = vertex; }
|
void setVertex(int index, Vector3d const &vertex) { this->vertex[index] = vertex; }
|
||||||
void setNormal(int index, Vector3d const &normal) { this->normal[index] = normalized(normal); }
|
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 setTangent(int index, Vector3d const &tangent) { this->tangent[index] = normalized(tangent); }
|
||||||
void setBitangent(int index, Vector3d const &bitangent) { this->bitangent[index] = normalized(bitangent); }
|
void setBitangent(int index, Vector3d const &bitangent) { this->bitangent[index] = normalized(bitangent); }
|
||||||
void setSurface(int index, Vector2d const &surface) { this->surface[index] = surface; }
|
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
|
// Primitive functions
|
||||||
bool intersect(Ray &ray) const override;
|
bool intersect(Ray &ray) const override;
|
||||||
|
bool intersectArea(Ray &ray) const;
|
||||||
|
|
||||||
// Bounding box
|
// Bounding box
|
||||||
float minimumBounds(int dimension) const override;
|
float minimumBounds(int dimension) const override;
|
||||||
|
|
|
@ -8,9 +8,54 @@
|
||||||
Texture SimpleRenderer::renderImage(Scene const &scene, Camera const &camera, int width, int height) {
|
Texture SimpleRenderer::renderImage(Scene const &scene, Camera const &camera, int width, int height) {
|
||||||
Texture image(width, height);
|
Texture image(width, height);
|
||||||
|
|
||||||
// Calculate the aspect ration
|
// Setup timer
|
||||||
|
std::chrono::steady_clock::time_point start, stop;
|
||||||
|
|
||||||
|
// 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<float>(height) / width;
|
||||||
|
for (int x = 0; x < image.width(); ++x) {
|
||||||
|
for (int y = 0; y < image.height(); ++y) {
|
||||||
|
Ray ray = camera.createRay((static_cast<float>(x) / width * 2 - 1), -(static_cast<float>(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<std::chrono::duration<double>>(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;
|
||||||
|
|
||||||
// Create the image by casting one ray into the scene for each pixel
|
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,19 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
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> &light) { this->lights_.push_back(light); }
|
void Scene::add(const std::shared_ptr<Light> &light) { this->lights_.push_back(light); }
|
||||||
|
|
||||||
void Scene::add(const std::shared_ptr<Primitive> &primitive) {
|
void Scene::add(const std::shared_ptr<Primitive> &primitive) {
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
|
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
class Light;
|
class Light;
|
||||||
class Primitive;
|
|
||||||
class Shader;
|
class Shader;
|
||||||
|
|
||||||
class Scene {
|
class Scene {
|
||||||
|
|
Loading…
Reference in a new issue