From 79869930cf6df0b8c53fc4bca0d36d98b8cde641 Mon Sep 17 00:00:00 2001 From: Moritz Gmeiner Date: Sat, 30 Dec 2023 14:01:45 +0100 Subject: [PATCH] added Materials Lambertian: scatter ray randomly with absorption Metal: reflect ray with absorption --- meson.build | 1 - src/colour.h | 16 ++++++++++++++++ src/main.cc | 21 ++++++++++++++++++--- src/material.h | 27 ++++++++++++++++++++++++--- src/rand.h | 2 +- src/renderer.h | 43 +++++++++++++++++++++---------------------- src/vec3.h | 20 ++++++++++++-------- 7 files changed, 92 insertions(+), 38 deletions(-) diff --git a/meson.build b/meson.build index 350c2b6..1748221 100644 --- a/meson.build +++ b/meson.build @@ -27,7 +27,6 @@ if get_option('native') endif - rand_proj = subproject('rand', default_options : ['warning_level=0', 'werror=false']) rand_dep = rand_proj.get_variable('rand_dep') diff --git a/src/colour.h b/src/colour.h index c34d3f8..77ecfe7 100644 --- a/src/colour.h +++ b/src/colour.h @@ -44,6 +44,14 @@ class Colour { return *this; } + constexpr Colour& operator*=(const Colour& c) { + r_ *= c.r(); + g_ *= c.g(); + b_ *= c.b(); + + return *this; + } + constexpr Colour to_gamma2() const { return Colour{std::sqrt(r()), std::sqrt(g()), std::sqrt(b())}; } @@ -79,6 +87,14 @@ constexpr Colour operator+(Colour c1, Colour c2) { return out; } +constexpr Colour operator*(Colour c1, Colour c2) { + Colour out{c1}; + + out *= c2; + + return out; +} + inline std::ostream& operator<<(std::ostream& os, Colour c) { double r = c.r(); double g = c.g(); diff --git a/src/main.cc b/src/main.cc index 3ed7bcf..3fac189 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,5 +1,6 @@ #include #include +#include #include "camera.h" #include "colour.h" @@ -16,10 +17,24 @@ int main(int /* argc */, char* /* argv */[]) { RenderObjectList world; - auto lamb = std::make_shared(Colour{0.1, 0.4, 0.8}); + /* auto lamb = std::make_shared(Colour{0.7, 0.0, 0.5}); + auto metal = std::make_shared(Colour{0.3, 0.3, 0.3}); - world.Add(std::make_unique(Vec3{0, -100.5, -1}, 100, lamb)); - world.Add(std::make_unique(-Vec3::e_z, 0.5, lamb)); + auto ground = std::make_unique(Point3{0, -100.5, -1}, 100, metal); + auto sphere = std::make_unique(-Vec3::e_z, 0.5, lamb); + + world.Add(std::move(ground)); + world.Add(std::move(sphere)); */ + + auto material_ground = std::make_shared(Colour(0.8, 0.8, 0.0)); + auto material_center = std::make_shared(Colour(0.7, 0.3, 0.3)); + auto material_left = std::make_shared(Colour(0.8, 0.8, 0.8), 0.05); + auto material_right = std::make_shared(Colour(0.8, 0.5, 0.4), 0.5); + + world.Add(std::make_unique(Point3(0.0, -100.5, -1.0), 100.0, material_ground)); + world.Add(std::make_unique(Point3(0.0, 0.0, -1.0), 0.5, material_center)); + world.Add(std::make_unique(Point3(-1.0, 0.0, -1.0), 0.5, material_left)); + world.Add(std::make_unique(Point3(1.0, 0.0, -1.0), 0.5, material_right)); // camera diff --git a/src/material.h b/src/material.h index bbedc27..4fd22f3 100644 --- a/src/material.h +++ b/src/material.h @@ -1,11 +1,13 @@ #pragma once +#include #include #include #include "colour.h" #include "rand.h" #include "ray.h" +#include "raytracer.h" #include "renderobject.h" class Material { @@ -37,10 +39,9 @@ class Lambertian : public Material { const HitRecord& hit_record) const override { auto scatter_dir = hit_record.normal + rand().GenOnUnitSphere(); - // TODO: enable - /* if (scatter_dir.almost_zero()) { + if (scatter_dir.almost_zero()) { scatter_dir = hit_record.normal; - } */ + } Ray scattered{hit_record.p, scatter_dir}; @@ -50,3 +51,23 @@ class Lambertian : public Material { private: Colour albedo_; }; + +class Metal : public Material { + public: + constexpr Metal(Colour albedo, f64 fuzz) : albedo_{albedo}, fuzz_{fuzz} { assert(fuzz <= 1); } + + std::optional> Scatter(const Ray& in, + const HitRecord& hit_record) const override { + auto reflect_dir = in.direction().reflect(hit_record.normal).normed(); + + reflect_dir += fuzz_ * rand().GenOnUnitSphere(); + + Ray scattered{hit_record.p, reflect_dir}; + + return std::make_tuple(albedo_, scattered); + } + + private: + Colour albedo_; + f64 fuzz_; +}; diff --git a/src/rand.h b/src/rand.h index fec80ed..13b68da 100644 --- a/src/rand.h +++ b/src/rand.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include "raytracer.h" #include "vec3.h" diff --git a/src/renderer.h b/src/renderer.h index 4aab1ba..0843811 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -76,7 +76,7 @@ class Renderer { pixel_centre += random_shift; - auto ray_direction = pixel_centre - camera_.centre(); + auto ray_direction = (pixel_centre - camera_.centre()).normed(); return Ray{camera_.centre(), ray_direction}; } @@ -84,33 +84,32 @@ class Renderer { constexpr Colour Cast(const Ray& ray, const RenderObject& world, u32 bounces) { auto hit_record = world.hit(ray, Interval{0.001, kInf}); - if (hit_record.has_value()) { - if (!hit_record->front_face || bounces == 0) { - return Colour::kBlack; - } + // background + if (!hit_record.has_value()) { + auto unit_dir = ray.direction().normed(); - /* Vec3 normal = hit_record->normal; + f64 a = 0.5 * (unit_dir.y() + 1.0); - Vec3 new_origin = hit_record->p; - - // Vec3 new_direction = rand_.GenOnHemisphere(normal); - Vec3 new_direction = normal + rand_.GenOnUnitSphere(); - - Ray new_ray{new_origin, new_direction}; */ - - auto res = hit_record->mat->Scatter(ray, hit_record.value()); - - auto [albedo, out_ray] = res.value(); - - assert(bounces > 0); - return 0.5 * Cast(out_ray, world, bounces - 1); + return (1.0 - a) * Colour{1.0, 1.0, 1.0} + a * Colour{0.5, 0.7, 1.0}; } - auto unit_dir = ray.direction().normed(); + // hit - f64 a = 0.5 * (unit_dir.y() + 1.0); + if (!hit_record->front_face || bounces == 0) { + return Colour::kBlack; + } - return (1.0 - a) * Colour{1.0, 1.0, 1.0} + a * Colour{0.5, 0.7, 1.0}; + auto res = hit_record->mat->Scatter(ray, hit_record.value()); + + if (!res.has_value()) { + // absorped + return Colour::kBlack; + } + + auto [albedo, out_ray] = res.value(); + + assert(bounces > 0); + return albedo * Cast(out_ray, world, bounces - 1); } Camera camera_; diff --git a/src/vec3.h b/src/vec3.h index 5f7520a..35b304a 100644 --- a/src/vec3.h +++ b/src/vec3.h @@ -65,15 +65,13 @@ class Vec3 { return std::fabs(x()) < eps && std::fabs(y()) < eps && std::fabs(z()) < eps; } - constexpr f64 squared() const { return x() * x() + y() * y() + z() * z(); } + constexpr f64 squared() const; - constexpr f64 norm() const { return std::sqrt(squared()); } + constexpr f64 norm() const; - constexpr Vec3 normed() const { - auto r = *this; - r /= norm(); - return r; - } + constexpr Vec3 normed() const; + + constexpr Vec3 reflect(Vec3 normal) const; private: std::array xyz_; @@ -119,4 +117,10 @@ constexpr Vec3 cross(const Vec3& u, const Vec3& v) { u.x() * v.y() - u.y() - v.x()}; } -constexpr Vec3 normed(const Vec3& v) { return v.normed(); } +constexpr f64 Vec3::squared() const { return dot(*this, *this); } + +constexpr f64 Vec3::norm() const { return std::sqrt(squared()); } + +constexpr Vec3 Vec3::normed() const { return *this / norm(); } + +constexpr Vec3 Vec3::reflect(Vec3 normal) const { return *this - 2 * dot(*this, normal) * normal; }