Hittables abstraction

This commit is contained in:
Armin Friedl 2022-07-26 17:01:53 +02:00
parent 0c8191be28
commit b9862477cd
6 changed files with 165 additions and 26 deletions

View file

@ -3,4 +3,9 @@ project(rtiww)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
add_executable(rtiww src/main.cpp src/vec3.h src/color.h src/ray.h) add_executable(rtiww src/main.cpp
src/vec3.h src/ray.h
src/color.h
src/hittable.h src/hittable_list.h
src/sphere.h
src/rtweekend.h)

25
rtiww/src/hittable.h Normal file
View file

@ -0,0 +1,25 @@
#ifndef HITTABLE_H_
#define HITTABLE_H_
#include "ray.h"
#include "vec3.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 t_min, double t_max,
hit_record &rec) const = 0;
};
#endif // HITTABLE_H_

44
rtiww/src/hittable_list.h Normal file
View file

@ -0,0 +1,44 @@
#ifndef HITTABLE_LIST_H_
#define HITTABLE_LIST_H_
#include "hittable.h"
#include <memory>
#include <vector>
using std::shared_ptr;
using std::vector;
class hittable_list : public hittable {
public:
hittable_list() {}
hittable_list(shared_ptr<hittable> object) { add(object); }
void clear() { objects.clear(); }
void add(shared_ptr<hittable> object) { objects.push_back(object); }
virtual bool hit(const ray &r, double t_min, double t_max,
hit_record &rec) const override;
public:
std::vector<shared_ptr<hittable>> objects;
};
bool hittable_list::hit(const ray &r, double t_min, double t_max,
hit_record &rec) const {
hit_record temp_rec;
bool hit_anything = false;
auto closest_so_far = t_max;
for (const auto &object : objects) {
if (object->hit(r, t_min, closest_so_far, temp_rec)) {
hit_anything = true;
closest_so_far = temp_rec.t;
rec = temp_rec;
}
}
return hit_anything;
}
#endif // HITTABLE_LIST_H_

View file

@ -1,33 +1,19 @@
#include "hittable.h"
#include "rtweekend.h"
#include "color.h" #include "color.h"
#include "vec3.h" #include "hittable_list.h"
#include "ray.h" #include "sphere.h"
#include <iostream> #include <iostream>
double hit_sphere(const point3 &center, double radius, const ray &r) { color ray_color(const ray &r, const hittable& world) {
vec3 oc = r.origin() - center; hit_record rec;
if(world.hit(r, 0, infinity, rec)) {
auto a = r.direction().length_squared(); return 0.5 * (rec.normal + color(1,1,1));
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) {
return -1.0;
} else {
return (-half_b - sqrt(discriminant)) / a;
} }
}
color ray_color(const ray &r) {
auto t = hit_sphere(point3(0,0,-1), 0.5, r);
if(t > 0.0) {
vec3 N = unit_vector(r.at(t) - vec3(0,0,-1));
return 0.5*color(N.x()+1, N.y()+1, N.z()+1);
}
vec3 unit_direction = unit_vector(r.direction()); 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); return (1.0 - t) * color(1.0, 1.0, 1.0) + t * color(0.5, 0.7, 1.0);
} }
@ -38,6 +24,11 @@ int main() {
const int image_width = 400; const int image_width = 400;
const int image_height = static_cast<int>(image_width / aspect_ratio); const int image_height = static_cast<int>(image_width / aspect_ratio);
// World
hittable_list world;
world.add(make_shared<sphere>(point3(0,0,-1), 0.5));
world.add(make_shared<sphere>(point3(0,-100.5,-1), 100));
// Camera // Camera
auto viewport_height = 2.0; auto viewport_height = 2.0;
auto viewport_width = aspect_ratio * viewport_height; auto viewport_width = aspect_ratio * viewport_height;
@ -58,7 +49,7 @@ int main() {
auto v = double(j) / (image_height - 1); auto v = double(j) / (image_height - 1);
ray r(origin, lower_left_corner + u * horizontal + v * vertical - origin); 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); write_color(std::cout, pixel_color);
} }
} }

32
rtiww/src/rtweekend.h Normal file
View file

@ -0,0 +1,32 @@
#ifndef RTWEEKEND_H_
#define RTWEEKEND_H_
#include <cmath>
#include <limits>
#include <memory>
using std::shared_ptr;
using std::make_shared;
using std::sqrt;
const double infinity = std::numeric_limits<double>::infinity();
const double pi = 3.1415926535897932385;
inline double degrees_to_radians(double degrees) {
return degrees * pi / 180.0;
}
inline double random_double() {
// Returns a random real in [0,1).
return rand() / (RAND_MAX + 1.0);
}
inline double random_double(double min, double max) {
// Returns a random real in [min, max).
return min + (max-min)*random_double();
}
#include "ray.h"
#include "vec3.h"
#endif // RTWEEKEND_H_

42
rtiww/src/sphere.h Normal file
View file

@ -0,0 +1,42 @@
#ifndef SPHERE_H_
#define SPHERE_H_
#include "hittable.h"
class sphere: public hittable {
public:
sphere() {}
sphere(point3 cen, double r): center(cen), radius(r) {};
virtual bool hit(const ray& r, double t_min, double t_max, hit_record& rec) const override;
public:
point3 center;
double radius;
};
bool sphere::hit(const ray& r, double t_min, double t_max, 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) return false;
auto sqrtd = sqrt(discriminant);
// Find the nearest root that lies in the acceptable range
auto root = (-half_b - sqrtd) / a;
if(root < t_min || t_max<root) {
root = (-half_b + sqrtd) / a;
if (root < t_min || t_max < root) return false;
}
rec.t = root;
rec.p = r.at(rec.t);
vec3 outward_normal = (rec.p - center) / radius;
rec.set_face_normal(r, outward_normal);
return true;
}
#endif // SPHERE_H_