2023-12-23 22:56:27 +01:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <array>
|
|
|
|
|
#include <cassert>
|
|
|
|
|
#include <cmath>
|
2023-12-27 17:23:35 +01:00
|
|
|
#include <cstddef>
|
2023-12-23 22:56:27 +01:00
|
|
|
#include <ostream>
|
|
|
|
|
|
2023-12-27 20:14:29 +01:00
|
|
|
#include "raytracer.h"
|
|
|
|
|
|
2023-12-23 22:56:27 +01:00
|
|
|
class Vec3 {
|
|
|
|
|
public:
|
|
|
|
|
static const Vec3 e_x;
|
|
|
|
|
static const Vec3 e_y;
|
|
|
|
|
static const Vec3 e_z;
|
|
|
|
|
|
2023-12-27 20:14:29 +01:00
|
|
|
constexpr Vec3(f64 x, f64 y, f64 z) : xyz_{x, y, z} {}
|
2023-12-23 22:56:27 +01:00
|
|
|
constexpr Vec3() : Vec3{0, 0, 0} {}
|
|
|
|
|
|
2023-12-27 20:14:29 +01:00
|
|
|
constexpr f64& x() { return xyz_[0]; }
|
|
|
|
|
constexpr f64& y() { return xyz_[1]; }
|
|
|
|
|
constexpr f64& z() { return xyz_[2]; }
|
2023-12-23 22:56:27 +01:00
|
|
|
|
2023-12-27 20:14:29 +01:00
|
|
|
constexpr f64 x() const { return xyz_[0]; }
|
|
|
|
|
constexpr f64 y() const { return xyz_[1]; }
|
|
|
|
|
constexpr f64 z() const { return xyz_[2]; }
|
2023-12-23 22:56:27 +01:00
|
|
|
|
|
|
|
|
constexpr Vec3 operator-() const { return Vec3{-x(), -y(), -z()}; }
|
|
|
|
|
|
2023-12-27 20:14:29 +01:00
|
|
|
constexpr f64& operator[](std::size_t i) {
|
2023-12-23 22:56:27 +01:00
|
|
|
assert(i <= 3);
|
|
|
|
|
return xyz_[i];
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-27 20:14:29 +01:00
|
|
|
constexpr f64 operator[](std::size_t i) const {
|
2023-12-23 22:56:27 +01:00
|
|
|
assert(i <= 3);
|
|
|
|
|
return xyz_[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constexpr Vec3& operator+=(const Vec3& v) {
|
|
|
|
|
x() += v.x();
|
|
|
|
|
y() += v.y();
|
|
|
|
|
z() += v.z();
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-27 20:14:29 +01:00
|
|
|
constexpr Vec3& operator*=(f64 t) {
|
2023-12-23 22:56:27 +01:00
|
|
|
x() *= t;
|
|
|
|
|
y() *= t;
|
|
|
|
|
z() *= t;
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-27 20:14:29 +01:00
|
|
|
constexpr Vec3& operator/=(f64 t) {
|
2023-12-23 22:56:27 +01:00
|
|
|
*this *= 1 / t;
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-30 12:37:27 +01:00
|
|
|
constexpr bool almost_zero() const {
|
|
|
|
|
f64 eps = 1e-8;
|
|
|
|
|
|
|
|
|
|
return std::fabs(x()) < eps && std::fabs(y()) < eps && std::fabs(z()) < eps;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-30 14:01:45 +01:00
|
|
|
constexpr f64 squared() const;
|
2023-12-23 22:56:27 +01:00
|
|
|
|
2023-12-30 14:01:45 +01:00
|
|
|
constexpr f64 norm() const;
|
2023-12-23 22:56:27 +01:00
|
|
|
|
2023-12-30 14:01:45 +01:00
|
|
|
constexpr Vec3 normed() const;
|
|
|
|
|
|
|
|
|
|
constexpr Vec3 reflect(Vec3 normal) const;
|
2023-12-23 22:56:27 +01:00
|
|
|
|
2023-12-31 00:28:45 +01:00
|
|
|
constexpr Vec3 refract(Vec3 normal, f64 eta) const;
|
|
|
|
|
|
2023-12-23 22:56:27 +01:00
|
|
|
private:
|
2023-12-27 20:14:29 +01:00
|
|
|
std::array<f64, 3> xyz_;
|
2023-12-23 22:56:27 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
constexpr Vec3 Vec3::e_x{1.0, 0.0, 0.0};
|
|
|
|
|
constexpr Vec3 Vec3::e_y{0.0, 1.0, 0.0};
|
|
|
|
|
constexpr Vec3 Vec3::e_z{0.0, 0.0, 1.0};
|
|
|
|
|
|
|
|
|
|
using Point3 = Vec3;
|
|
|
|
|
|
|
|
|
|
constexpr std::ostream& operator<<(std::ostream& out, const Vec3& v) {
|
|
|
|
|
return out << v.x() << ' ' << v.y() << ' ' << v.z();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constexpr Vec3 operator+(const Vec3& u, const Vec3& v) {
|
|
|
|
|
Vec3 out = u;
|
|
|
|
|
out += v;
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-31 00:28:45 +01:00
|
|
|
constexpr Vec3 operator-(const Vec3& u, const Vec3& v) {
|
|
|
|
|
return u + (-v);
|
|
|
|
|
}
|
2023-12-23 22:56:27 +01:00
|
|
|
|
|
|
|
|
constexpr Vec3 operator*(const Vec3& u, const Vec3& v) {
|
|
|
|
|
return {u.x() * v.x(), u.y() * v.y(), u.z() * v.z()};
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-27 20:14:29 +01:00
|
|
|
constexpr Vec3 operator*(f64 t, const Vec3& v) {
|
2023-12-23 22:56:27 +01:00
|
|
|
Vec3 out = v;
|
|
|
|
|
out *= t;
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-31 00:28:45 +01:00
|
|
|
constexpr Vec3 operator/(const Vec3& v, f64 t) {
|
|
|
|
|
return (1 / t) * v;
|
|
|
|
|
}
|
2023-12-23 22:56:27 +01:00
|
|
|
|
2023-12-27 20:14:29 +01:00
|
|
|
constexpr f64 dot(const Vec3& u, const Vec3& v) {
|
2023-12-23 22:56:27 +01:00
|
|
|
Vec3 tmp = u * v;
|
|
|
|
|
return tmp.x() + tmp.y() + tmp.z();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constexpr Vec3 cross(const Vec3& u, const Vec3& v) {
|
|
|
|
|
return {u.y() * v.z() - u.z() - v.y(), u.z() * v.x() - u.x() * v.z(),
|
|
|
|
|
u.x() * v.y() - u.y() - v.x()};
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-31 00:28:45 +01:00
|
|
|
constexpr f64 Vec3::squared() const {
|
|
|
|
|
return dot(*this, *this);
|
|
|
|
|
}
|
2023-12-30 14:01:45 +01:00
|
|
|
|
2023-12-31 00:28:45 +01:00
|
|
|
constexpr f64 Vec3::norm() const {
|
|
|
|
|
return std::sqrt(squared());
|
|
|
|
|
}
|
2023-12-30 14:01:45 +01:00
|
|
|
|
2023-12-31 00:28:45 +01:00
|
|
|
constexpr Vec3 Vec3::normed() const {
|
|
|
|
|
return *this / norm();
|
|
|
|
|
}
|
2023-12-30 14:01:45 +01:00
|
|
|
|
2023-12-31 00:28:45 +01:00
|
|
|
constexpr Vec3 Vec3::reflect(Vec3 normal) const {
|
|
|
|
|
return *this - 2 * dot(*this, normal) * normal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constexpr Vec3 Vec3::refract(Vec3 normal, f64 eta) const {
|
|
|
|
|
f64 cos_theta = dot(-*this, normal);
|
|
|
|
|
|
|
|
|
|
Vec3 out_orth = eta * (*this + cos_theta * normal);
|
|
|
|
|
Vec3 out_par = -std::sqrt(std::fabs(1.0 - out_orth.squared())) * normal;
|
|
|
|
|
|
|
|
|
|
return out_orth + out_par;
|
|
|
|
|
}
|