#ifndef MATERIALH #define MATERIALH //================================================================================================== // Written in 2016 by Peter Shirley // // To the extent possible under law, the author(s) have dedicated all copyright and related and // neighboring rights to this software to the public domain worldwide. This software is distributed // without any warranty. // // You should have received a copy (see file COPYING.txt) of the CC0 Public Domain Dedication along // with this software. If not, see . //================================================================================================== #include "hitable.h" #include "random.h" #include "ray.h" struct hit_record; __host__ __device__ float schlick(float cosine, float ref_idx) { float r0 = (1.0f-ref_idx) / (1.0f+ref_idx); r0 = r0*r0; return r0 + (1.0f-r0)*pow((1.0f - cosine),5.0f); } __host__ __device__ bool refract(const vec3& v, const vec3& n, float ni_over_nt, vec3& refracted) { vec3 uv = unit_vector(v); float dt = dot(uv, n); float discriminant = 1.0f - ni_over_nt*ni_over_nt*(1-dt*dt); if (discriminant > 0) { refracted = ni_over_nt*(uv - n*dt) - n*sqrt(discriminant); return true; } else return false; } __host__ __device__ vec3 reflect(const vec3& v, const vec3& n) { return v - 2.0f*dot(v,n)*n; } __host__ __device__ vec3 random_in_unit_sphere(RandState *randState) { vec3 p; do { p = 2.0f*vec3(random_double(randState),random_double(randState),random_double(randState)) - vec3(1,1,1); } while (p.squared_length() >= 1.0f); return p; } class material { public: __host__ __device__ virtual bool scatter(const ray& r_in, const hit_record& rec, vec3& attenuation, ray& scattered, RandState *randState) const = 0; __host__ __device__ virtual ~material() = default; }; class lambertian : public material { public: __host__ __device__ lambertian(const vec3& a) : albedo(a) {} __host__ __device__ virtual bool scatter([[maybe_unused]] const ray& r_in, const hit_record& rec, vec3& attenuation, ray& scattered, RandState *randState) const { vec3 target = rec.p + rec.normal + random_in_unit_sphere(randState); scattered = ray(rec.p, target-rec.p); attenuation = albedo; return true; } vec3 albedo; }; class metal : public material { public: __host__ __device__ metal(const vec3& a, float f) : albedo(a) { if (f < 1.0f) fuzz = f; else fuzz = 1.0f; } __host__ __device__ virtual bool scatter(const ray& r_in, const hit_record& rec, vec3& attenuation, ray& scattered, RandState *randState) const { vec3 reflected = reflect(unit_vector(r_in.direction()), rec.normal); scattered = ray(rec.p, reflected + fuzz*random_in_unit_sphere(randState)); attenuation = albedo; return (dot(scattered.direction(), rec.normal) > 0.0f); } vec3 albedo; float fuzz; }; class dielectric : public material { public: __host__ __device__ dielectric(float ri) : ref_idx(ri) {} __host__ __device__ virtual bool scatter(const ray& r_in, const hit_record& rec, vec3& attenuation, ray& scattered, RandState *randState) const { vec3 outward_normal; vec3 reflected = reflect(r_in.direction(), rec.normal); float ni_over_nt; attenuation = vec3(1.0f, 1.0f, 1.0f); vec3 refracted; float reflect_prob; float cosine; if (dot(r_in.direction(), rec.normal) > 0.0f) { outward_normal = -rec.normal; ni_over_nt = ref_idx; // cosine = ref_idx * dot(r_in.direction(), rec.normal) / r_in.direction().length(); cosine = dot(r_in.direction(), rec.normal) / r_in.direction().length(); cosine = sqrt(1.0f - ref_idx*ref_idx*(1-cosine*cosine)); } else { outward_normal = rec.normal; ni_over_nt = 1.0f / ref_idx; cosine = -dot(r_in.direction(), rec.normal) / r_in.direction().length(); } if (refract(r_in.direction(), outward_normal, ni_over_nt, refracted)) reflect_prob = schlick(cosine, ref_idx); else reflect_prob = 1.0f; if (random_double(randState) < reflect_prob) scattered = ray(rec.p, reflected); else scattered = ray(rec.p, refracted); return true; } float ref_idx; }; #endif