From 4348cc9581bfea05359485c5d2d074132d0271da Mon Sep 17 00:00:00 2001 From: Julian T Date: Thu, 6 Aug 2020 19:21:49 +0200 Subject: Renders scenes with a single hardcoded light and green objects --- src/object.cpp | 5 +-- src/object.hpp | 8 ++-- src/render.cpp | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/render.hpp | 50 +++++++++++++++++++++++ src/scene.cpp | 4 +- src/scene.hpp | 4 +- src/vector.cpp | 27 ++++++++++++- src/vector.hpp | 2 + 8 files changed, 210 insertions(+), 14 deletions(-) create mode 100644 src/render.cpp create mode 100644 src/render.hpp (limited to 'src') diff --git a/src/object.cpp b/src/object.cpp index e88ae13..179785a 100644 --- a/src/object.cpp +++ b/src/object.cpp @@ -1,6 +1,7 @@ #include "object.hpp" #include +#include #include "common.hpp" Sphere::Sphere(Vec3d center, double radius) { @@ -15,10 +16,6 @@ Plane::Plane(Vec3d start, Vec3d norm) { m_norm.normalize(); } -void Object::setMaterial(std::shared_ptr m) { - m_mat = m; -} - Vec3d Sphere::norm_at(const Vec3d &point, const Vec3d&) const { auto res = point - m_center; res.normalize(); diff --git a/src/object.hpp b/src/object.hpp index 3194dac..ac5122f 100644 --- a/src/object.hpp +++ b/src/object.hpp @@ -8,17 +8,15 @@ class Material { }; -class Object { +class Shape { public: void setMaterial(std::shared_ptr m); - std::shared_ptr m_mat; - virtual Vec3d norm_at(const Vec3d &point, const Vec3d &indir) const = 0; virtual double intersect(const Ray &ray, bool skip_dist) const = 0; }; -class Sphere : Object { +class Sphere : public Shape { public: Sphere(Vec3d center, double radius); Vec3d norm_at(const Vec3d &point, const Vec3d &indir) const; @@ -29,7 +27,7 @@ class Sphere : Object { double m_radius; }; -class Plane : Object { +class Plane : public Shape { public: Plane(Vec3d start, Vec3d norm); Vec3d norm_at(const Vec3d &point, const Vec3d &indir) const; diff --git a/src/render.cpp b/src/render.cpp new file mode 100644 index 0000000..5601863 --- /dev/null +++ b/src/render.cpp @@ -0,0 +1,124 @@ +#include "render.hpp" +#include "vector.hpp" +#include "common.hpp" + +#include +#include + +#define FOV 1.74533 + +const Vec3d up = Vec3d(0, 1, 0); + +void Color::clamp() { + if (m_x > 1) { m_x = 1; } + if (m_y > 1) { m_y = 1; } + if (m_z > 1) { m_z = 1; } +} + +Renderer::Renderer(const Scene &scn, Vec3d eye, Vec3d target, unsigned width, unsigned height) : + m_scn(scn) +{ + m_eye = eye; + m_target = target; + m_width = width; + m_height = height; + + 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) { + auto r = findray(x, y); + return pathtrace_sample(r, 0); +} + +Color Renderer::pathtrace_sample(const Ray &r, unsigned hop) { + double dist; + auto res = cast_ray(r, 0, &dist); + + if (!res) { + return Color(0, 0, 0); + } + + // Calculate endpoint + auto end = r.m_start + r.m_direction * dist; + + auto norm = res->norm_at(end, r.m_direction); + + // Simulate single light + auto l = Vec3d(0, 7, 0); + + auto tolight = l - end; + auto distance = tolight.length(); + tolight.normalize(); + auto lightray = Ray(end, tolight, false); + + if (cast_ray(lightray, distance, nullptr)) { + return Color(0, 0, 0); + } + + auto green = Color(0, 1, 0); + return Color(green * norm.dot(tolight)); +} + +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 new file mode 100644 index 0000000..3fd84b1 --- /dev/null +++ b/src/render.hpp @@ -0,0 +1,50 @@ +#ifndef RENDER_H +#define RENDER_H + +#include "vector.hpp" +#include "ray.hpp" +#include "scene.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; } + + void clamp(); + +}; + +class Renderer { + public: + Renderer(const Scene &scn, Vec3d eye, Vec3d target, unsigned width, unsigned height); + + Color render(unsigned x, unsigned y); + + unsigned m_width, m_height; + + 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; + + // User options + Vec3d m_eye, m_target; + + // Calculated values + Vec3d m_qx, m_qy, m_blc; + +}; + +#endif diff --git a/src/scene.cpp b/src/scene.cpp index d866fe4..a8c0695 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -1,5 +1,5 @@ #include "scene.hpp" -void Scene::addObject(Object &obj) { - objs.push_back(&obj); +void Scene::addShape(const Shape *obj) { + objs.push_back(obj); } diff --git a/src/scene.hpp b/src/scene.hpp index a06ccb4..f270409 100644 --- a/src/scene.hpp +++ b/src/scene.hpp @@ -6,9 +6,9 @@ class Scene { public: - void addObject(Object &obj); + void addShape(const Shape *obj); - std::vector objs; + std::vector objs; }; diff --git a/src/vector.cpp b/src/vector.cpp index 070f956..1e4f5a1 100644 --- a/src/vector.cpp +++ b/src/vector.cpp @@ -1,6 +1,7 @@ #include "vector.hpp" #include +#include Vec3d::Vec3d() { set(0, 0, 0); @@ -19,7 +20,7 @@ void Vec3d::set(double x, double y, double z) { void Vec3d::normalize() { auto len = length(); if (len == 0) { - throw "Normalizing zero vector"; + throw std::runtime_error("Normalizing zero vector"); } m_x /= len; @@ -35,6 +36,22 @@ 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) const { return Vec3d( m_x - vec.m_x, @@ -51,3 +68,11 @@ Vec3d Vec3d::operator-() const { ); } + +Vec3d Vec3d::operator*(double op) const { + return Vec3d( + m_x * op, + m_y * op, + m_z * op + ); +} diff --git a/src/vector.hpp b/src/vector.hpp index 76eb883..05de25c 100644 --- a/src/vector.hpp +++ b/src/vector.hpp @@ -15,8 +15,10 @@ class Vec3d { Vec3d cross(const Vec3d &vec) const; // Operators + Vec3d operator+(const Vec3d &vec) const; Vec3d operator-(const Vec3d &vec) const; Vec3d operator-() const; + Vec3d operator*(double) const; double m_x, m_y, m_z; }; -- cgit v1.2.3