first commit
This commit is contained in:
commit
bbfdda7796
41 changed files with 80434 additions and 0 deletions
19
.gitignore
vendored
Normal file
19
.gitignore
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# Project ide-Folders
|
||||||
|
.vs
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
build/
|
||||||
|
|
||||||
|
/data/*
|
||||||
|
!/data/README.txt
|
||||||
|
/result*
|
||||||
|
|
||||||
|
# Latex stuff
|
||||||
|
*.aux
|
||||||
|
*.fdb_latexmk
|
||||||
|
*.fls
|
||||||
|
*.log
|
||||||
|
*.out
|
||||||
|
*.pdf
|
||||||
|
*.synctex.gz
|
||||||
|
*.json
|
74
BUILD_INSTRUCTIONS.md
Normal file
74
BUILD_INSTRUCTIONS.md
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
# Build-Anleitung Linux (und hoffentlich auch Mac):
|
||||||
|
|
||||||
|
## Sicherstellen, dass alle Abhängigkeiten installiert sind
|
||||||
|
Das Projekt davon ab, dass folgende Programme vorhanden und auffindbar sind:
|
||||||
|
|
||||||
|
```
|
||||||
|
cmake
|
||||||
|
make (ninja, ...)
|
||||||
|
g++ (clang, ...)
|
||||||
|
ImageMagick
|
||||||
|
```
|
||||||
|
|
||||||
|
## Repository auschecken (ab hier alles im Terminal):
|
||||||
|
`git clone gogs@FORK_OF_THIS_REPO`
|
||||||
|
|
||||||
|
oder
|
||||||
|
|
||||||
|
`git -c http.sslVerify=false https://FORK_OF_THIS_REPO`
|
||||||
|
|
||||||
|
## Build Verzeichnis anlegen
|
||||||
|
`cd FOLDER`
|
||||||
|
|
||||||
|
`mkdir build`
|
||||||
|
|
||||||
|
`cd build`
|
||||||
|
|
||||||
|
## CMake und make ausführen
|
||||||
|
`cmake .. && make`
|
||||||
|
|
||||||
|
für schnelleres Bauen ist `make -j4` zu empfehlen
|
||||||
|
|
||||||
|
## Die gebaute Anwendung ausführen
|
||||||
|
`./tracey_ex1` oder `./tracey_exN`
|
||||||
|
|
||||||
|
# Build-Anleitung Windows
|
||||||
|
|
||||||
|
## Sicherstellen, dass alle Abhängigkeiten installiert sind
|
||||||
|
Das Projekt davon ab, dass folgende Programme vorhanden und auffindbar sind:
|
||||||
|
|
||||||
|
```
|
||||||
|
cmake
|
||||||
|
make (ninja, ...)
|
||||||
|
c++ Kompiler
|
||||||
|
ImageMagick
|
||||||
|
```
|
||||||
|
|
||||||
|
Der wahrscheinlich meistverbreitete C++ Kompiler für Windows ist der MSVC, der mit Visual Studio mitgeliefert wird.
|
||||||
|
Studenten der TU können diesen kostenlos in Enterprise-Variante von https://doku.rz.tu-bs.de/doku.php?id=software:azure_dev_tools beziehen.
|
||||||
|
Eine Community-Version ist auch verfügbar: https://visualstudio.microsoft.com/de/vs/
|
||||||
|
|
||||||
|
## Repository auschecken (im Terminal):
|
||||||
|
`git clone gogs@FORK_OF_THIS_REPO`
|
||||||
|
|
||||||
|
oder
|
||||||
|
|
||||||
|
`git -c http.sslVerify=false https://FORK_OF_THIS_REPO`
|
||||||
|
|
||||||
|
## CMake-GUI ausführen
|
||||||
|
![CMake-Gui](images/cmake-gui.png)
|
||||||
|
|
||||||
|
Auf _Configure_ klicken und sicherstellen, dass die entsprechende Version von Visual Studio verwendet wird:
|
||||||
|
|
||||||
|
![Generator](images/cmake-gui-generator.png)
|
||||||
|
|
||||||
|
Auf _Finish_ und auf _Generate_ (evtl. 2 mal) klicken.
|
||||||
|
|
||||||
|
Mit _Open Project_ sollte die entsprechende Solution in VS geöffnet werden (alternativ kann die _.sln_ aus dem Build-Ordner mit VS geöffnet werden).
|
||||||
|
|
||||||
|
## In Visual Studio bauen
|
||||||
|
Das _Startup Project_ auf die entsprechende Aufgabe setzen:
|
||||||
|
|
||||||
|
![Visual-Studio](images/vs.png)
|
||||||
|
|
||||||
|
Mit _F5_ das Projekt bauen und gleichzeitig mit angehängtem Debugger starten. Nach erfolgreicher Beendigung sollte sich im `build`-Ordner die `result.png` befinden.
|
39
CMakeLists.txt
Normal file
39
CMakeLists.txt
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
project(CG1_Tracer LANGUAGES CXX)
|
||||||
|
set(CMAKE_CXX_STANDARD 14)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
if(NOT WIN32)
|
||||||
|
find_package(Threads REQUIRED)
|
||||||
|
find_package(X11 REQUIRED)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# This directory
|
||||||
|
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
if(APPLE)
|
||||||
|
include_directories(AFTER "/opt/X11/include")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# which source files to use
|
||||||
|
file(GLOB common_src "common/*.cpp")
|
||||||
|
file(GLOB camera_src "camera/*.cpp")
|
||||||
|
file(GLOB light_src "light/*.cpp")
|
||||||
|
file(GLOB primitive_src "primitive/*.cpp")
|
||||||
|
file(GLOB renderer_src "renderer/*.cpp")
|
||||||
|
file(GLOB scene_src "scene/*.cpp")
|
||||||
|
file(GLOB shader_src "shader/*.cpp")
|
||||||
|
|
||||||
|
# The tracey library
|
||||||
|
add_library(tracey STATIC ${common_src} ${camera_src} ${light_src}
|
||||||
|
${primitive_src} ${renderer_src} ${scene_src} ${shader_src})
|
||||||
|
if(NOT WIN32)
|
||||||
|
target_link_libraries(tracey ${CMAKE_THREAD_LIBS_INIT} ${X11_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
|
||||||
|
add_executable(tracey_ex1 ex1.cpp)
|
||||||
|
target_link_libraries(tracey_ex1 tracey)
|
||||||
|
|
||||||
|
|
||||||
|
|
35
README.md
Normal file
35
README.md
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
# Git Grundlagen / Workflow
|
||||||
|
Git Spickzettel: https://files.morr.cc/git-spickzettel.png
|
||||||
|
|
||||||
|
Guter Schnellstart mit Begriffen und Konzepten ist Kapitel 2 des _pro Git_ Buches: https://git-scm.com/book/de/v2/Git-Grundlagen-Ein-Git-Repository-anlegen
|
||||||
|
|
||||||
|
# Musterlösung integrieren (ohne die ganze History wegzuwerfen)
|
||||||
|
Angepasst von https://medium.com/@topspinj/how-to-git-rebase-into-a-forked-repo-c9f05e821c8a
|
||||||
|
|
||||||
|
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`
|
||||||
|
|
||||||
|
Alle Branches von _upstream_ und deren Änderungen herunterladen
|
||||||
|
|
||||||
|
`git fetch upstream`
|
||||||
|
|
||||||
|
Die Änderungen hineinmergen und Konflikte so auflösen, dass die Musterlösung bevorzugt wird
|
||||||
|
|
||||||
|
`git merge -X theirs upstream/master`
|
||||||
|
|
||||||
|
bitte beachten: Dies löst nur _Konflikte_ so auf, dass die Änderungen der Musterlösung bevorzugt werden. Wenn ihr andere Dateien hinzugefügt habt, werden diese immer noch nach dem Merge vorhanden sein.
|
||||||
|
Ebenso verhält es sich, wenn ihr Interfaces von Funktionen geändert oder Änderungen vorgenommen habt, die nicht mit der _upstream_-Version in Konflikt stehen (z.B wenn ihr in Aufgabe 03 etwas an der Schnittpunktberechnung aus Aufgabe 01 ändert, das nicht in Aufgabe 03 angepasst wurde, wird die Änderung nach dem Merge immer noch da sein).
|
||||||
|
Deswegen kann so ein Merge immer noch in nicht-kompilierbaren Code resultieren oder Bugs einführen.
|
||||||
|
|
||||||
|
Daher ist es _immer_ eine gute Idee, sich noch einmal einen Diff zwischen der aktuellen Version und der Musterlösung zu Gemüte zu führen:
|
||||||
|
|
||||||
|
`git diff master upstream/master`
|
||||||
|
|
||||||
|
hier kann man dann noch ggf. selbst Hand anlegen und die Änderungen dann wieder auf das eigene Repository schieben:
|
||||||
|
|
||||||
|
`git commit -am "Merge solution"`
|
||||||
|
|
||||||
|
`git push origin master`
|
||||||
|
|
||||||
|
evtl. muss noch `--force` angegeben werden
|
17
camera/camera.h
Normal file
17
camera/camera.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef CAMERA_H
|
||||||
|
#define CAMERA_H
|
||||||
|
|
||||||
|
#include "common/ray.h"
|
||||||
|
|
||||||
|
class Camera {
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructor / Destructor
|
||||||
|
Camera() = default;
|
||||||
|
virtual ~Camera() = default;
|
||||||
|
|
||||||
|
// Camera functions
|
||||||
|
virtual Ray createRay(float x, float y) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
10
camera/perspectivecamera.cpp
Normal file
10
camera/perspectivecamera.cpp
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#include "camera/perspectivecamera.h"
|
||||||
|
|
||||||
|
PerspectiveCamera::PerspectiveCamera() : forwardDirection(0, 0, 1), upDirection(0, 1, 0), fovAngle(70) {}
|
||||||
|
|
||||||
|
Ray PerspectiveCamera::createRay(float x, float y) const {
|
||||||
|
// IMPLEMENT ME!
|
||||||
|
// Set up a left-handed coordinate system,
|
||||||
|
// in which the camera looks along the positive z-Axis
|
||||||
|
return Ray();
|
||||||
|
}
|
29
camera/perspectivecamera.h
Normal file
29
camera/perspectivecamera.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef PERSPECTIVECAMERA_H
|
||||||
|
#define PERSPECTIVECAMERA_H
|
||||||
|
|
||||||
|
#include "camera/camera.h"
|
||||||
|
|
||||||
|
class PerspectiveCamera : public Camera {
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructor / Destructor
|
||||||
|
PerspectiveCamera();
|
||||||
|
~PerspectiveCamera() override = default;
|
||||||
|
|
||||||
|
// 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; }
|
||||||
|
|
||||||
|
// Camera functions
|
||||||
|
Ray createRay(float x, float y) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Vector3d position;
|
||||||
|
Vector3d forwardDirection;
|
||||||
|
Vector3d upDirection;
|
||||||
|
float fovAngle;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
79034
common/CImg.h
Normal file
79034
common/CImg.h
Normal file
File diff suppressed because it is too large
Load diff
106
common/color.cpp
Normal file
106
common/color.cpp
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
#include "common/color.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
// Access operators ////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
float &Color::operator[](int channel) {
|
||||||
|
assert(0 <= channel && channel < 3);
|
||||||
|
switch (channel) {
|
||||||
|
case Channel::R:
|
||||||
|
return this->r;
|
||||||
|
case Channel::G:
|
||||||
|
return this->g;
|
||||||
|
case Channel::B:
|
||||||
|
return this->b;
|
||||||
|
default: // This must never happen
|
||||||
|
return this->r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float const &Color::operator[](int channel) const {
|
||||||
|
assert(0 <= channel && channel < 3);
|
||||||
|
switch (channel) {
|
||||||
|
case Channel::R:
|
||||||
|
return this->r;
|
||||||
|
case Channel::G:
|
||||||
|
return this->g;
|
||||||
|
case Channel::B:
|
||||||
|
return this->b;
|
||||||
|
default: // This must never happen
|
||||||
|
return this->r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comparison operators ////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool operator==(Color const &left, Color const &right) {
|
||||||
|
return (left.r == right.r && left.g == right.g && left.b == right.b);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(Color const &left, Color const &right) { return !(left == right); }
|
||||||
|
|
||||||
|
// Arithmetic operators ////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Color operator+(Color const &left, Color const &right) {
|
||||||
|
return Color(left.r + right.r, left.g + right.g, left.b + right.b);
|
||||||
|
}
|
||||||
|
|
||||||
|
Color operator-(Color const &right) { return Color(-right.r, -right.g, -right.b); }
|
||||||
|
|
||||||
|
Color operator-(Color const &left, Color const &right) {
|
||||||
|
return Color(left.r - right.r, left.g - right.g, left.b - right.b);
|
||||||
|
}
|
||||||
|
|
||||||
|
Color operator*(Color const &left, float right) { return Color(left.r * right, left.g * right, left.b * right); }
|
||||||
|
|
||||||
|
Color operator*(float left, Color const &right) { return Color(left * right.r, left * right.g, left * right.b); }
|
||||||
|
|
||||||
|
Color operator*(Color const &left, Color const &right) {
|
||||||
|
return Color(left.r * right.r, left.g * right.g, left.b * right.b);
|
||||||
|
}
|
||||||
|
|
||||||
|
Color operator/(Color const &left, float right) { return Color(left.r / right, left.g / right, left.b / right); }
|
||||||
|
|
||||||
|
Color operator/(Color const &left, Color const &right) {
|
||||||
|
return Color(left.r / right.r, left.g / right.g, left.b / right.b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assignment operators ////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Color &operator+=(Color &left, Color const &right) {
|
||||||
|
left.r += right.r;
|
||||||
|
left.g += right.g;
|
||||||
|
left.b += right.b;
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color &operator-=(Color &left, Color const &right) {
|
||||||
|
left.r -= right.r;
|
||||||
|
left.g -= right.g;
|
||||||
|
left.b -= right.b;
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color &operator*=(Color &left, float right) {
|
||||||
|
left.r *= right;
|
||||||
|
left.g *= right;
|
||||||
|
left.b *= right;
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color &operator/=(Color &left, float right) {
|
||||||
|
left.r /= right;
|
||||||
|
left.g /= right;
|
||||||
|
left.b /= right;
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Useful functions ////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Color clamped(Color const &c) {
|
||||||
|
return Color(std::max(0.0f, std::min(c.r, 1.0f)), std::max(0.0f, std::min(c.g, 1.0f)),
|
||||||
|
std::max(0.0f, std::min(c.b, 1.0f)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void clamp(Color *c) { *c = clamped(*c); }
|
45
common/color.h
Normal file
45
common/color.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#ifndef COLOR_H
|
||||||
|
#define COLOR_H
|
||||||
|
|
||||||
|
struct Color {
|
||||||
|
|
||||||
|
// Components
|
||||||
|
float r, g, b;
|
||||||
|
|
||||||
|
// Enum for readability
|
||||||
|
enum Channel { R, G, B };
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
Color() : r(0), g(0), b(0) {}
|
||||||
|
Color(float r, float g, float b) : r(r), g(g), b(b) {}
|
||||||
|
|
||||||
|
// Access operators
|
||||||
|
float &operator[](int channel);
|
||||||
|
float const &operator[](int channel) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Comparison operators
|
||||||
|
bool operator==(Color const &left, Color const &right);
|
||||||
|
bool operator!=(Color const &left, Color const &right);
|
||||||
|
|
||||||
|
// Arithmetic operators
|
||||||
|
Color operator+(Color const &left, Color const &right);
|
||||||
|
Color operator-(Color const &right);
|
||||||
|
Color operator-(Color const &left, Color const &right);
|
||||||
|
Color operator*(Color const &left, float right);
|
||||||
|
Color operator*(float left, Color const &right);
|
||||||
|
Color operator*(Color const &left, Color const &right);
|
||||||
|
Color operator/(Color const &left, float right);
|
||||||
|
Color operator/(Color const &left, Color const &right);
|
||||||
|
|
||||||
|
// Assignment operators
|
||||||
|
Color &operator+=(Color &left, Color const &right);
|
||||||
|
Color &operator-=(Color &left, Color const &right);
|
||||||
|
Color &operator*=(Color &left, float right);
|
||||||
|
Color &operator/=(Color &left, float right);
|
||||||
|
|
||||||
|
// Useful functions
|
||||||
|
Color clamped(Color const &c);
|
||||||
|
void clamp(Color *c);
|
||||||
|
|
||||||
|
#endif
|
18
common/common.h
Normal file
18
common/common.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#ifndef COMMON_H
|
||||||
|
#define COMMON_H
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#ifndef EPSILON
|
||||||
|
#define EPSILON 1E-4f
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef INFINITY
|
||||||
|
#define INFINITY HUGE_VAL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PI
|
||||||
|
#define PI 3.1415926535897932384f
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
40
common/ray.h
Normal file
40
common/ray.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#ifndef RAY_H
|
||||||
|
#define RAY_H
|
||||||
|
|
||||||
|
#include "common/common.h"
|
||||||
|
#include "common/vector2d.h"
|
||||||
|
#include "common/vector3d.h"
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
// Forward declaration
|
||||||
|
class Primitive;
|
||||||
|
|
||||||
|
struct Ray {
|
||||||
|
friend class Scene;
|
||||||
|
|
||||||
|
// Components
|
||||||
|
Vector3d origin; // o
|
||||||
|
Vector3d direction; // d
|
||||||
|
float length = INFINITY; // t
|
||||||
|
Primitive const *primitive = nullptr;
|
||||||
|
Vector3d normal;
|
||||||
|
Vector2d surface;
|
||||||
|
Vector3d tangent;
|
||||||
|
Vector3d bitangent;
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
Ray(Vector3d const &origin = Vector3d(0, 0, 0), Vector3d const &direction = Vector3d(0, 0, 1))
|
||||||
|
: origin(origin), direction(normalized(direction)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
#ifndef ICG_RAY_BOUNCES
|
||||||
|
int remainingBounces = 4;
|
||||||
|
#else
|
||||||
|
int remainingBounces = ICG_RAY_BOUNCES;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
66
common/texture.cpp
Normal file
66
common/texture.cpp
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
#include "common/texture.h"
|
||||||
|
#include <cmath>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
Texture::Texture(int width, int height) { this->resize(width, height); }
|
||||||
|
|
||||||
|
Texture::Texture(char const *fileName) { this->load(fileName); }
|
||||||
|
|
||||||
|
bool Texture::load(char const *fileName) {
|
||||||
|
CImg<unsigned char> img_char(fileName);
|
||||||
|
if (img_char.is_empty()) {
|
||||||
|
std::cerr << "(Image): Could not open file " << fileName << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->image_ = CImg<float>(img_char.width(), img_char.height(), img_char.depth(), 3, 0);
|
||||||
|
for (int c = 0; c < 3; c++)
|
||||||
|
cimg_forXYZ(img_char, x, y, z) {
|
||||||
|
this->image_(x, y, z, c) = img_char(x, y, z, std::min(c, img_char.spectrum() - 1)) / 255.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Texture::save(char const *fileName) const {
|
||||||
|
CImg<unsigned char> img_char;
|
||||||
|
img_char = 255 * this->image_;
|
||||||
|
|
||||||
|
img_char.save(fileName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color Texture::getPixelAt(int x, int y) const {
|
||||||
|
if ((x %= this->width()) < 0)
|
||||||
|
x += this->width();
|
||||||
|
if ((y %= this->height()) < 0)
|
||||||
|
y += this->height();
|
||||||
|
return Color(this->image_.atXY(x, y, 0), this->image_.atXY(x, y, 1), this->image_.atXY(x, y, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Texture::setPixelAt(int x, int y, Color const &color) {
|
||||||
|
if ((x %= this->width()) < 0)
|
||||||
|
x += this->width();
|
||||||
|
if ((y %= this->height()) < 0)
|
||||||
|
y += this->height();
|
||||||
|
this->image_(x, y, 0) = color.r;
|
||||||
|
this->image_(x, y, 1) = color.g;
|
||||||
|
this->image_(x, y, 2) = color.b;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color Texture::color(float u, float v, bool interpolate) const {
|
||||||
|
Color color;
|
||||||
|
if (!interpolate) {
|
||||||
|
color = this->getPixelAt(int(roundf(u * this->width())), int(roundf(v * this->height())));
|
||||||
|
} else {
|
||||||
|
// We will use bilinear filtering in the future, but for now we do a simple color look-up
|
||||||
|
color = this->getPixelAt(int(roundf(u * this->width())), int(roundf(v * this->height())));
|
||||||
|
}
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color Texture::color(Vector2d const &surfacePosition, bool interpolate) const {
|
||||||
|
return color(surfacePosition.u, surfacePosition.v, interpolate);
|
||||||
|
}
|
38
common/texture.h
Normal file
38
common/texture.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#ifndef TEXTURE_H
|
||||||
|
#define TEXTURE_H
|
||||||
|
|
||||||
|
#include "common/CImg.h"
|
||||||
|
#include "common/color.h"
|
||||||
|
#include "common/vector2d.h"
|
||||||
|
|
||||||
|
using namespace cimg_library;
|
||||||
|
|
||||||
|
class Texture {
|
||||||
|
public:
|
||||||
|
// Constructor
|
||||||
|
Texture(int width, int height);
|
||||||
|
Texture(char const *fileName);
|
||||||
|
|
||||||
|
// Image functions
|
||||||
|
inline void resize(int width, int height) { this->image_.resize(width, height, 1, 3); }
|
||||||
|
bool load(char const *fileName);
|
||||||
|
bool save(char const *fileName) const;
|
||||||
|
|
||||||
|
// Get
|
||||||
|
inline bool isNull() const { return this->image_.is_empty(); }
|
||||||
|
inline int width() const { return this->image_.width(); }
|
||||||
|
inline int height() const { return this->image_.height(); }
|
||||||
|
Color getPixelAt(int x, int y) const;
|
||||||
|
|
||||||
|
// Set
|
||||||
|
void setPixelAt(int x, int y, Color const &color);
|
||||||
|
|
||||||
|
// Color functions
|
||||||
|
Color color(float u, float v, bool interpolate = true) const;
|
||||||
|
Color color(Vector2d const &surfacePosition, bool interpolate = true) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
CImg<float> image_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
93
common/vector2d.cpp
Normal file
93
common/vector2d.cpp
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
#include "common/vector2d.h"
|
||||||
|
#include <cassert>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
// Access operators ////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
float &Vector2d::operator[](int dimension) {
|
||||||
|
assert(0 <= dimension && dimension < 2);
|
||||||
|
switch (dimension) {
|
||||||
|
case Dimension::U:
|
||||||
|
return this->u;
|
||||||
|
case Dimension::V:
|
||||||
|
return this->v;
|
||||||
|
default: // This must never happen
|
||||||
|
return this->u;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float const &Vector2d::operator[](int dimension) const {
|
||||||
|
assert(0 <= dimension && dimension < 2);
|
||||||
|
switch (dimension) {
|
||||||
|
case Dimension::U:
|
||||||
|
return this->u;
|
||||||
|
case Dimension::V:
|
||||||
|
return this->v;
|
||||||
|
default: // This must never happen
|
||||||
|
return this->u;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comparison operators ////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool operator==(Vector2d const &left, Vector2d const &right) { return (left.u == right.u && left.v == right.v); }
|
||||||
|
|
||||||
|
bool operator!=(Vector2d const &left, Vector2d const &right) { return !(left == right); }
|
||||||
|
|
||||||
|
// Arithmetic operators ////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Vector2d operator+(Vector2d const &left, Vector2d const &right) { return Vector2d(left.u + right.u, left.v + right.v); }
|
||||||
|
|
||||||
|
Vector2d operator-(Vector2d const &right) { return Vector2d(-right.u, -right.v); }
|
||||||
|
|
||||||
|
Vector2d operator-(Vector2d const &left, Vector2d const &right) { return Vector2d(left.u - right.u, left.v - right.v); }
|
||||||
|
|
||||||
|
Vector2d operator*(Vector2d const &left, float right) { return Vector2d(left.u * right, left.v * right); }
|
||||||
|
|
||||||
|
Vector2d operator*(float left, Vector2d const &right) { return Vector2d(left * right.u, left * right.v); }
|
||||||
|
|
||||||
|
Vector2d operator/(Vector2d const &left, float right) { return Vector2d(left.u / right, left.v / right); }
|
||||||
|
|
||||||
|
// Assignment operators ////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Vector2d &operator+=(Vector2d &left, Vector2d const &right) {
|
||||||
|
left.u += right.u;
|
||||||
|
left.v += right.v;
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2d &operator-=(Vector2d &left, Vector2d const &right) {
|
||||||
|
left.u -= right.u;
|
||||||
|
left.v -= right.v;
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2d &operator*=(Vector2d &left, float right) {
|
||||||
|
left.u *= right;
|
||||||
|
left.v *= right;
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2d &operator/=(Vector2d &left, float right) {
|
||||||
|
left.u /= right;
|
||||||
|
left.v /= right;
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Useful functions ////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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); }
|
||||||
|
|
||||||
|
void normalize(Vector2d *v) { *v = normalized(*v); }
|
46
common/vector2d.h
Normal file
46
common/vector2d.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#ifndef VECTOR2D_H
|
||||||
|
#define VECTOR2D_H
|
||||||
|
|
||||||
|
struct Vector2d {
|
||||||
|
// Components
|
||||||
|
float u, v;
|
||||||
|
|
||||||
|
// Enum for readability
|
||||||
|
enum Dimension { U, V };
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
Vector2d() : u(0), v(0) {}
|
||||||
|
Vector2d(float u, float v) : u(u), v(v) {}
|
||||||
|
|
||||||
|
// Access operators
|
||||||
|
float &operator[](int dimension);
|
||||||
|
float const &operator[](int dimension) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Comparison operators
|
||||||
|
bool operator==(Vector2d const &left, Vector2d const &right);
|
||||||
|
bool operator!=(Vector2d const &left, Vector2d const &right);
|
||||||
|
|
||||||
|
// Arithmetic operators
|
||||||
|
Vector2d operator+(Vector2d const &left, Vector2d const &right);
|
||||||
|
Vector2d operator-(Vector2d const &right);
|
||||||
|
Vector2d operator-(Vector2d const &left, Vector2d const &right);
|
||||||
|
Vector2d operator*(Vector2d const &left, float right);
|
||||||
|
Vector2d operator*(float left, Vector2d const &right);
|
||||||
|
Vector2d operator/(Vector2d const &left, float right);
|
||||||
|
|
||||||
|
// Assignment operators
|
||||||
|
Vector2d &operator+=(Vector2d &left, Vector2d const &right);
|
||||||
|
Vector2d &operator-=(Vector2d &left, Vector2d const &right);
|
||||||
|
Vector2d &operator*=(Vector2d &left, float right);
|
||||||
|
Vector2d &operator/=(Vector2d &left, float right);
|
||||||
|
|
||||||
|
// Useful functions
|
||||||
|
Vector2d componentProduct(Vector2d const &left, Vector2d const &right);
|
||||||
|
Vector2d componentQuotient(Vector2d const &left, Vector2d const &right);
|
||||||
|
float dotProduct(Vector2d const &left, Vector2d const &right);
|
||||||
|
float length(Vector2d const &c);
|
||||||
|
Vector2d normalized(Vector2d const &v);
|
||||||
|
void normalize(Vector2d *v);
|
||||||
|
|
||||||
|
#endif
|
120
common/vector3d.cpp
Normal file
120
common/vector3d.cpp
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
#include "common/vector3d.h"
|
||||||
|
#include <cassert>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
// Access operators ////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
float &Vector3d::operator[](int const dimension) {
|
||||||
|
assert(0 <= dimension && dimension < 3);
|
||||||
|
switch (dimension) {
|
||||||
|
case Dimension::X:
|
||||||
|
return this->x;
|
||||||
|
case Dimension::Y:
|
||||||
|
return this->y;
|
||||||
|
case Dimension::Z:
|
||||||
|
return this->z;
|
||||||
|
default: // This must never happen
|
||||||
|
return this->x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float const &Vector3d::operator[](int const dimension) const {
|
||||||
|
assert(0 <= dimension && dimension < 3);
|
||||||
|
switch (dimension) {
|
||||||
|
case Dimension::X:
|
||||||
|
return this->x;
|
||||||
|
case Dimension::Y:
|
||||||
|
return this->y;
|
||||||
|
case Dimension::Z:
|
||||||
|
return this->z;
|
||||||
|
default: // This must never happen
|
||||||
|
return this->x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 == 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 &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, 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/(Vector3d const &left, float right) {
|
||||||
|
return Vector3d(left.x / right, left.y / right, left.z / right);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assignment operators ////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
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, 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;
|
||||||
|
left.z *= right;
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3d &operator/=(Vector3d &left, float right) {
|
||||||
|
left.x /= right;
|
||||||
|
left.y /= right;
|
||||||
|
left.z /= right;
|
||||||
|
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 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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); }
|
||||||
|
|
||||||
|
void normalize(Vector3d *v) { *v = normalized(*v); }
|
47
common/vector3d.h
Normal file
47
common/vector3d.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#ifndef VECTOR3D_H
|
||||||
|
#define VECTOR3D_H
|
||||||
|
|
||||||
|
struct Vector3d {
|
||||||
|
// Components
|
||||||
|
float x, y, z;
|
||||||
|
|
||||||
|
// Enum for readability
|
||||||
|
enum Dimension { X, Y, Z };
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
Vector3d() : x(0), y(0), z(0) {}
|
||||||
|
Vector3d(float x, float y, float z) : x(x), y(y), z(z) {}
|
||||||
|
|
||||||
|
// Access operators
|
||||||
|
float &operator[](int dimension);
|
||||||
|
float const &operator[](int dimension) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Comparison operators
|
||||||
|
bool operator==(Vector3d const &left, Vector3d const &right);
|
||||||
|
bool operator!=(Vector3d const &left, Vector3d const &right);
|
||||||
|
|
||||||
|
// Arithmetic operators
|
||||||
|
Vector3d operator+(Vector3d const &left, Vector3d const &right);
|
||||||
|
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, float 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, float right);
|
||||||
|
|
||||||
|
// Useful functions
|
||||||
|
Vector3d componentProduct(Vector3d const &left, Vector3d const &right);
|
||||||
|
Vector3d componentQuotient(Vector3d const &left, Vector3d const &right);
|
||||||
|
Vector3d crossProduct(Vector3d const &left, Vector3d const &right);
|
||||||
|
float dotProduct(Vector3d const &left, Vector3d const &right);
|
||||||
|
float length(Vector3d const &v);
|
||||||
|
Vector3d normalized(Vector3d const &v);
|
||||||
|
void normalize(Vector3d *v);
|
||||||
|
|
||||||
|
#endif
|
2
data/README.txt
Normal file
2
data/README.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
Download the data folder from the lecture page under https://graphics.tu-bs.de/teaching
|
||||||
|
BRDFs courtesy of https://www.merl.com/brdf/
|
52
ex1.cpp
Normal file
52
ex1.cpp
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
#include "camera/perspectivecamera.h"
|
||||||
|
|
||||||
|
#include "renderer/simplerenderer.h"
|
||||||
|
|
||||||
|
#include "scene/simplescene.h"
|
||||||
|
|
||||||
|
#include "primitive/infiniteplane.h"
|
||||||
|
#include "primitive/sphere.h"
|
||||||
|
#include "primitive/triangle.h"
|
||||||
|
|
||||||
|
#include "shader/flatshader.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Let's create a simple cornell box scene...
|
||||||
|
SimpleScene scene;
|
||||||
|
|
||||||
|
// Add shaders for the walls
|
||||||
|
auto red = std::make_shared<FlatShader>(Color(1.0f, 0.3f, 0.2f));
|
||||||
|
auto white = std::make_shared<FlatShader>(Color(1.0f, 1.0f, 1.0f));
|
||||||
|
auto blue = std::make_shared<FlatShader>(Color(0.2f, 0.3f, 1.0f));
|
||||||
|
|
||||||
|
// Add shaders for the objects
|
||||||
|
auto green = std::make_shared<FlatShader>(Color(0.0f, 1.0f, 0.0f));
|
||||||
|
auto purple = std::make_shared<FlatShader>(Color(0.5f, 0.2f, 1.0f));
|
||||||
|
auto orange = std::make_shared<FlatShader>(Color(1.0f, 0.5f, 0.0f));
|
||||||
|
|
||||||
|
// Set up the cornell box walls
|
||||||
|
scene.add(std::make_shared<InfinitePlane>(Vector3d(0.0f, 0.0f, +5.0f), Vector3d(0.0f, 0.0f, -1.0f), purple));
|
||||||
|
scene.add(std::make_shared<InfinitePlane>(Vector3d(0.0f, 0.0f, -5.0f), Vector3d(0.0f, 0.0f, +1.0f), purple));
|
||||||
|
scene.add(std::make_shared<InfinitePlane>(Vector3d(0.0f, +5.0f, 0.0f), Vector3d(0.0f, -1.0f, 0.0f), white));
|
||||||
|
scene.add(std::make_shared<InfinitePlane>(Vector3d(0.0f, -5.0f, 0.0f), Vector3d(0.0f, +1.0f, 0.0f), white));
|
||||||
|
scene.add(std::make_shared<InfinitePlane>(Vector3d(+5.0f, 0.0f, 0.0f), Vector3d(-1.0f, 0.0f, 0.0f), blue));
|
||||||
|
scene.add(std::make_shared<InfinitePlane>(Vector3d(-5.0f, 0.0f, 0.0f), Vector3d(+1.0f, 0.0f, 0.0f), red));
|
||||||
|
|
||||||
|
// Add a sphere
|
||||||
|
scene.add(std::make_shared<Sphere>(Vector3d(-3.0f, 0.0f, 0.0f), 1.5f, green));
|
||||||
|
scene.add(std::make_shared<Triangle>(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));
|
||||||
|
|
||||||
|
// Render the scene
|
||||||
|
SimpleRenderer renderer;
|
||||||
|
renderer.renderImage(scene, camera, 512, 512).save("result.png");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
BIN
images/cmake-gui-generator.png
Normal file
BIN
images/cmake-gui-generator.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
images/cmake-gui.png
Normal file
BIN
images/cmake-gui.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.3 KiB |
BIN
images/vs.png
Normal file
BIN
images/vs.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
34
light/light.h
Normal file
34
light/light.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#ifndef LIGHT_H
|
||||||
|
#define LIGHT_H
|
||||||
|
|
||||||
|
#include "common/color.h"
|
||||||
|
#include "common/ray.h"
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
class Scene;
|
||||||
|
|
||||||
|
class Light {
|
||||||
|
public:
|
||||||
|
// Illumination object
|
||||||
|
struct Illumination {
|
||||||
|
Color color;
|
||||||
|
Vector3d direction;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Constructor / Destructor
|
||||||
|
Light(float intensity, Color const &color = Color(1, 1, 1)) : color(color), intensity(intensity) {}
|
||||||
|
virtual ~Light() = default;
|
||||||
|
|
||||||
|
// Set
|
||||||
|
void setColor(Color const &color) { this->color = color; }
|
||||||
|
void setIntensity(float intensity) { this->intensity = intensity; }
|
||||||
|
|
||||||
|
// Light functions
|
||||||
|
virtual Illumination illuminate(Scene const &scene, Ray const &ray) const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Color color;
|
||||||
|
float intensity;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
45
primitive/infiniteplane.cpp
Normal file
45
primitive/infiniteplane.cpp
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#include "primitive/infiniteplane.h"
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
// Constructor /////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
InfinitePlane::InfinitePlane(std::shared_ptr<Shader> const &shader) : Primitive(shader), normal(0, 1, 0) {}
|
||||||
|
|
||||||
|
InfinitePlane::InfinitePlane(Vector3d const &origin, Vector3d const &normal, std::shared_ptr<Shader> const &shader)
|
||||||
|
: Primitive(shader), origin(origin), normal(normal) {}
|
||||||
|
|
||||||
|
// Primitive functions /////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool InfinitePlane::intersect(Ray &ray) const {
|
||||||
|
// IMPLEMENT ME!
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// Determine whether the ray intersects the plane
|
||||||
|
|
||||||
|
// Test whether this is the foremost primitive in front of the camera
|
||||||
|
|
||||||
|
// (Optional for now) Set the normal
|
||||||
|
|
||||||
|
// Set the new length and the current primitive
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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::maximumBounds(int dimension) const {
|
||||||
|
if (this->normal[dimension] == 1.0f) // plane is orthogonal to the axis
|
||||||
|
return this->origin[dimension] + EPSILON;
|
||||||
|
else
|
||||||
|
return +INFINITY;
|
||||||
|
}
|
28
primitive/infiniteplane.h
Normal file
28
primitive/infiniteplane.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef INFINITEPLANE_H
|
||||||
|
#define INFINITEPLANE_H
|
||||||
|
|
||||||
|
#include "primitive/primitive.h"
|
||||||
|
|
||||||
|
class InfinitePlane : public Primitive {
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructor
|
||||||
|
InfinitePlane(std::shared_ptr<Shader> const &shader);
|
||||||
|
InfinitePlane(Vector3d const &origin, Vector3d const &normal, std::shared_ptr<Shader> const &shader);
|
||||||
|
|
||||||
|
// Set
|
||||||
|
void setOrigin(Vector3d const &origin) { this->origin = origin; }
|
||||||
|
void setNormal(Vector3d const &normal) { this->normal = normalized(normal); }
|
||||||
|
|
||||||
|
// Primitive functions
|
||||||
|
bool intersect(Ray &ray) const override;
|
||||||
|
|
||||||
|
// Bounding box
|
||||||
|
float minimumBounds(int dimension) const override;
|
||||||
|
float maximumBounds(int dimension) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Vector3d origin, normal;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
30
primitive/primitive.h
Normal file
30
primitive/primitive.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef PRIMITIVE_H
|
||||||
|
#define PRIMITIVE_H
|
||||||
|
|
||||||
|
#include "common/ray.h"
|
||||||
|
#include "shader/shader.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class Primitive {
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructor / Destructor
|
||||||
|
Primitive(const std::shared_ptr<Shader> &shader) : shader_(shader) {}
|
||||||
|
virtual ~Primitive() = default;
|
||||||
|
|
||||||
|
// Get
|
||||||
|
std::shared_ptr<Shader> shader() const { return this->shader_; }
|
||||||
|
|
||||||
|
// Primitive functions
|
||||||
|
virtual bool intersect(Ray &ray) const = 0;
|
||||||
|
|
||||||
|
// Bounding box
|
||||||
|
virtual float minimumBounds(int dimension) const = 0;
|
||||||
|
virtual float maximumBounds(int dimension) const = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<Shader> shader_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
33
primitive/sphere.cpp
Normal file
33
primitive/sphere.cpp
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#include "common/ray.h"
|
||||||
|
#include "primitive/sphere.h"
|
||||||
|
|
||||||
|
// Constructor /////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Sphere::Sphere(std::shared_ptr<Shader> const &shader) : Primitive(shader), radius(0.5f) {}
|
||||||
|
|
||||||
|
Sphere::Sphere(Vector3d const ¢er, float radius, std::shared_ptr<Shader> const &shader)
|
||||||
|
: Primitive(shader), center(center), radius(radius) {}
|
||||||
|
|
||||||
|
// Primitive functions /////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool Sphere::intersect(Ray &ray) const {
|
||||||
|
// IMPLEMENT ME!
|
||||||
|
|
||||||
|
// Determine whether the ray intersects the sphere
|
||||||
|
|
||||||
|
// Test whether this is the foremost primitive in front of the camera
|
||||||
|
|
||||||
|
// (Optional for now) Calculate the normal
|
||||||
|
|
||||||
|
// (Optional for now) Calculate the surface position
|
||||||
|
|
||||||
|
// Set the new length and the current primitive
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bounding box ////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
float Sphere::minimumBounds(int dimension) const { return this->center[dimension] - this->radius; }
|
||||||
|
|
||||||
|
float Sphere::maximumBounds(int dimension) const { return this->center[dimension] + this->radius; }
|
29
primitive/sphere.h
Normal file
29
primitive/sphere.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef SPHERE_H
|
||||||
|
#define SPHERE_H
|
||||||
|
|
||||||
|
#include "primitive/primitive.h"
|
||||||
|
|
||||||
|
class Sphere : public Primitive {
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructor
|
||||||
|
Sphere(std::shared_ptr<Shader> const &shader);
|
||||||
|
Sphere(Vector3d const ¢er, float radius, std::shared_ptr<Shader> const &shader);
|
||||||
|
|
||||||
|
// Set
|
||||||
|
void setCenter(Vector3d const ¢er) { this->center = center; }
|
||||||
|
void setRadius(float radius) { this->radius = radius; }
|
||||||
|
|
||||||
|
// Primitive functions
|
||||||
|
bool intersect(Ray &ray) const override;
|
||||||
|
|
||||||
|
// Bounding box
|
||||||
|
float minimumBounds(int dimension) const override;
|
||||||
|
float maximumBounds(int dimension) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Vector3d center;
|
||||||
|
float radius;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
47
primitive/triangle.cpp
Normal file
47
primitive/triangle.cpp
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#include "primitive/triangle.h"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
// Constructor /////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
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)
|
||||||
|
: 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<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,
|
||||||
|
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 functions /////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
bool Triangle::intersect(Ray &ray) const {
|
||||||
|
// IMPLEMENT ME!
|
||||||
|
|
||||||
|
// Determine whether the ray intersects the triangle
|
||||||
|
|
||||||
|
// Test whether this is the foremost primitive in front of the camera
|
||||||
|
|
||||||
|
// (Optional for now) Calculate the normal
|
||||||
|
|
||||||
|
// (Optional for now) Calculate the surface position
|
||||||
|
|
||||||
|
// Set the new length and the current primitive
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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::maximumBounds(int dimension) const {
|
||||||
|
return std::max(this->vertex[0][dimension], std::max(this->vertex[1][dimension], this->vertex[2][dimension]));
|
||||||
|
}
|
41
primitive/triangle.h
Normal file
41
primitive/triangle.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#ifndef TRIANGLE_H
|
||||||
|
#define TRIANGLE_H
|
||||||
|
|
||||||
|
#include "primitive/primitive.h"
|
||||||
|
|
||||||
|
class Triangle : public Primitive {
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructor
|
||||||
|
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, Vector3d const &na, Vector3d const &nb,
|
||||||
|
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);
|
||||||
|
|
||||||
|
// 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; }
|
||||||
|
|
||||||
|
// Primitive functions
|
||||||
|
bool intersect(Ray &ray) const override;
|
||||||
|
|
||||||
|
// Bounding box
|
||||||
|
float minimumBounds(int dimension) const override;
|
||||||
|
float maximumBounds(int dimension) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Vector3d vertex[3];
|
||||||
|
Vector3d normal[3];
|
||||||
|
Vector3d tangent[3];
|
||||||
|
Vector3d bitangent[3];
|
||||||
|
Vector2d surface[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
21
renderer/renderer.h
Normal file
21
renderer/renderer.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef RENDERER_H
|
||||||
|
#define RENDERER_H
|
||||||
|
|
||||||
|
#include "common/texture.h"
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
class Camera;
|
||||||
|
class Scene;
|
||||||
|
|
||||||
|
class Renderer {
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructor / Destructor
|
||||||
|
Renderer() = default;
|
||||||
|
virtual ~Renderer() = default;
|
||||||
|
|
||||||
|
// Render functions
|
||||||
|
virtual Texture renderImage(Scene const &scene, Camera const &camera, int width, int height) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
16
renderer/simplerenderer.cpp
Normal file
16
renderer/simplerenderer.cpp
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#include "camera/camera.h"
|
||||||
|
#include "renderer/simplerenderer.h"
|
||||||
|
#include "scene/scene.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <chrono>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
Texture SimpleRenderer::renderImage(Scene const &scene, Camera const &camera, int width, int height) {
|
||||||
|
Texture image(width, height);
|
||||||
|
|
||||||
|
// Calculate the aspect ration
|
||||||
|
|
||||||
|
// Create the image by casting one ray into the scene for each pixel
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
17
renderer/simplerenderer.h
Normal file
17
renderer/simplerenderer.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef SIMPLERENDERER_H
|
||||||
|
#define SIMPLERENDERER_H
|
||||||
|
|
||||||
|
#include "renderer/renderer.h"
|
||||||
|
|
||||||
|
class SimpleRenderer : public Renderer {
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructor / Destructor
|
||||||
|
SimpleRenderer() = default;
|
||||||
|
~SimpleRenderer() override = default;
|
||||||
|
|
||||||
|
// Render functions
|
||||||
|
Texture renderImage(Scene const &scene, Camera const &camera, int width, int height) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
32
scene/scene.cpp
Normal file
32
scene/scene.cpp
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#include "light/light.h"
|
||||||
|
#include "primitive/triangle.h"
|
||||||
|
#include "scene/scene.h"
|
||||||
|
#include "shader/shader.h"
|
||||||
|
#include <array>
|
||||||
|
#include <cassert>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
void Scene::add(const std::shared_ptr<Light> &light) { this->lights_.push_back(light); }
|
||||||
|
|
||||||
|
void Scene::add(const std::shared_ptr<Primitive> &primitive) {
|
||||||
|
assert(primitive->shader() != nullptr);
|
||||||
|
this->primitives_.push_back(primitive);
|
||||||
|
}
|
||||||
|
|
||||||
|
Color Scene::traceRay(Ray &ray) const {
|
||||||
|
if (this->findIntersection(ray) && ray.remainingBounces-- > 0) {
|
||||||
|
// If the ray has hit an object, call the shader ...
|
||||||
|
return ray.primitive->shader()->shade(*this, ray);
|
||||||
|
} else if (this->environmentMap) {
|
||||||
|
// ... otherwise look up the environment map ...
|
||||||
|
float const phi = std::acos(ray.direction.y);
|
||||||
|
float const rho = std::atan2(ray.direction.z, ray.direction.x) + float(PI);
|
||||||
|
return this->environmentMap->color(rho / (2.0f * float(PI)), phi / float(PI));
|
||||||
|
} else {
|
||||||
|
// ... if all else fails, just return the background color
|
||||||
|
return this->backgroundColor;
|
||||||
|
}
|
||||||
|
}
|
50
scene/scene.h
Normal file
50
scene/scene.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
#ifndef SCENE_H
|
||||||
|
#define SCENE_H
|
||||||
|
|
||||||
|
#include "common/color.h"
|
||||||
|
#include "common/ray.h"
|
||||||
|
#include "common/texture.h"
|
||||||
|
#include "common/vector3d.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
class Light;
|
||||||
|
class Primitive;
|
||||||
|
class Shader;
|
||||||
|
|
||||||
|
class Scene {
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructor / Destructor
|
||||||
|
Scene() = default;
|
||||||
|
virtual ~Scene() = default;
|
||||||
|
|
||||||
|
// Get
|
||||||
|
std::vector<std::shared_ptr<Light>> const &lights() const { return this->lights_; }
|
||||||
|
std::vector<std::shared_ptr<Primitive>> const &primitives() const { return this->primitives_; }
|
||||||
|
|
||||||
|
// Set
|
||||||
|
void setBackgroundColor(Color const &color) { this->backgroundColor = color; }
|
||||||
|
void setEnvironmentMap(std::shared_ptr<Texture> const &map) { this->environmentMap = map; }
|
||||||
|
|
||||||
|
// Setup functions
|
||||||
|
void add(const std::shared_ptr<Light> &light);
|
||||||
|
void add(const std::shared_ptr<Primitive> &primitive);
|
||||||
|
|
||||||
|
// Raytracing functions
|
||||||
|
Color traceRay(Ray &ray) const;
|
||||||
|
virtual bool findIntersection(Ray &ray) const = 0;
|
||||||
|
virtual bool findOcclusion(Ray &ray) const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Color backgroundColor;
|
||||||
|
std::shared_ptr<Texture> environmentMap;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::shared_ptr<Light>> lights_;
|
||||||
|
std::vector<std::shared_ptr<Primitive>> primitives_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
17
scene/simplescene.cpp
Normal file
17
scene/simplescene.cpp
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#include "scene/simplescene.h"
|
||||||
|
#include "primitive/primitive.h"
|
||||||
|
#include "shader/shader.h"
|
||||||
|
|
||||||
|
bool SimpleScene::findIntersection(Ray &ray) const {
|
||||||
|
bool hit = false;
|
||||||
|
for (auto i : this->primitives())
|
||||||
|
hit |= i->intersect(ray);
|
||||||
|
return hit;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SimpleScene::findOcclusion(Ray &ray) const {
|
||||||
|
for (auto i : this->primitives())
|
||||||
|
if (i->intersect(ray) && !i->shader()->isTransparent())
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
14
scene/simplescene.h
Normal file
14
scene/simplescene.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef SIMPLESCENE_H
|
||||||
|
#define SIMPLESCENE_H
|
||||||
|
|
||||||
|
#include "scene/scene.h"
|
||||||
|
|
||||||
|
class SimpleScene : public Scene {
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Raytracing functions
|
||||||
|
bool findIntersection(Ray &ray) const override;
|
||||||
|
bool findOcclusion(Ray &ray) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
8
shader/flatshader.cpp
Normal file
8
shader/flatshader.cpp
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#include "shader/flatshader.h"
|
||||||
|
|
||||||
|
FlatShader::FlatShader(Color const &objectColor) : objectColor(objectColor) {}
|
||||||
|
|
||||||
|
Color FlatShader::shade(Scene const &scene, Ray const &ray) const {
|
||||||
|
(void)ray; // ray is unused in this case, but we do not want a warning.
|
||||||
|
return this->objectColor;
|
||||||
|
}
|
19
shader/flatshader.h
Normal file
19
shader/flatshader.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef FLATSHADER_H
|
||||||
|
#define FLATSHADER_H
|
||||||
|
|
||||||
|
#include "shader/shader.h"
|
||||||
|
|
||||||
|
class FlatShader : public Shader {
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructor
|
||||||
|
FlatShader(Color const &objectColor);
|
||||||
|
|
||||||
|
// Shader functions
|
||||||
|
virtual Color shade(Scene const &scene, Ray const &ray) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Color objectColor;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
23
shader/shader.h
Normal file
23
shader/shader.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#ifndef SHADER_H
|
||||||
|
#define SHADER_H
|
||||||
|
|
||||||
|
#include "common/color.h"
|
||||||
|
#include "common/ray.h"
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
class Scene;
|
||||||
|
|
||||||
|
class Shader {
|
||||||
|
public:
|
||||||
|
// Constructor / Desctructor
|
||||||
|
Shader() = default;
|
||||||
|
virtual ~Shader() = default;
|
||||||
|
|
||||||
|
// Get
|
||||||
|
virtual bool isTransparent() const { return false; }
|
||||||
|
|
||||||
|
// Shader functions
|
||||||
|
virtual Color shade(Scene const &scene, Ray const &ray) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue