toytracer/material.cpp

45 lines
1.7 KiB
C++
Raw Normal View History

#include "material.h"
2020-06-06 22:03:25 +00:00
#include <cmath>
bool Lambertian::scatter(const Ray& r_in, const hit_record& rec, Color& attenuation, Ray& scattered) const {
//Vec3 scatter_direction = rec.normal + random_in_unit_sphere();
Vec3 scatter_direction = rec.normal + random_unit_vector();
//Vec3 scatter_direction = random_in_hemisphere(rec.normal);
scattered = Ray(rec.p, scatter_direction);
attenuation = albedo;
return true;
}
bool Metal::scatter(const Ray& r_in, const hit_record& rec, Color& attenuation, Ray& scattered) const {
Vec3 reflected = reflect(unit_vector(r_in.direction()), rec.normal);
2020-06-06 21:28:33 +00:00
scattered = Ray(rec.p, reflected + fuzz * random_in_unit_sphere());
attenuation = albedo;
return (dot(scattered.direction(), rec.normal) > 0);
}
2020-06-06 22:03:25 +00:00
double schlick(double cosine, double ref_idx) {
auto r0 = (1 - ref_idx) / (1 + ref_idx);
r0 = r0 * r0;
return r0 + (1 - r0) * std::pow((1 - cosine), 5);
}
bool Dielectric::scatter(const Ray& r_in, const hit_record& rec, Color& attenuation, Ray& scattered) const {
attenuation = Color(1.0, 1.0, 1.0);
double etai_over_etat = rec.front_face ? 1.0 / ref_idx : ref_idx;
Vec3 unit_direction = unit_vector(r_in.direction());
double cos_theta = std::fmin(dot(-unit_direction, rec.normal), 1.0);
double sin_theta = std::sqrt(1.0 - cos_theta*cos_theta);
double reflect_prob = schlick(cos_theta, etai_over_etat);
if (etai_over_etat * sin_theta > 1.0 || random_double() < reflect_prob) {
Vec3 reflected = reflect(unit_direction, rec.normal);
scattered = Ray(rec.p, reflected);
return true;
}
Vec3 refracted = refract(unit_direction, rec.normal, etai_over_etat);
scattered = Ray(rec.p, refracted);
return true;
}