From a97b38299d5f8297d15077160df5439d274bd571 Mon Sep 17 00:00:00 2001 From: Keuin Date: Tue, 12 Apr 2022 11:01:32 +0800 Subject: Make object::hit provides hit time t. Visualize normal vector at hit point. Add pixel::from_normalized(const vec3d&) for visualizing normal vector. --- bitmap.h | 7 ++++++- main_simple_scanner.cpp | 31 +++++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/bitmap.h b/bitmap.h index 31b9053..09f3711 100644 --- a/bitmap.h +++ b/bitmap.h @@ -31,10 +31,15 @@ struct pixel { * Create a pixel with given depth, from normalized color values. * For example: for 8bit pixel, with (1, 0.5, 0.25), we get: (255, 127, 63). */ - static pixel from_normalized(double r, double g, double b) { + static inline pixel from_normalized(double r, double g, double b) { const auto mod = (1ULL << (sizeof(T) * 8U)) - 1ULL; return pixel{.r = (T) (mod * r), .g = (T) (mod * g), .b = (T) (mod * b)}; } + + // v3d must be a normalized vector + static inline pixel from_normalized(const vec3d &v3d) { + return from_normalized(v3d.x / 2.0 + 0.5, v3d.y / 2.0 + 0.5, v3d.z / 2.0 + 0.5); + } }; // Mix two colors a and b. Returns a*u + b*v diff --git a/main_simple_scanner.cpp b/main_simple_scanner.cpp index 7279e12..e57ef03 100644 --- a/main_simple_scanner.cpp +++ b/main_simple_scanner.cpp @@ -17,8 +17,11 @@ class object { public: - // Will the given ray hit. - virtual bool hit(const ray3d &r) const = 0; + // Will the given ray hit. Returns time t if hits. + virtual bool hit(const ray3d &r, double &t) const = 0; + + // Given a point on the surface, returns the normalized normal vector on that point. + virtual vec3d normal_vector(const vec3d &where) const = 0; // object color, currently not parameterized virtual pixel8b color() const = 0; @@ -38,7 +41,12 @@ public: ~sphere() override = default; - bool hit(const ray3d &r) const override { + vec3d normal_vector(const vec3d &where) const override { + // We assume the point is on surface, speeding up the normalization + return (where - center) / radius; + } + + bool hit(const ray3d &r, double &t) const override { // Ray: {Source, Direction, time} // Sphere: {Center, radius} // sphere hit formula: |Source + Direction * time - Center| = radius @@ -51,7 +59,13 @@ public: const auto rel_src = r.source() - center; // relative position of ray source // C = (S - C) dot (S - C) - radius^2 const double c = dot(rel_src, rel_src) - radius * radius; - return b * b - 4 * a * c >= 0; + const auto delta = b * b - 4 * a * c; + const auto hit = delta >= 0; + if (hit) { + // the smaller root is the first point the ray hits, so return that one + t = (-b - sqrt(delta)) / (2.0 * a); + } + return hit; } pixel8b color() const override { @@ -67,9 +81,14 @@ class viewport { // Given a ray from the camera, generate a color the camera seen on the viewport. pixel8b color(const ray3d &r) { // Detect hits + double hit_t; for (const auto &obj: objects) { - if (obj->hit(r)) { - return obj->color(); + if (obj->hit(r, hit_t)) { + // normal vector on hit point + const auto nv = obj->normal_vector(r.at(hit_t)); +// return obj->color(); + // visualize normal vector at hit point + return pixel8b::from_normalized(nv); } } -- cgit v1.2.3