aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorladevieq <ladevie.quentin@gmail.com>2020-12-21 13:51:18 +0100
committerladevieq <ladevie.quentin@gmail.com>2020-12-21 13:51:18 +0100
commit56bed8e38f5b6d9effd77371ad781ae71601205b (patch)
tree1f57155b8f5b15fd2b33ac7e926e3e5d0ce1754c
parent92d66138f53645f3400f633c9821a6fa36f589e0 (diff)
Add lambertian and metallic materials
-rw-r--r--include/hittable.hpp5
-rw-r--r--include/lambertian.hpp15
-rw-r--r--include/material.hpp13
-rw-r--r--include/metal.hpp16
-rw-r--r--include/ray.hpp1
-rw-r--r--include/rt.hpp3
-rw-r--r--include/sphere.hpp5
-rw-r--r--include/vec3.hpp4
-rw-r--r--src/CMakeLists.txt13
-rw-r--r--src/lambertian.cpp18
-rw-r--r--src/main.cpp35
-rw-r--r--src/metal.cpp14
-rw-r--r--src/ray.cpp3
-rw-r--r--src/sphere.cpp4
-rw-r--r--src/vec3.cpp10
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;
}