]> code.bitgloo.com Git - clyne/raytracer.git/commitdiff
abstract objects
authorClyne Sullivan <clyne@bitgloo.com>
Thu, 16 May 2024 12:03:42 +0000 (08:03 -0400)
committerClyne Sullivan <clyne@bitgloo.com>
Thu, 16 May 2024 12:03:42 +0000 (08:03 -0400)
main.cpp
object.h [new file with mode: 0644]
sphere.h
world.h

index 00818289c48e9a2fc1fe5a27c6f4d142cb76171d..6fecf204fdf6a7c2e3b8ed27cc93855e0c263db1 100644 (file)
--- 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<double> 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<Object>& 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<Sphere>(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<Object>& o)
 {
     const auto idx = std::to_string(index);
 
     ImGui::SetNextItemWidth(200);
-    ImGui::Combo((std::string("mat") + idx).c_str(), reinterpret_cast<int *>(&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<int *>(&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<Sphere>(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 (file)
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 <optional>
+#include <tuple>
+
+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<color, ray> scatter(const ray& r, double root) const = 0;
+    virtual std::optional<double> hit(const ray& r, double tmin, double tmax) const = 0;
+};
+
+#endif // OBJECT_H
+
index 3cb2c8ced88993d0885fd09d2406cb1d66095b64..61d6de21a7098f772a359e3310cbc6bd01ec9c42 100644 (file)
--- 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"
 
 #include <optional>
 #include <tuple>
 
-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<color, ray> scatter(const ray& r, double root) const {
+    Sphere(point3 center_, double radius_, Material M_, color tint_):
+        Object(center_, M_, tint_), radius(radius_) {}
+
+    std::pair<color, ray> 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<double> hit(const ray& r, double tmin, double tmax) const {
+    std::optional<double> 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 4e01bcf764bbfd1ff6d49c9182bd07d8911f94d2..9723b78f9a9c48f5c14313d671dc4615a802b30a 100644 (file)
--- a/world.h
+++ b/world.h
@@ -4,26 +4,28 @@
 #include "sphere.h"
 
 #include <limits>
+#include <memory>
 #include <optional>
 #include <tuple>
 #include <vector>
 
 struct World
 {
-    std::vector<Sphere> objects;
+    std::vector<std::unique_ptr<Object>> objects;
 
+    template<class T>
     void add(auto&&... args) {
-        objects.emplace_back(args...);
+        objects.emplace_back(new T(args...));
     }
 
-    std::optional<std::pair<double, Sphere>> hit(const ray& r) const {
+    std::optional<std::pair<double, Object *>> hit(const ray& r) const {
         double closest = std::numeric_limits<double>::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();
             }
         }