From 35c69dbee61df5d79fd34126ae70bd6391bf1289 Mon Sep 17 00:00:00 2001 From: Nigel Date: Sun, 5 Mar 2023 12:02:51 +0100 Subject: [PATCH] Adding material abstractio plus metal reflective material --- src/color.h | 6 +++--- src/hittable.h | 4 ++++ src/material.h | 42 ++++++++++++++++++++++++++++++++++++++++++ src/program.cpp | 31 +++++++++++++++++++++++++------ src/sphere.h | 6 ++++-- src/vector3.h | 36 ++++++++++++++++++++++++++++++++++++ 6 files changed, 114 insertions(+), 11 deletions(-) create mode 100644 src/material.h diff --git a/src/color.h b/src/color.h index 04534eb..eed3f0f 100644 --- a/src/color.h +++ b/src/color.h @@ -10,9 +10,9 @@ void write_color(std::ostream& out, color pixel_color, int samples_per_pixel){ // Divide the color by the number of samples auto scale = 1.0 / samples_per_pixel; - r *= scale; - g *= scale; - b *= scale; + r = sqrt (scale * r); + g = sqrt (scale * g); + b = sqrt (scale * b); diff --git a/src/hittable.h b/src/hittable.h index f4ea713..9e03f6a 100644 --- a/src/hittable.h +++ b/src/hittable.h @@ -1,10 +1,14 @@ #pragma once #include "ray.h" +#include "rtweekend.h" + +class material; struct hit_record{ point3 p; vec3 normal; + shared_ptr mat_ptr; double t; bool front_face; diff --git a/src/material.h b/src/material.h new file mode 100644 index 0000000..cae78f3 --- /dev/null +++ b/src/material.h @@ -0,0 +1,42 @@ +#pragma once +#include "rtweekend.h" + +struct hit_record; + +class material { + public: + virtual bool scatter (const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered) const = 0; +}; + +class lambertian : public material{ + public: + lambertian(const color& a) : albedo(a){} + + virtual bool scatter(const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered) const override { + auto scatter_direction = rec.normal + random_unit_vector(); + if(scatter_direction.near_zero()) + scatter_direction = rec.normal; + + scattered = ray(rec.p, scatter_direction); + attenuation = albedo; + return true; + } + + public : + color albedo; + +}; + +class metal : public material{ + public: + metal(const color& a) : albedo(a){} + + virtual bool scatter(const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered)const override { + vec3 reflected = reflect(unit_vector(r_in.direction()), rec.normal); + scattered = ray(rec.p, reflected); + attenuation =albedo; + return (dot(scattered.direction(), rec.normal) > 0); + } + public: + color albedo; +}; \ No newline at end of file diff --git a/src/program.cpp b/src/program.cpp index 1fdafbd..b705823 100644 --- a/src/program.cpp +++ b/src/program.cpp @@ -4,13 +4,22 @@ #include "color.h" #include "hittable_list.h" #include "sphere.h" +#include "material.h" #include -color ray_color(const ray& r, const hittable& world){ +color ray_color(const ray& r, const hittable& world, int depth){ hit_record rec; - if(world.hit(r, 0, infinity, rec)){ - return 0.5 * (rec.normal + color(1,1,1)); + + if( depth <= 0) + return color(0,0,0); + + if(world.hit(r, 0.001, infinity, rec)) { + ray scattered; + color attenuation; + if(rec.mat_ptr->scatter(r, rec, attenuation,scattered)) + return attenuation * ray_color(scattered, world ,depth -1); + return color(0,0,0); } vec3 unit_direction = unit_vector(r.direction()); @@ -26,11 +35,21 @@ int main () const int image_width = 400; const int image_height = static_cast(image_width /aspect_ratio); const int samples_per_pixel = 100; + const int max_depth = 50; // World hittable_list world; - world.add(make_shared(point3(0,0,-1), 0.5)); - world.add(make_shared(point3(0,-100.5,-1), 100)); + + auto material_ground = make_shared(color(0.8,0.8, 0.0)); + auto material_center = make_shared(color(0.7,0.3,0.3)); + auto material_left = make_shared (color(0.8,0.8,0.8)); + auto material_right = make_shared(color(0.8,0.6,0.2)); + + + world.add(make_shared(point3(0,-100.5,-1), 100.0, material_ground)); + world.add(make_shared(point3(0,0,-1), 0.5, material_center)); + world.add(make_shared(point3(-1.0, 0.0, -1), 0.5, material_left)); + world.add(make_shared(point3(1.0, 0.0, -1), 0.5, material_right)); // Camera @@ -48,7 +67,7 @@ int main () auto u = (i + random_double()) / (image_width-1); auto v = (j + random_double()) / (image_height-1); ray r = cam.get_ray(u,v); - pixel_color += ray_color(r, world); + pixel_color += ray_color(r, world, max_depth); } write_color(std::cout, pixel_color, samples_per_pixel); diff --git a/src/sphere.h b/src/sphere.h index 5560baf..f51bade 100644 --- a/src/sphere.h +++ b/src/sphere.h @@ -6,13 +6,14 @@ class sphere : public hittable{ public: sphere(){} - sphere(point3 cen, double r): center(cen), radius(r){}; + sphere(point3 cen, double r, shared_ptr m): center(cen), radius(r), mat_ptr(m){}; virtual bool hit(const ray& r, double t_min, double t_max, hit_record& rec) const override; public: point3 center; double radius; + shared_ptr mat_ptr; }; @@ -38,6 +39,7 @@ bool sphere::hit(const ray& r, double t_min, double t_max, hit_record& rec) cons rec.p = r.at(rec.t); vec3 outward_normal = (rec.p - center) /radius; rec.set_face_normal(r, outward_normal); - + rec.mat_ptr = mat_ptr; + return true; } \ No newline at end of file diff --git a/src/vector3.h b/src/vector3.h index 755810f..42d9038 100644 --- a/src/vector3.h +++ b/src/vector3.h @@ -43,6 +43,18 @@ class vec3{ return e[0]*e[0] + e[1]*e[1] + e[2]*e[2]; } + inline static vec3 random(){ + return vec3(random_double(), random_double(), random_double()); + } + + inline static vec3 random (double min, double max){ + return vec3(random_double(min,max),random_double(min,max),random_double(min,max)); + } + bool near_zero() const { + const auto s = 1e-8; + return (fabs(e[0]) < s) && (fabs(e[1]) < s) && (fabs(e[2]) < s); + } + double e[3]; }; @@ -95,3 +107,27 @@ inline vec3 cross(const vec3& u, const vec3& v){ inline vec3 unit_vector(vec3 v){ return v / v.length(); } + +vec3 random_in_unit_sphere(){ + while(true){ + auto p = vec3::random(-1,1); + if(p.length_squared() >= 1) continue; + return p; + } +} + +vec3 random_unit_vector(){ + return unit_vector(random_in_unit_sphere()); +} + +vec3 random_in_hemisphere (const vec3& normal){ + vec3 in_unit_sphere = random_in_unit_sphere(); + if(dot(in_unit_sphere, normal) > 0.0) // In the same hemisphere as the normal + return in_unit_sphere; + else + return -in_unit_sphere; +} + +vec3 reflect (const vec3& v, const vec3& n){ + return v -2 *dot(v,n) *n; +} \ No newline at end of file