aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
7 files changed, 80 insertions, 17 deletions
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;
}