diff --git a/Makefile b/Makefile index d34ab54..cb77726 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ TARGET = wtracer all: $(TARGET) run -run: +run: $(TARGET) time -f '%E elapsed' ./wtracer > image.ppm eog image.ppm diff --git a/material.cpp b/material.cpp index 8e8edce..8fad811 100644 --- a/material.cpp +++ b/material.cpp @@ -1,5 +1,7 @@ #include "material.h" +#include + 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(); @@ -15,3 +17,28 @@ bool Metal::scatter(const Ray& r_in, const hit_record& rec, Color& attenuation, attenuation = albedo; return (dot(scattered.direction(), rec.normal) > 0); } + +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; +} diff --git a/material.h b/material.h index 5b7c2d4..e223e1d 100644 --- a/material.h +++ b/material.h @@ -31,4 +31,14 @@ private: double fuzz; }; +double schlick(double cosine, double ref_idx); + +class Dielectric : public Material { +public: + Dielectric(double ri) : ref_idx(ri) {} + virtual bool scatter(const Ray& r_in, const hit_record& rec, Color& attenuation, Ray& scattered) const; +private: + double ref_idx; +}; + #endif // MATERIAL_H diff --git a/vec3.cpp b/vec3.cpp index 827f81d..48bc5ce 100644 --- a/vec3.cpp +++ b/vec3.cpp @@ -22,3 +22,10 @@ Vec3 random_in_hemisphere(const Vec3& normal) { else return -in_unit_sphere; } + +Vec3 refract(const Vec3& uv, const Vec3& n, double etai_over_etat) { + auto cos_theta = dot(-uv, n); + Vec3 r_out_parallel = etai_over_etat * (uv + cos_theta*n); + Vec3 r_out_perp = - std::sqrt(1.0 - r_out_parallel.length_squared()) * n; + return r_out_parallel + r_out_perp; +} diff --git a/vec3.h b/vec3.h index 624c9f5..2f9073a 100644 --- a/vec3.h +++ b/vec3.h @@ -122,4 +122,6 @@ Vec3 random_unit_vector(); Vec3 random_in_hemisphere(const Vec3& normal); +Vec3 refract(const Vec3& uv, const Vec3& n, double etai_over_etat); + #endif // VEC3_H diff --git a/wtracer.cpp b/wtracer.cpp index dadeca2..9752d4b 100644 --- a/wtracer.cpp +++ b/wtracer.cpp @@ -41,14 +41,14 @@ int main() { std::cout << "P3\n" << image_width << " " << image_height << "\n255\n"; Hittable_list world; - /*world.add(std::make_shared(Point3(0, 0, -1), 0.5)); - world.add(std::make_shared(Point3(0, -100.5, -1), 100));*/ - world.add(std::make_shared(Point3(0, 0, -1), 0.5, std::make_shared(Color(0.7, 0.3, 0.3)))); + world.add(std::make_shared(Point3(0, 0, -1), 0.5, std::make_shared(Color(0.1, 0.2, 0.5)))); world.add(std::make_shared(Point3(0, -100.5, -1), 100, std::make_shared(Color(0.8, 0.8, 0.0)))); - world.add(std::make_shared(Point3(1, 0, -1), 0.5, std::make_shared(Color(0.8, 0.6, 0.2), 0.3))); - world.add(std::make_shared(Point3(-1, 0, -1), 0.5, std::make_shared(Color(0.8, 0.8, 0.8), 1.0))); + world.add(std::make_shared(Point3(1, 0, -1), 0.5, std::make_shared(Color(0.8, 0.6, 0.2), 0.0))); + + + world.add(std::make_shared(Point3(-1, 0, -1), 0.5, std::make_shared(1.45))); Camera cam;