aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--CMakeLists.txt32
-rw-r--r--Cargo.toml9
-rw-r--r--app/config.hpp22
-rw-r--r--app/draw.cpp32
-rw-r--r--app/draw.hpp30
-rw-r--r--app/main.cpp48
-rw-r--r--app/mainwindow.cpp50
-rw-r--r--app/mainwindow.hpp34
-rw-r--r--app/rendercoord.cpp220
-rw-r--r--app/rendercoord.hpp93
-rw-r--r--src/common.hpp6
-rw-r--r--src/main.rs3
-rw-r--r--src/object.cpp103
-rw-r--r--src/object.hpp76
-rw-r--r--src/ray.cpp17
-rw-r--r--src/ray.hpp15
-rw-r--r--src/render.cpp166
-rw-r--r--src/render.hpp61
-rw-r--r--src/scene.cpp5
-rw-r--r--src/scene.hpp15
-rw-r--r--src/vector.cpp106
-rw-r--r--src/vector.hpp33
-rw-r--r--test/main.cpp2
-rw-r--r--test/object.cpp36
-rw-r--r--test/vector.cpp31
26 files changed, 13 insertions, 1233 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/target
diff --git a/CMakeLists.txt b/CMakeLists.txt
deleted file mode 100644
index df9bd70..0000000
--- a/CMakeLists.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-cmake_minimum_required(VERSION 3.10)
-
-project(pathtracing)
-
-# cmake options
-set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
-set(CMAKE_AUTOMOC ON)
-
-set(CMAKE_CXX_STANDARD 11)
-set(CMAKE_CXX_STANDARD_REQUIRED True)
-
-# Compiler options
-set(CMAKE_CXX_FLAGS "-Wall -Wextra")
-set(CMAKE_CXX_FLAGS_DEBUG "-g")
-set(CMAKE_CXX_FLAGS_RELEASE "-O3")
-
-FILE(GLOB app_sources ${CMAKE_SOURCE_DIR}/app/*.cpp)
-FILE(GLOB sources ${CMAKE_SOURCE_DIR}/src/*.cpp)
-FILE(GLOB test_sources ${CMAKE_SOURCE_DIR}/test/*.cpp)
-
-add_executable(pathtracing ${sources} ${app_sources})
-target_include_directories(pathtracing PUBLIC src)
-
-# Catch2 unittests
-add_custom_target(test)
-add_executable(run_test EXCLUDE_FROM_ALL ${sources} ${test_sources})
-target_include_directories(run_test PUBLIC src)
-add_dependencies(test run_test)
-
-# Qt
-find_package(Qt5 COMPONENTS Widgets REQUIRED)
-target_link_libraries(pathtracing Qt5::Widgets)
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..621e7e3
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "pathtrace"
+version = "0.1.0"
+authors = ["Julian T <julian@jtle.dk>"]
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/app/config.hpp b/app/config.hpp
deleted file mode 100644
index 6e9962c..0000000
--- a/app/config.hpp
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef CONFIG_H
-#define CONFIG_H
-
-#include <render.hpp>
-
-class Config {
- public:
- unsigned m_width, m_height;
- unsigned m_maxhops, m_samples;
-
- unsigned m_framerate, m_workers;
-};
-
-class RendererConf : public Renderer {
- public:
- RendererConf(const Scene &scn, Vec3d eye, Vec3d target, Config &conf)
- : Renderer(scn, eye, target, conf.m_width, conf.m_height, conf.m_maxhops) {
-
- }
-};
-
-#endif
diff --git a/app/draw.cpp b/app/draw.cpp
deleted file mode 100644
index 88733ef..0000000
--- a/app/draw.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-#include "draw.hpp"
-#include <qnamespace.h>
-#include <qpainter.h>
-#include <qglobal.h>
-#include <qimage.h>
-#include <qrgb.h>
-#include <qtimer.h>
-#include <qwindowdefs.h>
-#include <iostream>
-
-DrawWidget::DrawWidget(const Config &conf) :
- QWidget(), m_conf(conf) {
- m_drawbuffer = new QRgb[conf.m_width * conf.m_height];
-
- m_img = QImage((uchar*)m_drawbuffer, conf.m_width, conf.m_height, QImage::Format_ARGB32);
-
-}
-
-void DrawWidget::paintEvent(QPaintEvent*) {
- QPainter painter(this);
-
- auto scaled = m_img.scaled(width(), height(), Qt::KeepAspectRatio);
- painter.drawImage(0, 0, scaled);
-}
-
-void DrawWidget::redraw() {
- repaint();
-}
-
-DrawWidget::~DrawWidget() {
- delete[] m_drawbuffer;
-}
diff --git a/app/draw.hpp b/app/draw.hpp
deleted file mode 100644
index 454558c..0000000
--- a/app/draw.hpp
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef DRAW_H
-#define DRAW_H
-
-#include "config.hpp"
-#include <qimage.h>
-#include <qtimer.h>
-#include <qwidget.h>
-
-class DrawWidget : public QWidget {
- Q_OBJECT
-
- public:
- DrawWidget(const Config &conf);
- void paintEvent(QPaintEvent*);
-
- QRgb *m_drawbuffer;
- QImage m_img;
- unsigned m_width, m_height;
-
- ~DrawWidget();
- private slots:
- void redraw();
-
- private:
- unsigned char i;
-
- const Config &m_conf;
-};
-
-#endif
diff --git a/app/main.cpp b/app/main.cpp
deleted file mode 100644
index e53b8ad..0000000
--- a/app/main.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-#include <iostream>
-#include <qapplication.h>
-#include <qpushbutton.h>
-
-#include "mainwindow.hpp"
-#include "vector.hpp"
-#include <scene.hpp>
-#include <render.hpp>
-#include <object.hpp>
-
-using namespace std;
-
-int main(int argc, char *argv[])
-{
- QApplication a(argc, argv);
- Scene scn;
- Config conf;
- conf.m_width = 500;
- conf.m_height = 500;
- conf.m_maxhops = 5;
- conf.m_samples = 100;
- conf.m_framerate = 3;
- conf.m_workers = 4;
-
-
- Material blue(Color(0.3, 0.3, 1), 1);
- Material red(Color(1, 0.3, 0.3), 1);
- Material white(Color(1, 1, 1), 1);
- Material em(Color(1, 1, 1), 0, 2);
-
- scn.addShape(new Sphere(red, Vec3d(2, 6, -1), 1));
- scn.addShape(new Sphere(white, Vec3d(0, 4, -1), 1.3));
- scn.addShape(new Sphere(white, Vec3d(-2, 5, -2), 1.3));
- scn.addShape(new Sphere(blue, Vec3d(0, 7, 0), 0.5));
-
- scn.addShape(new Plane(em, Vec3d(0, 0, 0), Vec3d(0, 1, 0)));
- scn.addShape(new Plane(white, Vec3d(0, 10, 0), Vec3d(0, 1, 0)));
- scn.addShape(new Plane(white, Vec3d(0, 0, -5), Vec3d(0, 0, 1)));
- scn.addShape(new Plane(red, Vec3d(-5, 0, 0), Vec3d(1, 0, 0)));
- scn.addShape(new Plane(blue, Vec3d(5, 0, 0), Vec3d(1, 0, 0)));
-
- RendererConf render(scn, Vec3d(0, 5, 4), Vec3d(0, 5, 0), conf);
-
- MainWindow main(render, conf);
- main.show();
-
- return a.exec();
-}
diff --git a/app/mainwindow.cpp b/app/mainwindow.cpp
deleted file mode 100644
index eed98f9..0000000
--- a/app/mainwindow.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-#include "mainwindow.hpp"
-#include <qaction.h>
-#include <qapplication.h>
-#include <qlabel.h>
-#include <qnamespace.h>
-#include <QFileDialog>
-#include <QMessageBox>
-
-MainWindow::MainWindow(Renderer r, const Config &conf)
- : m_drawer(conf),
- runstatus("Not running", this),
- m_render(this, m_drawer, r, conf, &runstatus),
- m_conf(conf)
-{
-
- setCentralWidget(&m_drawer);
-
- auto saveAct = new QAction(tr("&Save as"), this);
- saveAct->setStatusTip(tr("Save the rendered image"));
- connect(saveAct, &QAction::triggered, this, &MainWindow::saveimage);
-
- auto stopAct = new QAction(tr("&Stop"), this);
- stopAct->setStatusTip(tr("Stop and sync threads"));
- QObject::connect(stopAct, &QAction::triggered, &m_render, &RenderCoordinator::stop);
-
- fileMenu = menuBar()->addMenu(tr("&File"));
- fileMenu->addAction(saveAct);
-
- fileMenu = menuBar()->addMenu(tr("&Render"));
- fileMenu->addAction(stopAct);
-
- helpMenu = menuBar()->addMenu(tr("&Help"));
- helpMenu->addAction(tr("About Qt"), qApp, &QApplication::aboutQt);
-
- statusBar()->addWidget(&runstatus);
-}
-
-void MainWindow::saveimage() {
-
- QGuiApplication::setOverrideCursor(Qt::WaitCursor);
- QString fileName = QFileDialog::getSaveFileName(this,
- tr("Save image"), "", tr("PNG image (*.png);;All Files (*)"));
- if (fileName.isEmpty()) {
- return;
- }
-
- if (!m_drawer.m_img.save(fileName)) {
- QMessageBox::information(this, tr("Unable to save file"), "");
- }
-}
diff --git a/app/mainwindow.hpp b/app/mainwindow.hpp
deleted file mode 100644
index ffb4f08..0000000
--- a/app/mainwindow.hpp
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef MAIN_H
-#define MAIN_H
-
-#include <QMainWindow>
-#include <QLabel>
-#include <QMenuBar>
-#include <QStatusBar>
-
-#include "config.hpp"
-#include "draw.hpp"
-#include "rendercoord.hpp"
-#include <qmainwindow.h>
-#include <render.hpp>
-
-class MainWindow : public QMainWindow {
- Q_OBJECT
-
- public:
- MainWindow(Renderer r, const Config &conf);
-
- private slots:
- void saveimage();
- private:
- DrawWidget m_drawer;
- QLabel runstatus;
- RenderCoordinator m_render;
-
- QMenu *fileMenu;
- QMenu *helpMenu;
-
- const Config &m_conf;
-};
-
-#endif
diff --git a/app/rendercoord.cpp b/app/rendercoord.cpp
deleted file mode 100644
index 00a6437..0000000
--- a/app/rendercoord.cpp
+++ /dev/null
@@ -1,220 +0,0 @@
-#include "rendercoord.hpp"
-#include <algorithm>
-#include <qobject.h>
-#include <iostream>
-#include <qrgb.h>
-
-#include <qsemaphore.h>
-#include <render.hpp>
-#include <sstream>
-
-uint32_t colorToUint32(const Color &c) {
- Color cnew = Color(c);
- cnew.clamp();
- return (0xFF << 24) +
- (cnew.r() << 16) +
- (cnew.g() << 8) +
- cnew.b();
-}
-
-// Run by main thread
-RenderThread::RenderThread(Renderer r, unsigned threads, const Config &conf, QObject *parent, unsigned id)
- : QThread(parent),
- m_lock(1),
- m_render(r),
- m_conf(conf),
- m_pause(1)
-{
- m_id = id;
- m_workers = threads;
-}
-
-// Run on new thread
-void RenderThread::run() {
- while (1) {
- // Wait for work
- m_work.acquire();
-
- // Very expensive, but necesary to get live rendering
- Color *sum = new Color[m_render.m_width * m_render.m_height];
-
- m_current_samples = 0;
-
- for (int sample = 0; sample < m_samples; sample++) {
- m_current_samples = sample;
- // Probably not that smart
- m_pause.acquire();
- m_pause.release();
-
- for (unsigned y = m_id; y < m_render.m_height; y += m_workers) {
- for (unsigned x = 0; x < m_render.m_width; x++) {
- auto index = x + y * m_render.m_width;
- sum[index] += m_render.render(m_render.m_width - x, m_render.m_height - y, 1);
-
- m_writebuffer[index] = colorToUint32(sum[index] / (sample+1));
- }
- }
-
- }
-
- // Signal done
- m_lock.release();
- emit done(m_id);
- }
-}
-
-void RenderThread::pause() {
- m_pause.acquire();
-}
-
-void RenderThread::resume() {
- m_pause.release();
-}
-
-int RenderThread::render(QRgb *buffer, unsigned samples) {
- // Check if already running
- if (!m_lock.tryAcquire()) {
- return 1;
- }
- m_writebuffer = buffer;
- m_samples = samples;
- m_work.release();
- std::cout << samples << std::endl;
-
- return 0;
-}
-
-unsigned RenderThread::stop() {
- stopAt(m_current_samples);
- return m_current_samples;
-}
-
-void RenderThread::stopAt(int at) {
- m_samples = at;
-}
-
-// Running on main thread
-unsigned RenderThread::current_samples() {
- // No sync should not be a problem here.
- return m_current_samples;
-}
-
-RenderCoordinator::RenderCoordinator(QObject *parent, DrawWidget &target, Renderer r, const Config &conf, QLabel *status)
- : QObject(parent),
- m_target(target),
- m_renderer(r),
- m_timer(this),
- m_conf(conf)
-{
- m_status = status;
-
- // Create and start workers
- for (unsigned i = 0; i < conf.m_workers; i++) {
- auto thread = new RenderThread(m_renderer, conf.m_workers, conf, this, i);
-
- thread->start();
- QObject::connect(thread, &RenderThread::done, this, &RenderCoordinator::workerDone);
-
- m_workers.push_back(thread);
- }
-
- render();
-
-}
-
-void RenderCoordinator::render() {
- m_started = 0;
- for (auto thd : m_workers) {
- thd->render(m_target.m_drawbuffer, m_conf.m_samples);
- m_started++;
- }
-
- m_state = running;
- updateUi();
-
- QObject::connect(&m_timer, &QTimer::timeout, this, &RenderCoordinator::updateUi);
-
- m_timer.start(1000.0 / m_conf.m_framerate);
-}
-
-void RenderCoordinator::stop() {
- unsigned max = 0;
- for (auto thd : m_workers) {
- thd->pause();
-
- auto val = thd->current_samples();
- if (val>max) {
- max = val;
- }
- }
-
- std::cout << max << std::endl;
-
- for (auto thd : m_workers) {
- thd->stopAt(max+1);
- thd->resume();
- }
-
- m_state = stopping;
- updateUi();
-}
-
-void RenderCoordinator::workerDone(unsigned workerid) {
- std::cout << "Worker " << workerid << " done!" << std::endl;
- if (--m_started) {
- return;
- }
- std::cout << "All done :-)" << std::endl;
-
- // All workers are done
- m_state = stopped;
- m_timer.stop();
- updateUi();
-}
-
-unsigned RenderCoordinator::calcStats(unsigned *max, unsigned *min, double *avg) {
- unsigned count = 0;
- unsigned sum = 0;
- for (auto thd : m_workers) {
- auto val = thd->current_samples();
- if (min && (val < *min || !count)) {
- *min = val;
- }
- if (max && (val > *max || !count)) {
- *max = val;
- }
-
- sum += val;
- count++;
- }
-
- if (avg) {
- *avg = (double)sum / count;
- }
-
- return count;
-}
-
-
-void RenderCoordinator::updateUi() {
- m_target.repaint();
-
- if (!m_status) {
- return;
- }
-
- // Gather statictics from workers
- unsigned max;
- unsigned min;
- double avg;
- unsigned count = calcStats(&max, &min, &avg);
-
- std::ostringstream status;
- status << states[m_state] <<
- " Threads: " << count <<
- " Max: " << max << " samples" <<
- " Min: " << min << " samples" <<
- " Avg: " << avg << " samples";
-
- m_status->setText(QString::fromStdString(status.str()));
-}
diff --git a/app/rendercoord.hpp b/app/rendercoord.hpp
deleted file mode 100644
index eea1b40..0000000
--- a/app/rendercoord.hpp
+++ /dev/null
@@ -1,93 +0,0 @@
-#ifndef RENDER_THREAD_H
-#define RENDER_THREAD_H
-
-#include "draw.hpp"
-#include "config.hpp"
-#include <atomic>
-#include <qlabel.h>
-#include <render.hpp>
-
-#include <qobject.h>
-#include <qrgb.h>
-#include <qthread.h>
-#include <qsemaphore.h>
-#include <vector>
-// https://doc.qt.io/archives/qt-4.8/qt-threads-mandelbrot-example.html
-
-class RenderThread : public QThread {
- Q_OBJECT
-
- public:
- RenderThread(Renderer r, unsigned threads, const Config &cfg, QObject *parent = nullptr, unsigned id = 0);
-
- // Returns 0 if successful or 1 if busy
- int render(QRgb *buffer, unsigned samples);
-
- void pause();
- void resume();
-
- unsigned stop();
- void stopAt(int at);
-
- unsigned current_samples();
-
- signals:
- void done(unsigned workerid);
-
- protected:
- void run();
-
- QSemaphore m_lock;
-
- QRgb *m_writebuffer;
- std::atomic_int m_samples;
- std::atomic_int m_current_samples;
-
- Renderer m_render;
-
- unsigned m_workers;
-
- Config const m_conf;
-
- // Value in here means work is to be done
- QSemaphore m_work;
- QSemaphore m_pause;
- unsigned m_id;
-};
-
-const std::string states[] = { "Stopped", "Running", "Stopping" };
-enum State { stopped, running, stopping };
-
-class RenderCoordinator : public QObject {
- Q_OBJECT
-
- public:
- RenderCoordinator(QObject *parent, DrawWidget &target, Renderer r, const Config &conf, QLabel *status=nullptr);
- void setSamples(unsigned samples);
- void render();
-
- public slots:
- void workerDone(unsigned workerid);
- void stop();
-
- private slots:
- void updateUi();
-
- private:
- unsigned calcStats(unsigned *max, unsigned *min, double *avg);
-
- DrawWidget &m_target;
-
- Renderer m_renderer;
- std::vector<RenderThread*> m_workers;
- unsigned m_started;
-
- QLabel *m_status;
- QTimer m_timer;
-
- State m_state;
-
- const Config &m_conf;
-};
-
-#endif
diff --git a/src/common.hpp b/src/common.hpp
deleted file mode 100644
index fd219bf..0000000
--- a/src/common.hpp
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef COMMON_H
-#define COMMON_H
-
-#define ZERO_APPROX 1e-6
-
-#endif
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..e7a11a9
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,3 @@
+fn main() {
+ println!("Hello, world!");
+}
diff --git a/src/object.cpp b/src/object.cpp
deleted file mode 100644
index 1449cbb..0000000
--- a/src/object.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-#include "object.hpp"
-
-#include <math.h>
-#include <iostream>
-#include "common.hpp"
-
-void Color::clamp() {
- if (m_x > 1) { m_x = 1; }
- if (m_y > 1) { m_y = 1; }
- if (m_z > 1) { m_z = 1; }
-}
-
-Material::Material(Color color, double defuse, double emissive) {
- m_color = color;
- m_defuse = defuse;
- m_emissive = emissive;
-}
-
-Color Material::reflect(const Vec3d &normal, const Vec3d &in, const Vec3d &out, const Color &incol) const {
- return Vec3d(m_color) * m_emissive +
- (Vec3d(m_color) * Vec3d(incol)) * (out.dot(normal) * m_defuse);
-}
-
-Sphere::Sphere(const Material &mat, Vec3d center, double radius) : Shape(mat) {
- m_center = center;
- m_radius = radius;
-}
-
-Plane::Plane(const Material &mat, Vec3d start, Vec3d norm) : Shape(mat) {
- m_start = start;
- m_norm = norm;
-
- m_norm.normalize();
-}
-
-Vec3d Sphere::norm_at(const Vec3d &point, const Vec3d&) const {
- auto res = point - m_center;
- res.normalize();
- return res;
-}
-
-// https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection
-double Sphere::intersect(const Ray &ray, bool skip_dist) const {
- // Calculate O - C used multiple places
- auto oc = ray.m_start - m_center;
- // Calculate components of quadratic formula
- // a = 1 when ray.direction is a unit vector
- auto a = 1;
- auto b = 2 * ray.m_direction.dot(oc);
- auto c = oc.dot(oc) - m_radius * m_radius;
-
- // Solve quadratic function
- auto discr = b * b - 4 * a * c;
- if (discr < 0) {
- // No solution
- return -1;
- }
- if (skip_dist) {
- // Do not calculate distance
- return 1;
- }
-
- auto q = (b > 0) ?
- -0.5 * (b + sqrt(discr)):
- -0.5 * (b - sqrt(discr));
- auto t1 = q; // Assuming a = 1
- auto t0 = c / q;
-
- // Find correct result
- if (t0 <= ZERO_APPROX) {
- t0 = t1;
- }
-
- if (t0 <= ZERO_APPROX) {
- return -1;
- }
-
- return t0;
-}
-
-Vec3d Plane::norm_at(const Vec3d&, const Vec3d &indir) const {
- auto scale = m_norm.dot(indir);
- return scale > 0 ? -m_norm : m_norm;
-}
-
-// https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-plane-and-ray-disk-intersection
-// Requires that vectors are normalized
-// Skip dist is ignored as distance must be calculated
-double Plane::intersect(const Ray &ray, bool) const {
- // If ray is parallel
- auto nr = m_norm.dot(ray.m_direction);
- if (abs(nr) < ZERO_APPROX) {
- return -1;
- }
-
- // Calculate distance
- auto dist = m_norm.dot(m_start - ray.m_start) / nr;
- if (dist < 0) {
- return -1;
- }
-
- return dist;
-}
diff --git a/src/object.hpp b/src/object.hpp
deleted file mode 100644
index e697ba2..0000000
--- a/src/object.hpp
+++ /dev/null
@@ -1,76 +0,0 @@
-#ifndef OBJECT_H
-#define OBJECT_H
-
-#include <memory>
-#include "vector.hpp"
-#include "ray.hpp"
-
-class Color : public Vec3d {
- public:
- Color() {}
- Color(const Vec3d &v) : Vec3d(v) {}
- Color(double r, double g, double b) : Vec3d(r, g, b) {}
-
- uint8_t r() { return m_x * 255; }
- uint8_t g() { return m_y * 255; }
- uint8_t b() { return m_z * 255; }
-
- Color& operator+=(const Color& op) {
- Vec3d::operator+=(op);
- return *this;
- }
- void clamp();
-};
-
-// Implements phong BRDF
-class Material {
- public:
- Material(Color color, double defuse, double emissive=0);
-
- Color reflect(const Vec3d &normal, const Vec3d &in, const Vec3d &out, const Color &incol) const;
-
- Color emits() const {
- return m_color * m_emissive;
- }
-
- // Whether the material is reflective
- bool reflects() const { return m_defuse > 0; }
- private:
- Color m_color;
- double m_defuse;
- double m_emissive;
-};
-
-class Shape {
- public:
- Shape(const Material &mat) : m_mat(mat) { }
-
- virtual Vec3d norm_at(const Vec3d &point, const Vec3d &indir) const = 0;
- virtual double intersect(const Ray &ray, bool skip_dist) const = 0;
-
- const Material &m_mat;
-};
-
-class Sphere : public Shape {
- public:
- Sphere(const Material &mat, Vec3d center, double radius);
- Vec3d norm_at(const Vec3d &point, const Vec3d &indir) const;
- double intersect(const Ray &ray, bool skip_dist) const;
-
- private:
- Vec3d m_center;
- double m_radius;
-};
-
-class Plane : public Shape {
- public:
- Plane(const Material &mat, Vec3d start, Vec3d norm);
- Vec3d norm_at(const Vec3d &point, const Vec3d &indir) const;
- double intersect(const Ray &ray, bool skip_dist) const;
-
- private:
- Vec3d m_start;
- Vec3d m_norm;
-};
-
-#endif
diff --git a/src/ray.cpp b/src/ray.cpp
deleted file mode 100644
index 7bc6201..0000000
--- a/src/ray.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-#include "ray.hpp"
-
-Ray::Ray(Vec3d start, Vec3d direction, bool normalize) {
- m_start = start;
- m_direction = direction;
-
- if (normalize) {
- m_direction.normalize();
- }
-}
-
-Ray::Ray(Vec3d a, Vec3d b) {
- m_start = a;
- m_direction = b - a;
-
- m_direction.normalize();
-}
diff --git a/src/ray.hpp b/src/ray.hpp
deleted file mode 100644
index 6341d44..0000000
--- a/src/ray.hpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef RAY_H
-#define RAY_H
-
-#include "vector.hpp"
-
-class Ray {
- public:
- Ray(Vec3d start, Vec3d direction, bool normalize);
- Ray(Vec3d a, Vec3d b);
-
- Vec3d m_start;
- Vec3d m_direction;
-};
-
-#endif
diff --git a/src/render.cpp b/src/render.cpp
deleted file mode 100644
index c278797..0000000
--- a/src/render.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-#include "render.hpp"
-#include "vector.hpp"
-#include "common.hpp"
-
-#include <cstdlib>
-#include <math.h>
-#include <iostream>
-
-#define FOV 1.74533
-
-// Uniform sampling
-#define SAMPLING_POWER 0
-
-const Vec3d up = Vec3d(0, 1, 0);
-
-void Random::seed(unsigned seed) {
- for (unsigned i = 0; i < seed; i++) {
- rand_r(&m_seed);
- }
-}
-
-double Random::operator()() {
- return (double)rand_r(&m_seed) / (double)RAND_MAX;
-}
-
-Sampler::Sampler(Random &src) : m_src(src) { }
-
-Vec3d Sampler::sample(const Vec3d &norm) {
- /*
- auto theta = asin(pow(1 - random(), (double)1 / (1 + SAMPLING_POWER)));
- auto phi = 2 * M_PI * random();
- */
-
- auto theta = 2.0 * M_PI * m_src();
- auto phi = acos(2.0 * m_src() - 1.0);
-
- auto sinphi = sin(phi);
-
- auto newvec = Vec3d(cos(theta) * sinphi, sin(theta) * sinphi, cos(phi));
-
- if (newvec.dot(norm) <= 0) {
- newvec = -newvec;
- }
-
- return newvec;
-}
-
-Renderer::Renderer(const Scene &scn, Vec3d eye, Vec3d target, unsigned width, unsigned height, unsigned maxhops) :
- m_sampler(m_random),
- m_scn(scn)
-{
- m_eye = eye;
- m_target = target;
- m_width = width;
- m_height = height;
- m_maxhops = maxhops;
-
- recalculate();
-}
-
-void Renderer::recalculate() {
- auto tmp = m_target - m_eye;
-
- // Orthogonal vector to E
- auto b = up.cross(tmp);
-
- b.normalize();
- tmp.normalize();
-
- auto v = tmp.cross(b);
-
- // Calculate size of viewplane
- double gx = tan( FOV / 2);
- double gy = gx * ((double) m_height / m_width);
-
- // Calculate scaling vectors
- m_qx = b * ((2 * gx) / (m_width - 1));
- m_qy = v * ((2 * gy) / (m_height - 1));
-
- // Calculate starting point
- m_blc = tmp - (b * gx) - (v * gy);
-}
-
-Ray Renderer::findray(double x, double y) const {
- auto dir = m_blc + (m_qx * x) + (m_qy * y);
- return Ray(m_eye, dir, true);
-}
-
-Color Renderer::render(unsigned x, unsigned y, unsigned samples) {
-
- Color sum(0, 0, 0);
-
- for (unsigned i = 0; i < samples; i++) {
- auto r = findray(x + m_random(), y + m_random());
- sum += pathtrace_sample(r, 0);
- }
-
- if (samples < 2) {
- return sum;
- } else {
- return Vec3d(sum) / (double)samples;
- }
-}
-
-Color Renderer::pathtrace_sample(const Ray &r, unsigned hop) {
- if (hop >= m_maxhops) {
- return Color(0, 0, 0);
- }
-
- double dist;
- auto res = cast_ray(r, 0, &dist);
-
- if (!res) {
- return Color(0, 0, 0);
- }
-
- auto col = res->m_mat.emits();
- if (res->m_mat.reflects()) {
- // Calculate endpoint
- auto end = r.m_start + r.m_direction * dist;
- auto norm = res->norm_at(end, r.m_direction);
-
- auto randdir = m_sampler.sample(norm);
- auto newray = Ray(end, randdir, true);
- auto incol = pathtrace_sample(newray, hop+1);
-
- col += res->m_mat.reflect(norm, r.m_direction, newray.m_direction, incol);
- }
-
- return col;
-}
-
-const Shape* Renderer::cast_ray(const Ray &r, double chk_dist, double *dist_ret) {
- const Shape *smallest = nullptr;
- double dist = 0;
-
- for (auto obj : m_scn.objs) {
- if (!obj) {
- continue;
- }
- auto d = obj->intersect(r, false);
- if (d > ZERO_APPROX) {
- if (chk_dist > 0 && d < chk_dist) {
- dist = d; smallest = obj;
- goto exit;
- }
- if (d < dist || smallest == nullptr) {
- dist = d; smallest = obj;
- }
- }
- }
-
- if (chk_dist > 0) {
- // If we reach this it means none of the
- // object where within distance.
- return nullptr;
- }
-
-exit:
-
- if (dist_ret) {
- *dist_ret = dist;
- }
-
- return smallest;
-}
diff --git a/src/render.hpp b/src/render.hpp
deleted file mode 100644
index 7557fce..0000000
--- a/src/render.hpp
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef RENDER_H
-#define RENDER_H
-
-#include "vector.hpp"
-#include "ray.hpp"
-#include "scene.hpp"
-
-class Random {
- public:
- void seed(unsigned seed);
- double operator()();
-
- private:
- unsigned m_seed;
-};
-
-// Samples a random direction in a hemisphere, cosine weighed
-// https://blog.thomaspoulet.fr/uniform-sampling-on-unit-hemisphere/
-class Sampler {
- public:
- Sampler(Random &src);
-
- Vec3d sample(const Vec3d &norm);
-
- private:
- Random &m_src;
-};
-
-class Renderer {
- public:
- Renderer(const Scene &scn, Vec3d eye, Vec3d target, unsigned width, unsigned height, unsigned maxhops);
-
- Color render(unsigned x, unsigned y, unsigned samples);
-
- unsigned m_width, m_height;
- Sampler m_sampler;
-
- private:
- void recalculate();
- Ray findray(double x, double y) const ;
-
- Color pathtrace_sample(const Ray &r, unsigned hop);
- // Will return first result less than chk_dist.
- // This is ignored if chk_dist is 0.
- // If dist is non-null the resulting distance is written here.
- const Shape* cast_ray(const Ray &r, double chk_dist, double *dist);
-
- const Scene &m_scn;
-
- Random m_random;
-
- // User options
- Vec3d m_eye, m_target;
- unsigned m_maxhops;
-
- // Calculated values
- Vec3d m_qx, m_qy, m_blc;
-
-};
-
-#endif
diff --git a/src/scene.cpp b/src/scene.cpp
deleted file mode 100644
index a8c0695..0000000
--- a/src/scene.cpp
+++ /dev/null
@@ -1,5 +0,0 @@
-#include "scene.hpp"
-
-void Scene::addShape(const Shape *obj) {
- objs.push_back(obj);
-}
diff --git a/src/scene.hpp b/src/scene.hpp
deleted file mode 100644
index f270409..0000000
--- a/src/scene.hpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef SCENE_H
-#define SCENE_H
-
-#include <vector>
-#include "object.hpp"
-
-class Scene {
- public:
- void addShape(const Shape *obj);
-
- std::vector<const Shape*> objs;
-
-};
-
-#endif
diff --git a/src/vector.cpp b/src/vector.cpp
deleted file mode 100644
index 51d8e2e..0000000
--- a/src/vector.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-#include "vector.hpp"
-
-#include <math.h>
-#include <stdexcept>
-
-Vec3d::Vec3d() {
- set(0, 0, 0);
-}
-
-Vec3d::Vec3d(double x, double y, double z) {
- set(x, y, z);
-}
-
-void Vec3d::set(double x, double y, double z) {
- m_x = x;
- m_y = y;
- m_z = z;
-}
-
-void Vec3d::normalize() {
- auto len = length();
- if (len == 0) {
- throw std::runtime_error("Normalizing zero vector");
- }
-
- m_x /= len;
- m_y /= len;
- m_z /= len;
-}
-
-double Vec3d::length() const {
- return sqrt(m_x * m_x + m_y * m_y + m_z * m_z);
-}
-
-double Vec3d::dot(const Vec3d &vec) const {
- return m_x * vec.m_x + m_y * vec.m_y + m_z * vec.m_z;
-}
-
-Vec3d Vec3d::cross(const Vec3d &vec) const {
- return Vec3d(
- m_y * vec.m_z - m_z * vec.m_y,
- m_z * vec.m_x - m_x * vec.m_z,
- m_x * vec.m_y - m_y * vec.m_x
- );
-}
-
-Vec3d Vec3d::operator+(const Vec3d &vec) const {
- return Vec3d(
- m_x + vec.m_x,
- m_y + vec.m_y,
- m_z + vec.m_z
- );
-}
-
-Vec3d& Vec3d::operator+=(const Vec3d &vec) {
- m_x += vec.m_x;
- m_y += vec.m_y;
- m_z += vec.m_z;
- return *this;
-}
-
-Vec3d Vec3d::operator-(const Vec3d &vec) const {
- return Vec3d(
- m_x - vec.m_x,
- m_y - vec.m_y,
- m_z - vec.m_z
- );
-}
-
-Vec3d Vec3d::operator-() const {
- return Vec3d(
- -m_x,
- -m_y,
- -m_z
- );
-}
-
-
-Vec3d Vec3d::operator*(double op) const {
- return Vec3d(
- m_x * op,
- m_y * op,
- m_z * op
- );
-}
-
-Vec3d Vec3d::operator*(const Vec3d &vec) const {
- return Vec3d(
- m_x * vec.m_x,
- m_y * vec.m_y,
- m_z * vec.m_z
- );
-}
-
-Vec3d Vec3d::operator/(double op) const {
- return Vec3d(
- m_x / op,
- m_y / op,
- m_z / op
- );
-}
-
-std::ostream& operator<<(std::ostream &out, const Vec3d &v){
- out << "[ " << v.m_x << ", " << v.m_y << ", " << v.m_z << " ]";
- return out;
-}
diff --git a/src/vector.hpp b/src/vector.hpp
deleted file mode 100644
index 20e8210..0000000
--- a/src/vector.hpp
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef VECTOR_H
-#define VECTOR_H
-
-#include <iostream>
-
-class Vec3d {
- public:
- Vec3d();
- Vec3d(double x, double y, double z);
-
- void set(double x, double y, double z);
- void normalize();
-
- double length() const;
- double dot(const Vec3d &vec) const;
-
- Vec3d cross(const Vec3d &vec) const;
-
- // Operators
- Vec3d operator+(const Vec3d &vec) const;
- Vec3d& operator+=(const Vec3d &vec);
- Vec3d operator-(const Vec3d &vec) const;
- Vec3d operator-() const;
- Vec3d operator*(double) const;
- Vec3d operator*(const Vec3d &vec) const;
- Vec3d operator/(double) const;
-
- friend std::ostream& operator<<(std::ostream& os, const Vec3d &v);
-
- double m_x, m_y, m_z;
-};
-
-#endif
diff --git a/test/main.cpp b/test/main.cpp
deleted file mode 100644
index 4ed06df..0000000
--- a/test/main.cpp
+++ /dev/null
@@ -1,2 +0,0 @@
-#define CATCH_CONFIG_MAIN
-#include <catch2/catch.hpp>
diff --git a/test/object.cpp b/test/object.cpp
deleted file mode 100644
index bbce055..0000000
--- a/test/object.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-#include <object.hpp>
-#include <ray.hpp>
-#include <common.hpp>
-#include <vector.hpp>
-
-#include <catch2/catch.hpp>
-#include <math.h>
-
-TEST_CASE("Sphere normal at", "[sphere]") {
- auto sph = Sphere(Vec3d(2, 3, 4), 2);
-
- auto norm = sph.norm_at(Vec3d(2, 3, 2), Vec3d());
- REQUIRE(norm.m_x == 0);
- REQUIRE(norm.m_y == 0);
- REQUIRE(norm.m_z == -1);
-}
-
-TEST_CASE("Sphere intersect", "[sphere]") {
- auto sph = Sphere(Vec3d(2, 3, 4), 2);
- auto ray = Ray(Vec3d(1, 0, 0), Vec3d(0, 1, 1.5), true);
-
- auto dist = sph.intersect(ray, false);
- REQUIRE(abs(dist - 3.28) < 0.01);
-}
-
-TEST_CASE("Plane intersect", "[plane]") {
- auto pln = Plane(Vec3d(3, 4, 2), Vec3d(-6, -3, -2));
- auto ray = Ray(Vec3d(0, 0, 0), Vec3d(-2, -1, 5));
-
- auto dist = pln.intersect(ray, false);
- REQUIRE(dist == -1);
-
- ray = Ray(Vec3d(-2, -2, 0), Vec3d(-2, -1, 5));
- dist = pln.intersect(ray, false);
- REQUIRE(abs(dist - 20.4) < 0.1);
-}
diff --git a/test/vector.cpp b/test/vector.cpp
deleted file mode 100644
index 61648c6..0000000
--- a/test/vector.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-#include <vector.hpp>
-#include <common.hpp>
-#include <catch2/catch.hpp>
-
-TEST_CASE( "Vector length", "[vector]" ) {
- auto vec = Vec3d(2, 4, 4);
- REQUIRE(vec.length() == 6);
- vec.set(0, 0, 0);
- REQUIRE(vec.length() == 0);
- vec.set(0, 3.5, 0);
- REQUIRE(vec.length() == 3.5);
-}
-
-TEST_CASE("Vector_normal", "[vector]") {
- auto vec = Vec3d(4, 5, 4545);
- REQUIRE(vec.length() != 1.0);
- vec.normalize();
- REQUIRE(vec.length() - 1.0 < ZERO_APPROX);
- vec.set(0, 0, 0);
- REQUIRE_THROWS(vec.normalize());
-}
-
-TEST_CASE("Vector dot", "[vector]") {
- auto a = Vec3d(4, 5, 6);
- auto b = Vec3d(1, 2, 3);
- REQUIRE(a.dot(b) == 32);
- a.set(0, 0, 0);
- REQUIRE(a.dot(b) == 0);
- a.set(0, 5, 0);
- REQUIRE(a.dot(b) == 10);
-}