aboutsummaryrefslogtreecommitdiff
path: root/src/render.cpp
diff options
context:
space:
mode:
authorJulian T <julian@jtle.dk>2020-08-06 19:21:49 +0200
committerJulian T <julian@jtle.dk>2020-08-06 19:22:37 +0200
commit4348cc9581bfea05359485c5d2d074132d0271da (patch)
tree0c6d92a90ac4cf9acd326f632dcdc962ddca013a /src/render.cpp
parent893176a0b18a2281abe09def716ccc3db5583c3f (diff)
Renders scenes with a single hardcoded light and green objects
Diffstat (limited to 'src/render.cpp')
-rw-r--r--src/render.cpp124
1 files changed, 124 insertions, 0 deletions
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 <math.h>
+#include <iostream>
+
+#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;
+}