From fdc2d91285cd9548a3c95f1bdfb75c70ccfffff6 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Thu, 16 May 2024 08:03:42 -0400 Subject: [PATCH] abstract objects --- main.cpp | 30 +++++++++++++++--------------- object.h | 32 ++++++++++++++++++++++++++++++++ sphere.h | 20 +++++++------------- world.h | 14 ++++++++------ 4 files changed, 62 insertions(+), 34 deletions(-) create mode 100644 object.h diff --git a/main.cpp b/main.cpp index 0081828..6fecf20 100644 --- a/main.cpp +++ b/main.cpp @@ -3,9 +3,9 @@ constexpr double Aspect = 16.0 / 9.0; constexpr unsigned Height = Width / Aspect; #include "color.h" +#include "object.h" #include "ray.h" #include "renderer.h" -#include "sphere.h" #include "vec3.h" #include "view.h" #include "world.h" @@ -36,7 +36,7 @@ static std::chrono::duration renderTime; static color ray_color(const ray& r, int depth = 50); static void initiateRender(SDL_Surface *canvas); -static void showObjectControls(int index, Sphere& o); +static void showObjectControls(int index, std::unique_ptr& o); static void addRandomObject(); static void preview(SDL_Surface *canvas); @@ -52,7 +52,7 @@ int main() ImGui_ImplSDL2_InitForSDLRenderer(window, painter); ImGui_ImplSDLRenderer2_Init(painter); - world.add(point3(0.00, -100.50, -1.0), 100.0, + world.add(point3(0.00, -100.50, -1.0), 100.0, Material::Lambertian, color(0.5, 1.0, 0.5)); for (auto i : std::views::iota(0, 10)) addRandomObject(); @@ -173,8 +173,8 @@ color ray_color(const ray& r, int depth) return {}; if (auto hit = world.hit(r); hit) { - const auto& [closest, sphere] = *hit; - const auto [atten, scat] = sphere.scatter(r, closest); + const auto& [closest, object] = *hit; + const auto [atten, scat] = object->scatter(r, closest); return atten * ray_color(scat, depth - 1); } else { const auto unitDir = r.direction().normalize(); @@ -202,25 +202,25 @@ void initiateRender(SDL_Surface *canvas) (uint32_t *)canvas->pixels)); } -void showObjectControls(int index, Sphere& o) +void showObjectControls(int index, std::unique_ptr& o) { const auto idx = std::to_string(index); ImGui::SetNextItemWidth(200); - ImGui::Combo((std::string("mat") + idx).c_str(), reinterpret_cast(&o.M), - "Lambertian\0Metal\0Dielectric\0"); - ImGui::SameLine(); ImGui::SetNextItemWidth(100); - ImGui::InputDouble((std::string("radius") + idx).c_str(), - &o.radius, 0.1, 0.05, "%.2lf"); + ImGui::Combo((std::string("mat") + idx).c_str(), + reinterpret_cast(&o->M), "Lambertian\0Metal\0Dielectric\0"); + //ImGui::SameLine(); ImGui::SetNextItemWidth(100); + //ImGui::InputDouble((std::string("radius") + idx).c_str(), + // &o->radius, 0.1, 0.05, "%.2lf"); ImGui::SetNextItemWidth(100); ImGui::InputDouble((std::string("x") + idx).c_str(), - &o.center.x(), 0.05, 0.05, "%.2lf"); + &o->center.x(), 0.05, 0.05, "%.2lf"); ImGui::SameLine(); ImGui::SetNextItemWidth(100); ImGui::InputDouble((std::string("y") + idx).c_str(), - &o.center.y(), 0.1, 0.05, "%.2lf"); + &o->center.y(), 0.1, 0.05, "%.2lf"); ImGui::SameLine(); ImGui::SetNextItemWidth(100); ImGui::InputDouble((std::string("z") + idx).c_str(), - &o.center.z(), 0.1, 0.05, "%.2lf"); + &o->center.z(), 0.1, 0.05, "%.2lf"); } void addRandomObject() @@ -228,7 +228,7 @@ void addRandomObject() const point3 pos = vec3::random() * vec3(6, 0.8, 3) - vec3(3, 0, 3.8); const color col = vec3::random(); const auto mat = (int)(randomN() * (int)Material::Undefined); - world.add(pos, randomN() * 0.3 + 0.05, (Material)mat, col); + world.add(pos, randomN() * 0.3 + 0.05, (Material)mat, col); } void preview(SDL_Surface *canvas) diff --git a/object.h b/object.h new file mode 100644 index 0000000..5db620e --- /dev/null +++ b/object.h @@ -0,0 +1,32 @@ +#ifndef OBJECT_H +#define OBJECT_H + +#include "color.h" +#include "ray.h" +#include "vec3.h" + +#include +#include + +enum class Material : int { + Lambertian = 0, + Metal, + Dielectric, + Undefined +}; + +struct Object +{ + point3 center; + Material M; + color tint; + + Object(point3 center_, Material M_, color tint_): + center(center_), M(M_), tint(tint_) {} + + virtual std::pair scatter(const ray& r, double root) const = 0; + virtual std::optional hit(const ray& r, double tmin, double tmax) const = 0; +}; + +#endif // OBJECT_H + diff --git a/sphere.h b/sphere.h index 3cb2c8c..61d6de2 100644 --- a/sphere.h +++ b/sphere.h @@ -2,6 +2,7 @@ #define SPHERE_H #include "color.h" +#include "object.h" #include "ray.h" #include "vec3.h" @@ -9,21 +10,14 @@ #include #include -enum class Material : int { - Lambertian = 0, - Metal, - Dielectric, - Undefined -}; - -struct Sphere +struct Sphere : public Object { - point3 center; double radius; - Material M; - color tint; - std::pair scatter(const ray& r, double root) const { + Sphere(point3 center_, double radius_, Material M_, color tint_): + Object(center_, M_, tint_), radius(radius_) {} + + std::pair scatter(const ray& r, double root) const override { const auto p = r.at(root); auto normal = (p - center) / radius; @@ -52,7 +46,7 @@ struct Sphere } } - std::optional hit(const ray& r, double tmin, double tmax) const { + std::optional hit(const ray& r, double tmin, double tmax) const override { const vec3 oc = center - r.origin(); const auto a = r.direction().length_squared(); const auto h = r.direction().dot(oc); diff --git a/world.h b/world.h index 4e01bcf..9723b78 100644 --- a/world.h +++ b/world.h @@ -4,26 +4,28 @@ #include "sphere.h" #include +#include #include #include #include struct World { - std::vector objects; + std::vector> objects; + template void add(auto&&... args) { - objects.emplace_back(args...); + objects.emplace_back(new T(args...)); } - std::optional> hit(const ray& r) const { + std::optional> hit(const ray& r) const { double closest = std::numeric_limits::infinity(); - Sphere sphere; + Object *sphere; for (const auto& o : objects) { - if (auto t = o.hit(r, 0.001, closest); t) { + if (auto t = o->hit(r, 0.001, closest); t) { closest = *t; - sphere = o; + sphere = o.get(); } }