move classes to headers
parent
8a8fab0c68
commit
af1740bde3
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef RANDOM_H
|
||||||
|
#define RANDOM_H
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
inline double randomN()
|
||||||
|
{
|
||||||
|
static std::uniform_real_distribution<double> distribution (0.0, 1.0);
|
||||||
|
static std::mt19937 generator;
|
||||||
|
return distribution(generator);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // RANDOM_H
|
||||||
|
|
@ -0,0 +1,80 @@
|
|||||||
|
#ifndef SPHERE_H
|
||||||
|
#define SPHERE_H
|
||||||
|
|
||||||
|
#include "color.h"
|
||||||
|
#include "ray.h"
|
||||||
|
#include "vec3.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <optional>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
enum class Material : int {
|
||||||
|
Lambertian,
|
||||||
|
Metal,
|
||||||
|
Dielectric
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Sphere
|
||||||
|
{
|
||||||
|
point3 center;
|
||||||
|
double radius;
|
||||||
|
Material M;
|
||||||
|
color tint;
|
||||||
|
|
||||||
|
std::pair<color, ray> scatter(const ray& r, double root) const {
|
||||||
|
const auto p = r.at(root);
|
||||||
|
auto normal = (p - center) / radius;
|
||||||
|
|
||||||
|
if (M == Material::Lambertian) {
|
||||||
|
return {tint, ray(p, normal + randomUnitSphere())};
|
||||||
|
} else if (M == Material::Metal) {
|
||||||
|
return {tint, ray(p, r.direction().reflect(normal))};
|
||||||
|
} else if (M == Material::Dielectric) {
|
||||||
|
constexpr auto index = 1.0 / 1.33;
|
||||||
|
|
||||||
|
const bool front = r.direction().dot(normal) < 0;
|
||||||
|
const auto ri = front ? 1.0 / index : index;
|
||||||
|
if (!front)
|
||||||
|
normal *= -1;
|
||||||
|
|
||||||
|
const auto dir = r.direction().normalize();
|
||||||
|
const double costh = std::fmin((-dir).dot(normal), 1);
|
||||||
|
const double sinth = std::sqrt(1 - costh * costh);
|
||||||
|
|
||||||
|
if (ri * sinth > 1)
|
||||||
|
return {color(1, 1, 1), ray(p, dir.reflect(normal))};
|
||||||
|
else
|
||||||
|
return {color(1, 1, 1), ray(p, dir.refract(normal, ri))};
|
||||||
|
} else {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<double> hit(const ray& r, double tmin, double tmax) const {
|
||||||
|
const vec3 oc = center - r.origin();
|
||||||
|
const auto a = r.direction().length_squared();
|
||||||
|
const auto h = r.direction().dot(oc);
|
||||||
|
const auto c = oc.length_squared() - radius * radius;
|
||||||
|
const auto discriminant = h * h - a * c;
|
||||||
|
|
||||||
|
if (discriminant < 0) {
|
||||||
|
return {}; // No hit
|
||||||
|
} else {
|
||||||
|
const auto sqrtd = std::sqrt(discriminant);
|
||||||
|
|
||||||
|
// Find the nearest root that lies in the acceptable range.
|
||||||
|
auto root = (h - sqrtd) / a;
|
||||||
|
if (root <= tmin || tmax <= root) {
|
||||||
|
root = (h + sqrtd) / a;
|
||||||
|
if (root <= tmin || tmax <= root)
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SPHERE_H
|
||||||
|
|
@ -0,0 +1,64 @@
|
|||||||
|
#ifndef VIEW_H
|
||||||
|
#define VIEW_H
|
||||||
|
|
||||||
|
#include "random.h"
|
||||||
|
#include "vec3.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
struct View
|
||||||
|
{
|
||||||
|
static constexpr auto lookat = point3(0, 0, -1); // Point camera is looking at
|
||||||
|
static constexpr auto vup = vec3(0, 1, 0); // Camera-relative "up" direction
|
||||||
|
|
||||||
|
float fieldOfView = 90.f;
|
||||||
|
float focalLength;
|
||||||
|
float viewportHeight;
|
||||||
|
float viewportWidth;
|
||||||
|
|
||||||
|
point3 camera;
|
||||||
|
vec3 viewportX;
|
||||||
|
vec3 viewportY;
|
||||||
|
vec3 pixelDX;
|
||||||
|
vec3 pixelDY;
|
||||||
|
vec3 viewportUL;
|
||||||
|
vec3 pixelUL;
|
||||||
|
|
||||||
|
View() {
|
||||||
|
recalculate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void recalculate() {
|
||||||
|
focalLength = (camera - lookat).length();
|
||||||
|
viewportHeight = 2 * std::tan(fieldOfView * 3.14159265 / 180.0 / 2.0) * focalLength;
|
||||||
|
viewportWidth = viewportHeight * Aspect;
|
||||||
|
|
||||||
|
const auto w = (camera - lookat).normalize();
|
||||||
|
const auto u = cross(vup, w).normalize();
|
||||||
|
const auto v = cross(w, u);
|
||||||
|
|
||||||
|
viewportX = viewportWidth * u;
|
||||||
|
viewportY = -viewportHeight * v;
|
||||||
|
|
||||||
|
pixelDX = viewportX / Width;
|
||||||
|
pixelDY = viewportY / Height;
|
||||||
|
viewportUL = camera - focalLength * w - viewportX / 2 - viewportY / 2;
|
||||||
|
pixelUL = viewportUL + 0.5 * (pixelDX + pixelDY);
|
||||||
|
}
|
||||||
|
|
||||||
|
ray getRay(int x, int y, bool addRandom = false) const {
|
||||||
|
double X = x;
|
||||||
|
double Y = y;
|
||||||
|
|
||||||
|
if (addRandom) {
|
||||||
|
X += randomN() - 0.5;
|
||||||
|
Y += randomN() - 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pixel = pixelUL + X * pixelDX + Y * pixelDY;
|
||||||
|
return ray(camera, pixel - camera);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VIEW_H
|
||||||
|
|
@ -0,0 +1,38 @@
|
|||||||
|
#ifndef WORLD_H
|
||||||
|
#define WORLD_H
|
||||||
|
|
||||||
|
#include "sphere.h"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
#include <optional>
|
||||||
|
#include <tuple>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
struct World
|
||||||
|
{
|
||||||
|
std::vector<Sphere> objects;
|
||||||
|
|
||||||
|
void add(auto&&... args) {
|
||||||
|
objects.emplace_back(args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::pair<double, Sphere>> hit(const ray& r) const {
|
||||||
|
double closest = std::numeric_limits<double>::infinity();
|
||||||
|
Sphere sphere;
|
||||||
|
|
||||||
|
for (const auto& o : objects) {
|
||||||
|
if (auto t = o.hit(r, 0.001, closest); t) {
|
||||||
|
closest = *t;
|
||||||
|
sphere = o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (closest != std::numeric_limits<double>::infinity())
|
||||||
|
return std::pair {closest, sphere};
|
||||||
|
else
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // WORLD_H
|
||||||
|
|
Loading…
Reference in New Issue