From 56bed8e38f5b6d9effd77371ad781ae71601205b Mon Sep 17 00:00:00 2001 From: ladevieq Date: Mon, 21 Dec 2020 13:51:18 +0100 Subject: Add lambertian and metallic materials --- src/CMakeLists.txt | 13 ++++++++++++- src/lambertian.cpp | 18 ++++++++++++++++++ src/main.cpp | 35 ++++++++++++++++++++--------------- src/metal.cpp | 14 ++++++++++++++ src/ray.cpp | 3 +++ src/sphere.cpp | 4 +++- src/vec3.cpp | 10 ++++++++++ 7 files changed, 80 insertions(+), 17 deletions(-) create mode 100644 src/lambertian.cpp create mode 100644 src/metal.cpp (limited to 'src') 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(point3(0,0,-1), 0.5)); - world.add(std::make_shared(point3(0,-100.5,-1), 100)); + + auto material_ground = std::make_shared(color(0.8, 0.8, 0.0)); + auto material_center = std::make_shared(color(0.7, 0.3, 0.3)); + auto material_left = std::make_shared(color(0.8, 0.8, 0.8), 0.3); + auto material_right = std::make_shared(color(0.8, 0.6, 0.2), 1.0); + + world.add(std::make_shared(point3( 0.0, -100.5, -1.0), 100.0, material_ground)); + world.add(std::make_shared(point3( 0.0, 0.0, -1.0), 0.5, material_center)); + world.add(std::make_shared(point3(-1.0, 0.0, -1.0), 0.5, material_left)); + world.add(std::make_shared(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) + : 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; } -- cgit v1.3