added Materials

Lambertian: scatter ray randomly with absorption

Metal: reflect ray with absorption
This commit is contained in:
Moritz Gmeiner 2023-12-30 14:01:45 +01:00
commit 79869930cf
7 changed files with 92 additions and 38 deletions

View file

@ -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')

View file

@ -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();

View file

@ -1,5 +1,6 @@
#include <iostream>
#include <memory>
#include <utility>
#include "camera.h"
#include "colour.h"
@ -16,10 +17,24 @@ int main(int /* argc */, char* /* argv */[]) {
RenderObjectList world;
auto lamb = std::make_shared<Lambertian>(Colour{0.1, 0.4, 0.8});
/* auto lamb = std::make_shared<Lambertian>(Colour{0.7, 0.0, 0.5});
auto metal = std::make_shared<Metal>(Colour{0.3, 0.3, 0.3});
world.Add(std::make_unique<Sphere>(Vec3{0, -100.5, -1}, 100, lamb));
world.Add(std::make_unique<Sphere>(-Vec3::e_z, 0.5, lamb));
auto ground = std::make_unique<Sphere>(Point3{0, -100.5, -1}, 100, metal);
auto sphere = std::make_unique<Sphere>(-Vec3::e_z, 0.5, lamb);
world.Add(std::move(ground));
world.Add(std::move(sphere)); */
auto material_ground = std::make_shared<Lambertian>(Colour(0.8, 0.8, 0.0));
auto material_center = std::make_shared<Lambertian>(Colour(0.7, 0.3, 0.3));
auto material_left = std::make_shared<Metal>(Colour(0.8, 0.8, 0.8), 0.05);
auto material_right = std::make_shared<Metal>(Colour(0.8, 0.5, 0.4), 0.5);
world.Add(std::make_unique<Sphere>(Point3(0.0, -100.5, -1.0), 100.0, material_ground));
world.Add(std::make_unique<Sphere>(Point3(0.0, 0.0, -1.0), 0.5, material_center));
world.Add(std::make_unique<Sphere>(Point3(-1.0, 0.0, -1.0), 0.5, material_left));
world.Add(std::make_unique<Sphere>(Point3(1.0, 0.0, -1.0), 0.5, material_right));
// camera

View file

@ -1,11 +1,13 @@
#pragma once
#include <cassert>
#include <optional>
#include <tuple>
#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<std::tuple<Colour, Ray>> 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_;
};

View file

@ -1,6 +1,6 @@
#pragma once
#include <philox.h>
#include <philox.hh>
#include "raytracer.h"
#include "vec3.h"

View file

@ -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_;

View file

@ -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<f64, 3> 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; }