diff --git a/src/hittable.h b/src/hittable.h new file mode 100644 index 0000000..f8e050a --- /dev/null +++ b/src/hittable.h @@ -0,0 +1,23 @@ +#pragma once + +#include "ray.h" + +struct hit_record +{ + point3 p; + vec3 normal; + double t; + bool front_face; + + inline void set_face_normal(const ray& r, const vec3& outward_normal) + { + front_face = dot(r.direction(), outward_normal) < 0; + normal = front_face ? outward_normal : -outward_normal; + } +}; + +class hittable +{ + public: + virtual bool hit(const ray& r, double tMin, double tMax, hit_record& rec) const = 0; +}; diff --git a/src/sphere.h b/src/sphere.h new file mode 100644 index 0000000..cb3e521 --- /dev/null +++ b/src/sphere.h @@ -0,0 +1,59 @@ +#pragma once + +#include "hittable.h" +#include "vec3.h" + +class sphere : public hittable +{ + public: + sphere() {} + sphere(point3 centre, double r) : + centre_(centre), + radius_(r) {}; + + virtual bool hit(const ray& r, double t_min, double t_max, hit_record& rec) const; + + private: + point3 centre_; + double radius_; +}; + +bool sphere::hit(const ray& r, double t_min, double t_max, hit_record& rec) const +{ + vec3 oc = r.origin() - centre_; + auto a = r.direction().length_squared(); + auto half_b = dot(oc, r.direction()); + auto c = oc.length_squared() - radius_*radius_; + auto discriminant = half_b*half_b - a*c; + + if (discriminant > 0) + { + auto root = sqrt(discriminant); + + auto temp = (-half_b - root)/a; + if (temp < t_max && temp > t_min) + { + rec.t = temp; + rec.p = r.at(rec.t); + + vec3 outward_normal = (rec.p - centre_) / radius_; + rec.set_face_normal(r, outward_normal); + + return true; + } + + temp = (-half_b + root) / a; + if (temp < t_max && temp > t_min) + { + rec.t = temp; + rec.p = r.at(rec.t); + + vec3 outward_normal = (rec.p - centre_) / radius_; + rec.set_face_normal(r, outward_normal); + + return true; + } + } + + return false; +}