mirror of
https://github.com/MorizzG/ray-tracer.git
synced 2025-12-06 04:22:42 +00:00
added Materials
Lambertian: scatter ray randomly with absorption Metal: reflect ray with absorption
This commit is contained in:
parent
aaae4a8196
commit
79869930cf
7 changed files with 92 additions and 38 deletions
|
|
@ -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')
|
||||
|
||||
|
|
|
|||
16
src/colour.h
16
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();
|
||||
|
|
|
|||
21
src/main.cc
21
src/main.cc
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <philox.h>
|
||||
#include <philox.hh>
|
||||
|
||||
#include "raytracer.h"
|
||||
#include "vec3.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_;
|
||||
|
|
|
|||
20
src/vec3.h
20
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<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; }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue