diff --git a/Makefile b/Makefile index c766cc2..ce6458e 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ CXX = g++ CXXFLAGS = -Wall -Wextra -O2 -std=c++14 -DEPS = vec3.h color.h ray.h hittable.h sphere.h +DEPS = util.h vec3.h color.h ray.h hittable.h hittable_list.h sphere.h OBJ = wtracer.o TARGET = wtracer diff --git a/hittable.h b/hittable.h index 9632db0..6c757e2 100644 --- a/hittable.h +++ b/hittable.h @@ -7,11 +7,17 @@ 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(cosnt Ray &r, double t_min, double t_max, hit_record &rec) const = 0; -} + virtual bool hit(const Ray &r, double tmin, double tmax, hit_record &rec) const = 0; +}; #endif // HITTABLE_H diff --git a/hittable_list.h b/hittable_list.h new file mode 100644 index 0000000..12e4c4f --- /dev/null +++ b/hittable_list.h @@ -0,0 +1,39 @@ +#ifndef HITTABLE_LIST_H +#define HITTABLE_LIST_H + +#include +#include + +#include "hittable.h" + +class Hittable_list : public Hittable { +public: + Hittable_list() {} + Hittable_list(std::shared_ptr object) { add(object); } + + void clear() { objects.clear(); } + void add(std::shared_ptr object) { objects.push_back(object); } + + virtual bool hit(const Ray &r, double tmin, double tmax, hit_record &rec) const; + +private: + std::vector> objects; +}; + +bool Hittable_list::hit(const Ray &r, double tmin, double tmax, hit_record &rec) const { + hit_record temp_rec; + bool hit_anything = false; + auto closest_so_far = tmax; + + for (const auto& object : objects) { + if (object->hit(r, tmin, closest_so_far, temp_rec)) { + hit_anything = true; + closest_so_far = temp_rec.t; + rec = temp_rec; + } + } + + return hit_anything; +} + +#endif // HITTABLE_LIST_H diff --git a/sphere.h b/sphere.h index b9fdbc5..7e7f644 100644 --- a/sphere.h +++ b/sphere.h @@ -18,27 +18,29 @@ private: double radius; }; -bool Sphere::hit(const Ray& r, double tmin, double tmax, hit_record& rec) { +bool Sphere::hit(const Ray& r, double tmin, double tmax, hit_record& rec) const { Vec3 oc = r.origin() - center; 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) { + if (discriminant > 0) { auto root = std::sqrt(discriminant); auto temp = (-half_b - root) / a; - if (temp < t_max && temp > t_min) { + if (temp < tmax && temp > tmin) { rec.t = temp; rec.p = r.at(rec.t); - rec.normal = (rec.p - center) / radius; - return true + Vec3 outward_normal = (rec.p - center) / radius; + rec.set_face_normal(r, outward_normal); + return true; } - temp (-half_b + root) / a; - if (temp < t_max && temp > t_min) { + temp = (-half_b + root) / a; + if (temp < tmax && temp > tmin) { rec.t = temp; rec.p = r.at(rec.t); - rec.normal = (rec.p - center) / radius; - return true + Vec3 outward_normal = (rec.p - center) / radius; + rec.set_face_normal(r, outward_normal); + return true; } } return false; diff --git a/util.h b/util.h new file mode 100644 index 0000000..4750d34 --- /dev/null +++ b/util.h @@ -0,0 +1,13 @@ +#ifndef UTIL_H +#define UTIL_H + +#include + +const double infinity = std::numeric_limits::infinity(); +const double pi = 3.1415926535897932385; + +inline double degrees_to_radians(double degrees) { + return degrees * pi / 180; +} + +#endif // UTIL_H diff --git a/wtracer.cpp b/wtracer.cpp index 13c91f6..6941344 100644 --- a/wtracer.cpp +++ b/wtracer.cpp @@ -1,19 +1,20 @@ #include -#include #include "color.h" #include "vec3.h" #include "ray.h" +#include "util.h" -Color ray_color(const Ray& r) { - auto sphere_center = Point3(0, 0, -1); - auto t = hit_sphere(sphere_center, 0.5, r); - if (t > 0.0) { - Vec3 n = unit_vector(r.at(t) - sphere_center); - return 0.5 * Color(n.x()+1, n.y()+1, n.z()+1); +#include "hittable_list.h" +#include "sphere.h" + +Color ray_color(const Ray& r, const Hittable& world) { + hit_record rec; + if (world.hit(r, 0, infinity, rec)) { + return 0.5 * (rec.normal + Color(1,1,1)); } Vec3 unit_direction = unit_vector(r.direction()); - t = 0.5 * (unit_direction.y() + 1.0); + auto t = 0.5 * (unit_direction.y() + 1.0); return (1.0 - t) * Color(1.0, 1.0, 1.0) + t * Color(0.5, 0.7, 1.0); } @@ -33,13 +34,17 @@ int main() { auto vertical = Vec3(0, viewport_height, 0); auto lower_left_corner = origin - horizontal/2 - vertical/2 - Vec3(0, 0, focal_length); + 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)); + for (int j = image_height - 1; j >= 0; --j) { std::cerr << "\rScanlines remaining: " << j << " " << std::flush; for (int i = 0; i < image_width; ++i) { auto u = double(i) / (image_width - 1); auto v = double(j) / (image_height - 1); Ray r(origin, lower_left_corner + u*horizontal + v*vertical - origin); - Color pixel_color = ray_color(r); + Color pixel_color = ray_color(r, world); write_color(std::cout, pixel_color); } }