abstract objects

main
Clyne 5 months ago
parent 549fe1388c
commit fdc2d91285
Signed by: clyne
GPG Key ID: 1B74EE6C49C96795

@ -3,9 +3,9 @@ constexpr double Aspect = 16.0 / 9.0;
constexpr unsigned Height = Width / Aspect; constexpr unsigned Height = Width / Aspect;
#include "color.h" #include "color.h"
#include "object.h"
#include "ray.h" #include "ray.h"
#include "renderer.h" #include "renderer.h"
#include "sphere.h"
#include "vec3.h" #include "vec3.h"
#include "view.h" #include "view.h"
#include "world.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 color ray_color(const ray& r, int depth = 50);
static void initiateRender(SDL_Surface *canvas); 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 addRandomObject();
static void preview(SDL_Surface *canvas); static void preview(SDL_Surface *canvas);
@ -52,7 +52,7 @@ int main()
ImGui_ImplSDL2_InitForSDLRenderer(window, painter); ImGui_ImplSDL2_InitForSDLRenderer(window, painter);
ImGui_ImplSDLRenderer2_Init(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)); Material::Lambertian, color(0.5, 1.0, 0.5));
for (auto i : std::views::iota(0, 10)) for (auto i : std::views::iota(0, 10))
addRandomObject(); addRandomObject();
@ -173,8 +173,8 @@ color ray_color(const ray& r, int depth)
return {}; return {};
if (auto hit = world.hit(r); hit) { if (auto hit = world.hit(r); hit) {
const auto& [closest, sphere] = *hit; const auto& [closest, object] = *hit;
const auto [atten, scat] = sphere.scatter(r, closest); const auto [atten, scat] = object->scatter(r, closest);
return atten * ray_color(scat, depth - 1); return atten * ray_color(scat, depth - 1);
} else { } else {
const auto unitDir = r.direction().normalize(); const auto unitDir = r.direction().normalize();
@ -202,25 +202,25 @@ void initiateRender(SDL_Surface *canvas)
(uint32_t *)canvas->pixels)); (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); const auto idx = std::to_string(index);
ImGui::SetNextItemWidth(200); ImGui::SetNextItemWidth(200);
ImGui::Combo((std::string("mat") + idx).c_str(), reinterpret_cast<int *>(&o.M), ImGui::Combo((std::string("mat") + idx).c_str(),
"Lambertian\0Metal\0Dielectric\0"); reinterpret_cast<int *>(&o->M), "Lambertian\0Metal\0Dielectric\0");
ImGui::SameLine(); ImGui::SetNextItemWidth(100); //ImGui::SameLine(); ImGui::SetNextItemWidth(100);
ImGui::InputDouble((std::string("radius") + idx).c_str(), //ImGui::InputDouble((std::string("radius") + idx).c_str(),
&o.radius, 0.1, 0.05, "%.2lf"); // &o->radius, 0.1, 0.05, "%.2lf");
ImGui::SetNextItemWidth(100); ImGui::SetNextItemWidth(100);
ImGui::InputDouble((std::string("x") + idx).c_str(), 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::SameLine(); ImGui::SetNextItemWidth(100);
ImGui::InputDouble((std::string("y") + idx).c_str(), 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::SameLine(); ImGui::SetNextItemWidth(100);
ImGui::InputDouble((std::string("z") + idx).c_str(), 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() void addRandomObject()
@ -228,7 +228,7 @@ void addRandomObject()
const point3 pos = vec3::random() * vec3(6, 0.8, 3) - vec3(3, 0, 3.8); const point3 pos = vec3::random() * vec3(6, 0.8, 3) - vec3(3, 0, 3.8);
const color col = vec3::random(); const color col = vec3::random();
const auto mat = (int)(randomN() * (int)Material::Undefined); 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) void preview(SDL_Surface *canvas)

@ -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

@ -2,6 +2,7 @@
#define SPHERE_H #define SPHERE_H
#include "color.h" #include "color.h"
#include "object.h"
#include "ray.h" #include "ray.h"
#include "vec3.h" #include "vec3.h"
@ -9,21 +10,14 @@
#include <optional> #include <optional>
#include <tuple> #include <tuple>
enum class Material : int { struct Sphere : public Object
Lambertian = 0,
Metal,
Dielectric,
Undefined
};
struct Sphere
{ {
point3 center;
double radius; 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); const auto p = r.at(root);
auto normal = (p - center) / radius; 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 vec3 oc = center - r.origin();
const auto a = r.direction().length_squared(); const auto a = r.direction().length_squared();
const auto h = r.direction().dot(oc); const auto h = r.direction().dot(oc);

@ -4,26 +4,28 @@
#include "sphere.h" #include "sphere.h"
#include <limits> #include <limits>
#include <memory>
#include <optional> #include <optional>
#include <tuple> #include <tuple>
#include <vector> #include <vector>
struct World struct World
{ {
std::vector<Sphere> objects; std::vector<std::unique_ptr<Object>> objects;
template<class T>
void add(auto&&... args) { 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(); double closest = std::numeric_limits<double>::infinity();
Sphere sphere; Object *sphere;
for (const auto& o : objects) { 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; closest = *t;
sphere = o; sphere = o.get();
} }
} }

Loading…
Cancel
Save