diff options
| -rw-r--r-- | include/hittable.hpp | 5 | ||||
| -rw-r--r-- | include/lambertian.hpp | 15 | ||||
| -rw-r--r-- | include/material.hpp | 13 | ||||
| -rw-r--r-- | include/metal.hpp | 16 | ||||
| -rw-r--r-- | include/ray.hpp | 1 | ||||
| -rw-r--r-- | include/rt.hpp | 3 | ||||
| -rw-r--r-- | include/sphere.hpp | 5 | ||||
| -rw-r--r-- | include/vec3.hpp | 4 | ||||
| -rw-r--r-- | src/CMakeLists.txt | 13 | ||||
| -rw-r--r-- | src/lambertian.cpp | 18 | ||||
| -rw-r--r-- | src/main.cpp | 35 | ||||
| -rw-r--r-- | src/metal.cpp | 14 | ||||
| -rw-r--r-- | src/ray.cpp | 3 | ||||
| -rw-r--r-- | src/sphere.cpp | 4 | ||||
| -rw-r--r-- | src/vec3.cpp | 10 |
15 files changed, 141 insertions, 18 deletions
diff --git a/include/hittable.hpp b/include/hittable.hpp index 4978e57..aa55034 100644 --- a/include/hittable.hpp +++ b/include/hittable.hpp @@ -1,13 +1,18 @@ #ifndef __HITTABLE_HPP_ #define __HITTABLE_HPP_ +#include <memory> + #include "ray.hpp" +class material; + struct hit_info { double t; point3 point; vec3 normal; bool front_face; + std::shared_ptr<material> mat_ptr; inline void set_face_normal(const ray& r, const vec3& outward_normal) { front_face = r.direction.dot(outward_normal) < 0.0; diff --git a/include/lambertian.hpp b/include/lambertian.hpp new file mode 100644 index 0000000..b9b7509 --- /dev/null +++ b/include/lambertian.hpp @@ -0,0 +1,15 @@ +#ifndef __LAMBERTIAN_HPP_ +#define __LAMBERTIAN_HPP_ + +#include "material.hpp" + +class lambertian : public material { + public: + lambertian(const color& albedo); + + virtual bool scatter(const ray& r, const struct hit_info& info, color& attenuation, ray& scattered) const; + + color albedo; +}; + +#endif // !__LAMBERTIAN_HPP_ diff --git a/include/material.hpp b/include/material.hpp new file mode 100644 index 0000000..5e6f095 --- /dev/null +++ b/include/material.hpp @@ -0,0 +1,13 @@ +#ifndef __MATERIAL_HPP_ +#define __MATERIAL_HPP_ + +#include "ray.hpp" + +struct hit_info; + +class material { + public: + virtual bool scatter(const ray& r, const struct hit_info& info, color& attenuation, ray& scaterred) const = 0; +}; + +#endif // !__MATERIAL_HPP_ diff --git a/include/metal.hpp b/include/metal.hpp new file mode 100644 index 0000000..5516890 --- /dev/null +++ b/include/metal.hpp @@ -0,0 +1,16 @@ +#ifndef __METAL_HPP_ +#define __METAL_HPP_ + +#include "material.hpp" + +class metal : public material { + public: + metal(const color& albedo, double f); + + virtual bool scatter(const ray& r, const struct hit_info& info, color& attenuation, ray& scattered) const; + + color albedo; + double fuzz; +}; + +#endif // !__METAL_HPP_ diff --git a/include/ray.hpp b/include/ray.hpp index b3d88ae..e18812e 100644 --- a/include/ray.hpp +++ b/include/ray.hpp @@ -6,6 +6,7 @@ class ray { public: + ray(); ray(const point3& origin, const vec3& direction); point3 at(double t) const; diff --git a/include/rt.hpp b/include/rt.hpp index a0c912e..2cf3ce2 100644 --- a/include/rt.hpp +++ b/include/rt.hpp @@ -31,5 +31,8 @@ inline double clamp(double x, double min, double max) { #include "color.hpp" #include "sphere.hpp" #include "camera.hpp" +#include "material.hpp" +#include "lambertian.hpp" +#include "metal.hpp" #endif // !__RT_HPP_ diff --git a/include/sphere.hpp b/include/sphere.hpp index 5bf0ab9..c33a796 100644 --- a/include/sphere.hpp +++ b/include/sphere.hpp @@ -2,15 +2,18 @@ #define __SPHERE_HPP_ #include "hittable.hpp" +#include "material.hpp" class sphere : public hittable { public: - sphere(point3 center, double radius = 1.0); + sphere(point3 center, double radius, std::shared_ptr<material> material); virtual bool hit(const ray& r, double t_min, double t_max, struct hit_info& info) const; point3 center; double radius; + + std::shared_ptr<material> mat_ptr; }; #endif // !__SPHERE_HPP_ diff --git a/include/vec3.hpp b/include/vec3.hpp index 7b0e469..317f99b 100644 --- a/include/vec3.hpp +++ b/include/vec3.hpp @@ -28,6 +28,8 @@ class vec3 { vec3 unit() const; + bool near_zero() const; + static vec3 random(); static vec3 random(double min, double max); @@ -49,6 +51,8 @@ vec3 operator*(double scale, vec3 u); vec3 operator/(vec3 u, double scale); +vec3 reflect(vec3 v, vec3 n); + std::ostream& operator<<(std::ostream& out, vec3 vec); vec3 random_in_unit_sphere(); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 996db85..691d221 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,3 +1,14 @@ include_directories(${CMAKE_SOURCE_DIR}/include) -add_executable(path-tracer main.cpp vec3.cpp color.cpp ray.cpp sphere.cpp hittable_list.cpp camera.cpp) +add_executable( + path-tracer + main.cpp + vec3.cpp + color.cpp + ray.cpp + sphere.cpp + hittable_list.cpp + camera.cpp + lambertian.cpp + metal.cpp +) diff --git a/src/lambertian.cpp b/src/lambertian.cpp new file mode 100644 index 0000000..16ab146 --- /dev/null +++ b/src/lambertian.cpp @@ -0,0 +1,18 @@ +#include "lambertian.hpp" +#include "hittable.hpp" + +lambertian::lambertian(const color& albedo) : albedo(albedo) {} + +bool lambertian::scatter(const ray& r, const struct hit_info& info, color& attenuation, ray& scattered) const { + // auto scatter_direction = info.normal + random_in_unit_sphere(); + // auto scatter_direction = info.normal + random_unit_vector(); + auto scatter_direction = info.normal + random_in_hemisphere(info.normal); + + if (scatter_direction.near_zero()) { + scatter_direction = info.normal; + } + + scattered = ray { info.point, scatter_direction }; + attenuation = albedo; + return true; +} diff --git a/src/main.cpp b/src/main.cpp index 62ef981..9718d3e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,24 +10,21 @@ color ray_color(ray& r, const hittable& world, uint32_t depth) { if (depth <= 0) { return color{}; } - sphere sphere { { 0.0, 0.0, -1.0 }, 0.5 }; - - auto unit_dir = r.direction.unit(); - auto t = (unit_dir.y + 1.0) * 0.5; - - auto c = lerp(ground_color, sky_color, t); struct hit_info info; if (world.hit(r, 0.001, infinity, info)) { - // point3 target = info.point + info.normal + random_in_unit_sphere(); - // point3 target = info.point + info.normal + random_unit_vector(); - point3 target = info.point + info.normal + random_in_hemisphere(info.normal); - ray reflect { info.point, target - info.point }; - c = 0.5 * ray_color(reflect, world, depth - 1); - // c = 0.5 * (target - info.point + vec3{ 1.0, 1.0, 1.0 }); + color attenuation; + ray scattered {}; + + if (info.mat_ptr->scatter(r, info, attenuation, scattered)) { + return attenuation * ray_color(scattered, world, depth - 1); + } + return color{}; } - return c; + auto unit_dir = r.direction.unit(); + auto t = (unit_dir.y + 1.0) * 0.5; + return lerp(ground_color, sky_color, t); } int main() { @@ -42,8 +39,16 @@ int main() { // World hittable objects hittable_list world {}; - world.add(std::make_shared<sphere>(point3(0,0,-1), 0.5)); - world.add(std::make_shared<sphere>(point3(0,-100.5,-1), 100)); + + auto material_ground = std::make_shared<lambertian>(color(0.8, 0.8, 0.0)); + auto material_center = std::make_shared<lambertian>(color(0.7, 0.3, 0.3)); + auto material_left = std::make_shared<metal>(color(0.8, 0.8, 0.8), 0.3); + auto material_right = std::make_shared<metal>(color(0.8, 0.6, 0.2), 1.0); + + world.add(std::make_shared<sphere>(point3( 0.0, -100.5, -1.0), 100.0, material_ground)); + world.add(std::make_shared<sphere>(point3( 0.0, 0.0, -1.0), 0.5, material_center)); + world.add(std::make_shared<sphere>(point3(-1.0, 0.0, -1.0), 0.5, material_left)); + world.add(std::make_shared<sphere>(point3( 1.0, 0.0, -1.0), 0.5, material_right)); // PPM format header std::cout << "P3\n" << width << '\n' << height << "\n 255" << std::endl; diff --git a/src/metal.cpp b/src/metal.cpp new file mode 100644 index 0000000..d02a2f7 --- /dev/null +++ b/src/metal.cpp @@ -0,0 +1,14 @@ +#include "metal.hpp" +#include "hittable.hpp" +#include "vec3.hpp" + +metal::metal(const color& albedo, double f) + : albedo(albedo), fuzz(f < 1 ? f : 1) {} + +bool metal::scatter(const ray& r, const struct hit_info& info, color& attenuation, ray& scattered) const { + auto reflected = reflect(r.direction, info.normal).unit(); + + scattered = ray { info.point, reflected + fuzz * random_in_unit_sphere() }; + attenuation = albedo; + return (scattered.direction.dot(info.normal) > 0.0); +} diff --git a/src/ray.cpp b/src/ray.cpp index ebf392b..9a8bd36 100644 --- a/src/ray.cpp +++ b/src/ray.cpp @@ -1,5 +1,8 @@ #include "ray.hpp" +ray::ray() +{} + ray::ray(const point3& origin, const vec3& direction): origin(origin), direction(direction) {} diff --git a/src/sphere.cpp b/src/sphere.cpp index 31915a2..611dc34 100644 --- a/src/sphere.cpp +++ b/src/sphere.cpp @@ -1,6 +1,7 @@ #include "sphere.hpp" -sphere::sphere(point3 center, double radius) : center(center), radius(radius) +sphere::sphere(point3 center, double radius, std::shared_ptr<material> material) + : center(center), radius(radius), mat_ptr(material) {} bool sphere::hit(const ray& r, double t_min, double t_max, struct hit_info& info) const { @@ -29,6 +30,7 @@ bool sphere::hit(const ray& r, double t_min, double t_max, struct hit_info& info info.t = t; info.point = r.at(t); + info.mat_ptr = mat_ptr; vec3 out_normal = (info.point - center).unit(); info.set_face_normal(r, out_normal); diff --git a/src/vec3.cpp b/src/vec3.cpp index f5b6909..92ccae4 100644 --- a/src/vec3.cpp +++ b/src/vec3.cpp @@ -61,6 +61,12 @@ vec3 vec3::unit() const { return *this / length(); } +bool vec3::near_zero() const { + const auto s = 1e-8; + + return (fabs(x) < s) && (fabs(y) < s) && (fabs(z) < s); +} + vec3 vec3::random() { return vec3 { randd(), randd(), randd() }; } @@ -101,6 +107,10 @@ vec3 operator/(vec3 u, double scale) { return (1.0 / scale) * u; } +vec3 reflect(vec3 v, vec3 n) { + return v - 2 * v.dot(n) * n; +} + std::ostream& operator<<(std::ostream& out, vec3 vec) { return out << vec.x << ' ' << vec.y << ' ' << vec.z << std::endl; } |
