From 403ea4bb9fdd18f09d4ba38086e7bd2374220f62 Mon Sep 17 00:00:00 2001 From: Keuin Date: Tue, 12 Apr 2022 10:17:14 +0800 Subject: Add basic object hit rendering. Add NOPRINT environ switch. Add demo sphere rendering. --- main_simple_scanner.cpp | 84 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 77 insertions(+), 7 deletions(-) diff --git a/main_simple_scanner.cpp b/main_simple_scanner.cpp index 103cfab..bc4e279 100644 --- a/main_simple_scanner.cpp +++ b/main_simple_scanner.cpp @@ -4,19 +4,76 @@ #include #include +#include +#include +#include #include "vec.h" #include "ray.h" #include "bitmap.h" #include "timer.h" +#define DEMO_BALL + +class object { +public: + // Will the given ray hit. + virtual bool hit(const ray3d &r) const = 0; + + // object color, currently not parameterized + virtual pixel8b color() const = 0; + + // subclasses must have virtual destructors + virtual ~object() = default; +}; + +class sphere : public object { + vec3d center; + double radius; + +public: + sphere() = delete; + + sphere(const vec3d ¢er, double radius) : center(center), radius(radius) {} + + ~sphere() override = default; + + bool hit(const ray3d &r) const override { + // Ray: {Source, Direction, time} + // Sphere: {Center, radius} + // sphere hit formula: |Source + Direction * time - Center| = radius + // |(Sx + Dx * t - Cx, Sy + Dy * t - Cy, Sz + Dz * t - Cz)| = radius + + // A = D dot D + const double a = dot(r.direction(), r.direction()); + // B = 2(S - C) dot D + const double b = 2 * dot(r.source() - center, r.direction()); + 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; + } + + pixel8b color() const override { + return pixel8b::from_normalized(1.0, 0.0, 0.0); + } +}; class viewport { double half_width, half_height; // viewport size vec3d center; // coordinate of the viewport center point + std::vector> objects; // Given a ray from the camera, generate a color the camera seen on the viewport. - static pixel8b color(const ray3d &r) { + pixel8b color(const ray3d &r) { + // Detect hits + for (const auto &obj: objects) { + if (obj->hit(r)) { + return obj->color(); + } + } + + // Does not hit anything. Get background color (infinity) const auto u = (r.direction().y + 1.0) * 0.5; return mix( pixel8b::from_normalized(1.0, 1.0, 1.0), @@ -32,6 +89,11 @@ public: viewport(double width, double height, vec3d viewport_center) : half_width(width / 2.0), half_height(height / 2.0), center(viewport_center) {} + // Add an object to the world. + void add_object(std::unique_ptr &&obj) { + objects.push_back(std::move(obj)); + } + // Generate the image seen on given viewpoint. bitmap8b render(vec3d viewpoint, uint16_t image_width, uint16_t image_height) { bitmap8b image{image_width, image_height}; @@ -55,22 +117,30 @@ public: } }; -void generate_image(uint16_t image_width, uint16_t image_height, double viewport_width, double focal_length) { +void generate_image(uint16_t image_width, uint16_t image_height, double viewport_width, double focal_length, + double sphere_z, double sphere_r) { double r = 1.0 * image_width / image_height; viewport vp{viewport_width, viewport_width / r, vec3d{0, 0, -focal_length}}; + vp.add_object(std::unique_ptr{new sphere{vec3d{0, 0, sphere_z}, sphere_r}}); timer tm; tm.start_measure(); const auto image = vp.render(vec3d::zero(), image_width, image_height); // camera position as the coordinate origin tm.stop_measure(); - image.write_plain_ppm(std::cout); + if (!std::getenv("NOPRINT")) { + image.write_plain_ppm(std::cout); + } else { + std::cerr << "NOPRINT is defined. PPM Image won't be printed." << std::endl; + } } int main(int argc, char **argv) { - if (argc != 5) { - printf("Usage: %s \n", argv[0]); + if (argc != 7) { + printf("Usage: %s \n", + argv[0]); return 0; } - std::string iw{argv[1]}, ih{argv[2]}, vw{argv[3]}, fl{argv[4]}; + std::string iw{argv[1]}, ih{argv[2]}, vw{argv[3]}, fl{argv[4]}, sz{argv[5]}, sr{argv[6]}; generate_image(std::stoul(iw), std::stoul(ih), - std::stod(vw), std::stod(fl)); + std::stod(vw), std::stod(fl), + std::stod(sz), std::stod(sr)); } \ No newline at end of file -- cgit v1.2.3