From 2d4671d5469116b05709bb1acb614d784d339964 Mon Sep 17 00:00:00 2001 From: Keuin Date: Fri, 15 Apr 2022 14:06:27 +0800 Subject: Make ray3::decay_ distinguishable between different color channels. --- bitmap.h | 5 +++++ hitlist.h | 2 +- material.cpp | 25 ++++++++++++++++++++----- material.h | 9 ++++++--- ray.h | 10 +++++----- vec.h | 13 +++++++++++++ 6 files changed, 50 insertions(+), 14 deletions(-) diff --git a/bitmap.h b/bitmap.h index 64f69a6..a544b03 100644 --- a/bitmap.h +++ b/bitmap.h @@ -123,6 +123,11 @@ pixel operator*(S scale, const pixel &pixel) { return ::pixel < T > {.r=(T) (pixel.r * scale), .g=(T) (pixel.g * scale), .b=(T) (pixel.b * scale)}; } +template +pixel operator*(const vec3 &scale, const pixel &pixel) { + return ::pixel < T > {.r=(T) (pixel.r * scale.x), .g=(T) (pixel.g * scale.y), .b=(T) (pixel.b * scale.z)}; +} + // Mix two colors a and b. Returns a*u + b*v template inline pixel mix(const pixel &a, const pixel &b, double u, double v) { diff --git a/hitlist.h b/hitlist.h index 3b853de..797644a 100644 --- a/hitlist.h +++ b/hitlist.h @@ -39,7 +39,7 @@ public: // Given a ray, compute the color. template pixel color(ray3d r, random_uv_gen_3d &ruvg, uint_fast32_t max_recursion_depth = 64) const { - assert(r.decay() == 1.0); + assert(r.decay().is_one()); while (max_recursion_depth-- > 0) { // Detect hits bool hit = false; diff --git a/material.cpp b/material.cpp index f92b02c..b312246 100644 --- a/material.cpp +++ b/material.cpp @@ -18,16 +18,21 @@ bool material_diffuse_lambertian::scatter(ray3d &r, const object &hit_obj, doubl return true; } -material_diffuse_lambertian::material_diffuse_lambertian(double albedo) : albedo(albedo) { - assert(albedo >= 0); - assert(albedo <= 1); +material_diffuse_lambertian::material_diffuse_lambertian(vec3d albedo) : albedo(albedo) { + assert(albedo.mod2() >= 0); + assert(albedo.mod2() <= 1); } -material_diffuse_simple::material_diffuse_simple(double albedo) : albedo(albedo) { +material_diffuse_lambertian::material_diffuse_lambertian(double albedo) : albedo{albedo, albedo, albedo} { assert(albedo >= 0); assert(albedo <= 1); } +material_diffuse_simple::material_diffuse_simple(vec3d albedo) : albedo(albedo) { + assert(albedo.mod2() >= 0); + assert(albedo.mod2() <= 1); +} + bool material_diffuse_simple::scatter(ray3d &r, const object &hit_obj, double hit_t, random_uv_gen_3d &ruvg) const { const auto hit_point = r.at(hit_t); // hit point, on the surface auto nv = hit_obj.normal_vector(hit_point); @@ -41,11 +46,16 @@ bool material_diffuse_simple::scatter(ray3d &r, const object &hit_obj, double hi return true; } -material_diffuse_hemispherical::material_diffuse_hemispherical(double albedo) : albedo(albedo) { +material_diffuse_simple::material_diffuse_simple(double albedo) : albedo{albedo, albedo, albedo} { assert(albedo >= 0); assert(albedo <= 1); } +material_diffuse_hemispherical::material_diffuse_hemispherical(vec3d albedo) : albedo(albedo) { + assert(albedo.mod2() >= 0); + assert(albedo.mod2() <= 1); +} + bool material_diffuse_hemispherical::scatter(ray3d &r, const object &hit_obj, double hit_t, random_uv_gen_3d &ruvg) const { const auto hit_point = r.at(hit_t); // hit point, on the surface @@ -59,3 +69,8 @@ material_diffuse_hemispherical::scatter(ray3d &r, const object &hit_obj, double r.direction((diffuse_target - hit_point).unit_vec()); // the new diffused ray we trace on return true; } + +material_diffuse_hemispherical::material_diffuse_hemispherical(double albedo) : albedo{albedo, albedo, albedo} { + assert(albedo >= 0); + assert(albedo <= 1); +} diff --git a/material.h b/material.h index a1d03db..b839cc9 100644 --- a/material.h +++ b/material.h @@ -22,24 +22,27 @@ public: }; class material_diffuse_lambertian : public material { - double albedo; + vec3d albedo; public: + explicit material_diffuse_lambertian(vec3d albedo); explicit material_diffuse_lambertian(double albedo); bool scatter(ray3d &r, const object &hit_obj, double hit_t, random_uv_gen_3d &ruvg) const override; }; class material_diffuse_simple : public material { - double albedo; + vec3d albedo; public: + explicit material_diffuse_simple(vec3d albedo); explicit material_diffuse_simple(double albedo); bool scatter(ray3d &r, const object &hit_obj, double hit_t, random_uv_gen_3d &ruvg) const override; }; class material_diffuse_hemispherical : public material { - double albedo; + vec3d albedo; public: + explicit material_diffuse_hemispherical(vec3d albedo); explicit material_diffuse_hemispherical(double albedo); bool scatter(ray3d &r, const object &hit_obj, double hit_t, random_uv_gen_3d &ruvg) const override; diff --git a/ray.h b/ray.h index 51a3da1..11baa30 100644 --- a/ray.h +++ b/ray.h @@ -13,7 +13,7 @@ template class ray3 { vec3 source_; vec3 direction_; // unit vector - double decay_; // How much power remaining + vec3d decay_; // How much power remaining public: ~ray3() = default; @@ -30,7 +30,7 @@ public: } ray3(const vec3 &source, const vec3 &direction) : - source_(source), direction_(direction.unit_vec()), decay_(1.0) {} + source_(source), direction_(direction.unit_vec()), decay_{vec3d::one()} {} // Get the source point from where the ray emits. vec3 source() const { @@ -65,11 +65,11 @@ public: return decay_ * color; } - void decay(double a) { - decay_ *= a; + void decay(const vec3d &a) { + decay_ = decay_.scale(a); } - double decay() const { + vec3d decay() const { return decay_; } diff --git a/vec.h b/vec.h index 5050065..99004d6 100644 --- a/vec.h +++ b/vec.h @@ -36,12 +36,20 @@ struct vec3 { return vec3{0, 0, 0}; } + static vec3 one() { + return vec3{1, 1, 1}; + } + bool is_zero() const { #define EPS (1e-8) return x >= -EPS && y >= -EPS && z >= -EPS && x <= EPS && y <= EPS && z <= EPS; #undef EPS } + bool is_one() const { + return (*this - vec3::one()).is_zero(); + } + vec3 operator+(const vec3 &b) const { return vec3{.x=x + b.x, .y=y + b.y, .z=z + b.z}; } @@ -68,6 +76,11 @@ struct vec3 { return vec3{.x=y * b.z - z * b.y, .y=x * b.z - z * b.x, .z=x * b.y - y * b.x}; } + // Multiply with b on every dimension. + vec3 scale(const vec3 &b) const { + return vec3{.x=x * b.x, .y=y * b.y, .z=z * b.z}; + } + // norm value double norm(const int level = 2) const { if (level == 2) { -- cgit v1.2.3