diff --git a/.gitignore b/.gitignore index b127847..72bb439 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ *.o wtracer -image.ppm +*.ppm diff --git a/Makefile b/Makefile index 283401a..d34ab54 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,9 @@ CXX = g++ -CXXFLAGS = -std=c++14 -Wall -Wextra -march=native -Ofast -fopenmp -flto +CXXFLAGS = -std=c++14 -Wall -Wextra -Wno-unused-parameter -march=native -Ofast -fopenmp -flto -DEPS = util.h vec3.h color.h ray.h camera.h hittable.h hittable_list.h sphere.h -OBJ = wtracer.o +DEPS = util.h vec3.h color.h ray.h camera.h hittable.h hittable_list.h sphere.h material.h +OBJ = wtracer.o material.o vec3.o TARGET = wtracer diff --git a/hittable.h b/hittable.h index 6c757e2..6736158 100644 --- a/hittable.h +++ b/hittable.h @@ -1,11 +1,17 @@ #ifndef HITTABLE_H #define HITTABLE_H +#include + #include "ray.h" +#include "material.h" + +class Material; struct hit_record { Point3 p; Vec3 normal; + std::shared_ptr mat_ptr; double t; bool front_face; diff --git a/material.cpp b/material.cpp new file mode 100644 index 0000000..f9ee044 --- /dev/null +++ b/material.cpp @@ -0,0 +1,17 @@ +#include "material.h" + +bool Lambertian::scatter(const Ray& r_in, const hit_record& rec, Color& attenuation, Ray& scattered) const { + //Vec3 scatter_direction = rec.normal + random_in_unit_sphere(); + Vec3 scatter_direction = rec.normal + random_unit_vector(); + //Vec3 scatter_direction = random_in_hemisphere(rec.normal); + scattered = Ray(rec.p, scatter_direction); + attenuation = albedo; + return true; +} + +bool Metal::scatter(const Ray& r_in, const hit_record& rec, Color& attenuation, Ray& scattered) const { + Vec3 reflected = reflect(unit_vector(r_in.direction()), rec.normal); + scattered = Ray(rec.p, reflected); + attenuation = albedo; + return (dot(scattered.direction(), rec.normal) > 0); +} diff --git a/material.h b/material.h new file mode 100644 index 0000000..109c12e --- /dev/null +++ b/material.h @@ -0,0 +1,33 @@ +#ifndef MATERIAL_H +#define MATERIAL_H + +#include "hittable.h" +#include "vec3.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; + +private: + 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; +private: + Color albedo; +}; + +#endif // MATERIAL_H diff --git a/sphere.h b/sphere.h index 7e7f644..2b22fc4 100644 --- a/sphere.h +++ b/sphere.h @@ -2,20 +2,23 @@ #define SPHERE_H #include +#include #include "hittable.h" +#include "material.h" #include "vec3.h" class Sphere : public Hittable { public: Sphere() {} - Sphere(Point3 cen, double r) : center(cen), radius(r) {} + Sphere(Point3 cen, double r, std::shared_ptr m) : center(cen), radius(r), mat_ptr(m) {} virtual bool hit(const Ray& r, double tmin, double tmax, hit_record& rec) const; private: Point3 center; double radius; + std::shared_ptr mat_ptr; }; bool Sphere::hit(const Ray& r, double tmin, double tmax, hit_record& rec) const { @@ -32,6 +35,7 @@ bool Sphere::hit(const Ray& r, double tmin, double tmax, hit_record& rec) const 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; } temp = (-half_b + root) / a; @@ -40,6 +44,7 @@ bool Sphere::hit(const Ray& r, double tmin, double tmax, hit_record& rec) const 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; } } diff --git a/vec3.cpp b/vec3.cpp new file mode 100644 index 0000000..827f81d --- /dev/null +++ b/vec3.cpp @@ -0,0 +1,24 @@ +#include "vec3.h" + +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() { + auto a = random_double(0, 2*pi); + auto z = random_double(-1, 1); + auto r = std::sqrt(1 - z*z); + return Vec3(r*std::cos(a), r*std::sin(a), z); +} + +Vec3 random_in_hemisphere(const Vec3& normal) { + Vec3 in_unit_sphere = random_in_unit_sphere(); + if (dot(in_unit_sphere, normal) > 0.0) + return in_unit_sphere; + else + return -in_unit_sphere; +} diff --git a/vec3.h b/vec3.h index 92f42ea..624c9f5 100644 --- a/vec3.h +++ b/vec3.h @@ -112,27 +112,14 @@ 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; - } +inline Vec3 reflect(const Vec3& v, const Vec3& n) { + return v - 2 * dot(v, n) * n; } -Vec3 random_unit_vector() { - auto a = random_double(0, 2*pi); - auto z = random_double(-1, 1); - auto r = std::sqrt(1 - z*z); - return Vec3(r*std::cos(a), r*std::sin(a), z); -} +Vec3 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) - return in_unit_sphere; - else - return -in_unit_sphere; -} +Vec3 random_unit_vector(); + +Vec3 random_in_hemisphere(const Vec3& normal); #endif // VEC3_H diff --git a/wtracer.cpp b/wtracer.cpp index 28ba327..47c72ba 100644 --- a/wtracer.cpp +++ b/wtracer.cpp @@ -17,10 +17,11 @@ Color ray_color(const Ray& r, const Hittable& world, int depth) { return Color(0, 0, 0); if (world.hit(r, 0.001, infinity, rec)) { - //Point3 target = rec.p + rec.normal + random_in_unit_sphere(); - //Point3 target = rec.p + rec.normal + random_unit_vector(); - Point3 target = rec.p + random_in_hemisphere(rec.normal); - return 0.5 * ray_color(Ray(rec.p, target - rec.p), world, depth-1); + 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()); auto t = 0.5 * (unit_direction.y() + 1.0); @@ -33,14 +34,21 @@ int main() { const int image_width = 768; //const int image_width = 384; const int image_height = static_cast(image_width / aspect_ratio); + //const int samples_per_pixel = 1000; const int samples_per_pixel = 400; const int max_depth = 50; std::cout << "P3\n" << image_width << " " << image_height << "\n255\n"; 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)); + /*world.add(std::make_shared(Point3(0, 0, -1), 0.5)); + world.add(std::make_shared(Point3(0, -100.5, -1), 100));*/ + + world.add(std::make_shared(Point3(0, 0, -1), 0.5, std::make_shared(Color(0.7, 0.3, 0.3)))); + world.add(std::make_shared(Point3(0, -100.5, -1), 100, std::make_shared(Color(0.8, 0.8, 0.8)))); + + world.add(std::make_shared(Point3(1, 0, -1), 0.5, std::make_shared(Color(0.8, 0.6, 0.2)))); + world.add(std::make_shared(Point3(-1, 0, -1), 0.5, std::make_shared(Color(0.8, 0.8, 0.8)))); Camera cam;