Add material support

This commit is contained in:
Phireh 2021-08-22 17:24:33 +02:00
commit 58ffcff459
7 changed files with 112 additions and 36 deletions

View file

@ -1,16 +0,0 @@
#ifndef HITTABLE_H
#define HITTABLE_H
#include "ray.h"
struct hit_record {
point3 p;
vec3 normal;
double t;
};
struct hittable {
virtual bool hit(const ray& r, double t_min, double t_max, hit_record& rec) const = 0;
};
#endif

View file

@ -1,21 +1,8 @@
#ifndef HITTABLE_H #ifndef HITTABLE_H
#define HITTABLE_H #define HITTABLE_H
#include "ray.hpp" #include "rtweekend.hpp"
#include "material.hpp"
/* Representation of a hitpoint of a ray against a hittable object */
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;
}
};
/* Virtual class that represents objects who could collide against a ray */ /* Virtual class that represents objects who could collide against a ray */
struct hittable { struct hittable {

View file

@ -21,8 +21,16 @@ color ray_color(const ray& r, const hittable& world, int32_t depth)
hit_record rec; hit_record rec;
if (world.hit(r, 0.001, INFINITY, rec)) if (world.hit(r, 0.001, INFINITY, rec))
{ {
point3 target = rec.p + rec.normal + random_in_hemisphere(rec.normal); ray scattered;
return 0.5 * ray_color(ray(rec.p, target - rec.p), world, depth-1); color attenuation;
if (rec.mat_ptr->scatter(r, rec, attenuation, scattered))
{
return attenuation * ray_color(scattered, world, depth-1);
}
else
{
return color(0,0,0);
}
} }
vec3 unit_direction = normalize(r.direction); vec3 unit_direction = normalize(r.direction);
double t = 0.5 * (unit_direction.y + 1.0); double t = 0.5 * (unit_direction.y + 1.0);
@ -64,8 +72,17 @@ int main()
// World // World
hittable_list world; 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)); std::shared_ptr<lambertian> material_ground = make_shared<lambertian>(color(0.8, 0.8, 0.0));
std::shared_ptr<lambertian> material_center = make_shared<lambertian>(color(0.7, 0.3, 0.3));
std::shared_ptr<metal> material_left = make_shared<metal>(color(0.8, 0.8, 0.8));
std::shared_ptr<metal> material_right = make_shared<metal>(color(0.8, 0.6, 0.2));
world.add(make_shared<sphere>(point3( 0.0, -100.5, -1.0), 100.0, material_ground));
world.add(make_shared<sphere>(point3( 0.0, 0.0, -1.0), 0.5, material_center));
world.add(make_shared<sphere>(point3(-1.0, 0.0, -1.0), 0.5, material_left));
world.add(make_shared<sphere>(point3( 1.0, 0.0, -1.0), 0.5, material_right));
// Camera // Camera
camera cam; camera cam;

52
material.hpp Normal file
View file

@ -0,0 +1,52 @@
#ifndef MATERIAL_H
#define MATERIAL_H
#include "rtweekend.hpp"
struct material {
virtual bool scatter(const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered) const = 0;
};
struct lambertian : material {
/* Attributes */
color albedo;
// Constructor
lambertian(const color& c) { albedo = c; }
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
virtual bool scatter(const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered) const override
{
vec3 scatter_direction = rec.normal + random_unit_vector();
/* NOTE: it is possible that the random vector we generate is exactly opposite to the normal vector,
in which case it will sum to a near-zero scatter vector and generate degenerate results.
We check for near-zero vectors here.
*/
if (scatter_direction.near_zero())
scatter_direction = rec.normal;
scattered = ray(rec.p, scatter_direction);
attenuation = albedo;
return true;
}
#pragma GCC diagnostic pop
};
struct metal : material {
/* Attributes */
color albedo;
// Constructor
metal(const color& c) { albedo = c; };
virtual bool scatter(const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered) const override
{
vec3 reflected = reflect(normalize(r_in.direction), rec.normal);
scattered = ray(rec.p, reflected);
attenuation = albedo;
return (dot(scattered.direction, rec.normal) > 0);
}
};
#endif

View file

@ -33,5 +33,25 @@ inline double clamp(double v, double min, double max)
#include "ray.hpp" #include "ray.hpp"
#include "vec3.hpp" #include "vec3.hpp"
struct material;
/* Common data structures */
struct hit_record {
point3 p;
vec3 normal;
std::shared_ptr<material> mat_ptr;
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;
}
};
#endif #endif

View file

@ -8,12 +8,14 @@ struct sphere : hittable {
/* Attributes */ /* Attributes */
point3 center; point3 center;
double radius; double radius;
std::shared_ptr<material> mat_ptr;
/* Contructor */ /* Contructor */
sphere(point3 c, double r) sphere(point3 c, double r, std::shared_ptr<material> m)
{ {
center = c; center = c;
radius = r; radius = r;
mat_ptr = m;
} }
/* Virtual methods declaration */ /* Virtual methods declaration */
@ -46,6 +48,7 @@ bool sphere::hit(const ray& r, double t_min, double t_max, hit_record& rec) cons
rec.p = r.at(rec.t); rec.p = r.at(rec.t);
vec3 outward_normal = (rec.p - center) / radius; vec3 outward_normal = (rec.p - center) / radius;
rec.set_face_normal(r, outward_normal); rec.set_face_normal(r, outward_normal);
rec.mat_ptr = mat_ptr;
return true; return true;
} }

View file

@ -76,6 +76,13 @@ struct vec3 {
{ {
return vec3(random_double(min, max), random_double(min, max), random_double(min, max)); return vec3(random_double(min, max), random_double(min, max), random_double(min, max));
} }
// Check if all vector components are near zero
bool near_zero() const
{
double s = 1e-8;
return (fabs(x) < s) && (fabs(y) < s) && (fabs(z) < s);
}
}; };
/* Type aliases */ /* Type aliases */
@ -175,4 +182,10 @@ vec3 random_in_hemisphere(const vec3& normal)
return -in_unit_sphere; return -in_unit_sphere;
} }
// Reflect like a metallic material
vec3 reflect(const vec3& v, const vec3 n)
{
return v - 2*dot(v,n)*n;
}
#endif #endif