2020-06-07 00:59:30 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "hittable.h"
|
2023-02-20 02:19:28 +01:00
|
|
|
#include "hit_record.h"
|
2020-06-07 00:59:30 +02:00
|
|
|
|
|
|
|
class material
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
virtual bool scatter(
|
|
|
|
const ray& r_in,
|
|
|
|
const hit_record& rec,
|
|
|
|
colour& attenuation,
|
|
|
|
ray& scattered) const = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
class lambertian : public material
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
lambertian(const colour& a) : albedo_(a) {}
|
|
|
|
|
|
|
|
virtual bool scatter(
|
|
|
|
const ray& r_in,
|
|
|
|
const hit_record& rec,
|
|
|
|
colour& attenuation,
|
|
|
|
ray& scattered) const
|
|
|
|
{
|
2023-02-19 20:55:42 +01:00
|
|
|
vec3 scatter_direction = rec.normal + vec3::random_unit_vector();
|
2020-06-07 00:59:30 +02:00
|
|
|
scattered = ray(rec.p, scatter_direction);
|
|
|
|
attenuation = albedo_;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
colour albedo_;
|
|
|
|
};
|
|
|
|
|
|
|
|
class metal : public material
|
|
|
|
{
|
|
|
|
public:
|
2020-06-07 02:13:39 +02:00
|
|
|
metal(const colour& a, double f) :
|
|
|
|
albedo_(a),
|
|
|
|
fuzz_(f < 1 ? f : 1) {}
|
2020-06-07 00:59:30 +02:00
|
|
|
|
|
|
|
virtual bool scatter(
|
|
|
|
const ray& r_in,
|
|
|
|
const hit_record& rec,
|
|
|
|
colour& attenuation,
|
|
|
|
ray& scattered) const
|
|
|
|
{
|
2023-02-19 22:30:48 +01:00
|
|
|
vec3 reflected = reflect(normalize(r_in.direction()), rec.normal);
|
2023-02-19 20:55:42 +01:00
|
|
|
scattered = ray(rec.p, reflected + fuzz_ * vec3::random_in_unit_sphere());
|
2020-06-07 00:59:30 +02:00
|
|
|
attenuation = albedo_;
|
|
|
|
return dot(scattered.direction(), rec.normal) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
colour albedo_;
|
2020-06-07 02:13:39 +02:00
|
|
|
double fuzz_;
|
|
|
|
};
|
|
|
|
|
|
|
|
class dielectric : public material
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
dielectric(double ri) : refraction_index_(ri) {}
|
|
|
|
|
|
|
|
virtual bool scatter(
|
|
|
|
const ray& r_in,
|
|
|
|
const hit_record& rec,
|
|
|
|
colour& attenuation,
|
|
|
|
ray& scattered) const
|
|
|
|
{
|
|
|
|
attenuation = colour(1.0,1.0,1.0);
|
|
|
|
double etai_over_etat = rec.front_face ? (1.0 / refraction_index_) : refraction_index_;
|
|
|
|
|
2023-02-19 22:30:48 +01:00
|
|
|
vec3 unit_direction = normalize(r_in.direction());
|
2020-06-07 02:13:39 +02:00
|
|
|
|
|
|
|
double cos_theta = fmin(dot(-unit_direction, rec.normal), 1.0);
|
|
|
|
double sin_theta = sqrt(1.0 - cos_theta*cos_theta);
|
|
|
|
if (etai_over_etat * sin_theta > 1.0)
|
|
|
|
{
|
2023-02-19 22:30:48 +01:00
|
|
|
vec3 reflected = reflect(unit_direction, rec.normal);
|
2020-06-07 02:13:39 +02:00
|
|
|
scattered = ray(rec.p, reflected);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
double reflect_prob = schlick(cos_theta, etai_over_etat);
|
2023-02-19 20:55:42 +01:00
|
|
|
if (math::random_double() < reflect_prob)
|
2020-06-07 02:13:39 +02:00
|
|
|
{
|
2023-02-19 22:30:48 +01:00
|
|
|
vec3 reflected = reflect(unit_direction, rec.normal);
|
2020-06-07 02:13:39 +02:00
|
|
|
scattered = ray(rec.p, reflected);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-02-19 22:30:48 +01:00
|
|
|
vec3 refracted = refract(unit_direction, rec.normal, etai_over_etat);
|
2020-06-07 02:13:39 +02:00
|
|
|
scattered = ray(rec.p, refracted);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
double refraction_index_;
|
2023-02-20 02:19:28 +01:00
|
|
|
|
|
|
|
double schlick(double cosine, double refraction_index) const
|
|
|
|
{
|
|
|
|
auto r0 = (1-refraction_index) / (1+refraction_index);
|
|
|
|
r0 = r0*r0;
|
|
|
|
return r0 + (1-r0)*pow(1-cosine, 5);
|
|
|
|
}
|
2020-06-07 00:59:30 +02:00
|
|
|
};
|