diff --git a/src/material.h b/src/material.h index cae78f3..82cd311 100644 --- a/src/material.h +++ b/src/material.h @@ -29,14 +29,55 @@ class lambertian : public material{ class metal : public material{ public: - metal(const color& a) : albedo(a){} + metal(const color& a, double f) : albedo(a), fuzz(f < 1 ? f : 1){} virtual bool scatter(const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered)const override { vec3 reflected = reflect(unit_vector(r_in.direction()), rec.normal); - scattered = ray(rec.p, reflected); + scattered = ray(rec.p, reflected + fuzz * random_in_unit_sphere()); attenuation =albedo; return (dot(scattered.direction(), rec.normal) > 0); } public: color albedo; + double fuzz; +}; + +class dielectric : public material{ + public: + dielectric(double index_of_refraction) : ir(index_of_refraction){} + + virtual bool scatter (const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered) const override{ + attenuation = color(1.0,1.0,1.0); + double refraction_ratio = rec.front_face ? (1.0/ir) : ir; + + vec3 unit_direction = unit_vector(r_in.direction()); + + double cos_theta = fmin(dot(-unit_direction, rec.normal), 1.0); + double sin_theta = sqrt(1.0 - cos_theta * cos_theta); + bool cannot_refract = refraction_ratio * sin_theta > 1.0; + vec3 direction; + + if(cannot_refract || reflectance(cos_theta, refraction_ratio) > random_double()){ + // Must reflect + direction = reflect(unit_direction, rec.normal); + } else { + // can refract + direction = refract(unit_direction, rec.normal, refraction_ratio); + } + + scattered = ray(rec.p, direction); + + return true; + } + + public: + double ir; + + private: + static double reflectance(double cosine, double ref_idx){ + // use Schlik's approximation + auto r0 = (1-ref_idx) / (1+ref_idx); + r0 = r0*r0; + return r0 + (1-r0)*pow((1-cosine), 5); + } }; \ No newline at end of file diff --git a/src/program.cpp b/src/program.cpp index b705823..ce04180 100644 --- a/src/program.cpp +++ b/src/program.cpp @@ -41,14 +41,15 @@ int main () hittable_list world; auto material_ground = make_shared(color(0.8,0.8, 0.0)); - auto material_center = make_shared(color(0.7,0.3,0.3)); - auto material_left = make_shared (color(0.8,0.8,0.8)); - auto material_right = make_shared(color(0.8,0.6,0.2)); + auto material_center = make_shared(color(0.1, 0.2, 0.5)); + auto material_left = make_shared (1.5); + auto material_right = make_shared(color(0.8,0.6,0.2), 0.0); world.add(make_shared(point3(0,-100.5,-1), 100.0, material_ground)); world.add(make_shared(point3(0,0,-1), 0.5, material_center)); world.add(make_shared(point3(-1.0, 0.0, -1), 0.5, material_left)); + world.add(make_shared(point3(-1.0, 0.0, -1), -0.4, material_left)); world.add(make_shared(point3(1.0, 0.0, -1), 0.5, material_right)); diff --git a/src/vector3.h b/src/vector3.h index 42d9038..1850bec 100644 --- a/src/vector3.h +++ b/src/vector3.h @@ -130,4 +130,11 @@ vec3 random_in_hemisphere (const vec3& normal){ vec3 reflect (const vec3& v, const vec3& n){ return v -2 *dot(v,n) *n; +} + +vec3 refract(const vec3& uv, const vec3& n, double etai_over_etat){ + auto cos_theta = fmin(dot(-uv,n), 1.0); + vec3 r_out_perp = etai_over_etat * (uv + cos_theta*n); + vec3 r_out_parallel = -sqrt(fabs(1.0 - r_out_perp.length_squared())) * n; + return r_out_perp + r_out_parallel; } \ No newline at end of file