mirror of
https://github.com/MorizzG/ray-tracer.git
synced 2025-12-06 04:22:42 +00:00
finished 6.7
This commit is contained in:
parent
a3e1542250
commit
40951c3bbd
13 changed files with 188970 additions and 188753 deletions
51
src/camera.h
Normal file
51
src/camera.h
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ray.h"
|
||||||
|
#include "raytracer.h"
|
||||||
|
#include "vec3.h"
|
||||||
|
|
||||||
|
class Camera {
|
||||||
|
public:
|
||||||
|
constexpr Camera(Vec3 centre, u32 image_width, u32 image_height, double focal_length)
|
||||||
|
: centre_{centre} {
|
||||||
|
constexpr double viewport_height = 2.0;
|
||||||
|
double viewport_width = viewport_height * static_cast<double>(image_width) / image_height;
|
||||||
|
|
||||||
|
Vec3 u_viewport = viewport_width * Vec3::e_x;
|
||||||
|
Vec3 v_viewport = -viewport_height * Vec3::e_y;
|
||||||
|
|
||||||
|
d_u_pixel_ = u_viewport / image_width;
|
||||||
|
d_v_pixel_ = v_viewport / image_height;
|
||||||
|
|
||||||
|
// upper left of viewport: move from camera centre `focal_length` in z direction, then half
|
||||||
|
// of the viewport length in x and y direction respectively
|
||||||
|
auto viewport_upper_left =
|
||||||
|
centre_ - focal_length * Vec3::e_z - u_viewport / 2 - v_viewport / 2;
|
||||||
|
|
||||||
|
pixel_00_ = viewport_upper_left + 0.5 * d_u_pixel_ + 0.5 * d_v_pixel_;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr Vec3 centre() const { return centre_; }
|
||||||
|
|
||||||
|
constexpr Vec3 Image2World(u32 i, u32 j) const {
|
||||||
|
return pixel_00_ + i * d_u_pixel_ + j * d_v_pixel_;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr Ray CastRay(u32 i, u32 j) const {
|
||||||
|
auto pixel_centre = Image2World(i, j);
|
||||||
|
|
||||||
|
auto ray_direction = pixel_centre - centre();
|
||||||
|
|
||||||
|
return Ray{centre(), ray_direction};
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vec3 centre_;
|
||||||
|
|
||||||
|
// position of pixel 0, 0
|
||||||
|
Vec3 pixel_00_;
|
||||||
|
|
||||||
|
// Vec3 pointing from pixel to right/lower neighbour resp.
|
||||||
|
Vec3 d_u_pixel_;
|
||||||
|
Vec3 d_v_pixel_;
|
||||||
|
};
|
||||||
34
src/colour.h
34
src/colour.h
|
|
@ -3,9 +3,13 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <ios>
|
#include <ios>
|
||||||
|
#include <iostream>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "util.h"
|
#include "raytracer.h"
|
||||||
|
#include "vec3.h"
|
||||||
|
|
||||||
class Colour {
|
class Colour {
|
||||||
public:
|
public:
|
||||||
|
|
@ -19,6 +23,8 @@ class Colour {
|
||||||
assert(0.0 <= b && b <= 1.0);
|
assert(0.0 <= b && b <= 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr explicit Colour(Vec3 v) : Colour{v.x(), v.y(), v.z()} {}
|
||||||
|
|
||||||
constexpr double& r() { return r_; }
|
constexpr double& r() { return r_; }
|
||||||
constexpr double& g() { return g_; }
|
constexpr double& g() { return g_; }
|
||||||
constexpr double& b() { return b_; }
|
constexpr double& b() { return b_; }
|
||||||
|
|
@ -27,6 +33,18 @@ class Colour {
|
||||||
constexpr double g() const { return g_; }
|
constexpr double g() const { return g_; }
|
||||||
constexpr double b() const { return b_; }
|
constexpr double b() const { return b_; }
|
||||||
|
|
||||||
|
std::string to_string() const {
|
||||||
|
std::stringstream ss;
|
||||||
|
|
||||||
|
ss << '#';
|
||||||
|
|
||||||
|
ss << std::hex << std::setfill('0') << std::setw(2) << FToU8(r());
|
||||||
|
ss << std::hex << std::setfill('0') << std::setw(2) << FToU8(g());
|
||||||
|
ss << std::hex << std::setfill('0') << std::setw(2) << FToU8(b());
|
||||||
|
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
double r_;
|
double r_;
|
||||||
double g_;
|
double g_;
|
||||||
|
|
@ -35,20 +53,14 @@ class Colour {
|
||||||
|
|
||||||
constexpr Colour Colour::kBlack{0.0, 0.0, 0.0};
|
constexpr Colour Colour::kBlack{0.0, 0.0, 0.0};
|
||||||
|
|
||||||
constexpr Colour operator*(double t, Colour col) {
|
constexpr Colour operator*(double t, Colour col) { return {t * col.r(), t * col.g(), t * col.b()}; }
|
||||||
return {t * col.r(), t * col.g(), t * col.b()};
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Colour operator+(Colour c1, Colour c2) {
|
constexpr Colour operator+(Colour c1, Colour c2) {
|
||||||
return {c1.r() + c2.r(), c1.g() + c2.g(), c1.b() + c2.b()};
|
return {c1.r() + c2.r(), c1.g() + c2.g(), c1.b() + c2.b()};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::ostream& operator<<(std::ostream& out, Colour colour) {
|
inline std::ostream& operator<<(std::ostream& os, Colour colour) {
|
||||||
out << '#';
|
os << FToU8(colour.r()) << ' ' << FToU8(colour.g()) << ' ' << FToU8(colour.b());
|
||||||
|
|
||||||
out << std::hex << std::setfill('0') << std::setw(2) << FToU8(colour.r());
|
return os;
|
||||||
out << std::hex << std::setfill('0') << std::setw(2) << FToU8(colour.g());
|
|
||||||
out << std::hex << std::setfill('0') << std::setw(2) << FToU8(colour.b());
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
29
src/image.h
29
src/image.h
|
|
@ -2,26 +2,25 @@
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
#include "colour.h"
|
#include "colour.h"
|
||||||
#include "util.h"
|
#include "raytracer.h"
|
||||||
|
|
||||||
class Image {
|
class Image {
|
||||||
public:
|
public:
|
||||||
constexpr Image(uint32_t width, uint32_t height)
|
constexpr Image(u32 width, u32 height)
|
||||||
// NOLINTNEXTLINE(modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays)
|
// NOLINTNEXTLINE(modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays)
|
||||||
: buf_(std::make_unique_for_overwrite<Colour[]>(static_cast<std::size_t>(width) * height)),
|
: buf_(std::make_unique_for_overwrite<Colour[]>(static_cast<std::size_t>(width) * height)),
|
||||||
width_{width},
|
width_{width},
|
||||||
height_{height} {}
|
height_{height} {}
|
||||||
|
|
||||||
constexpr uint32_t width() const { return width_; }
|
constexpr u32 width() const { return width_; }
|
||||||
constexpr uint32_t height() const { return height_; }
|
constexpr u32 height() const { return height_; }
|
||||||
|
|
||||||
Colour& operator[](uint32_t x, uint32_t y) {
|
Colour& operator[](u32 x, u32 y) {
|
||||||
assert(x < width_);
|
assert(x < width_);
|
||||||
assert(y < height_);
|
assert(y < height_);
|
||||||
|
|
||||||
|
|
@ -30,7 +29,7 @@ class Image {
|
||||||
return buf_[y * width_ + x];
|
return buf_[y * width_ + x];
|
||||||
}
|
}
|
||||||
|
|
||||||
Colour operator[](uint32_t x, uint32_t y) const {
|
Colour operator[](u32 x, u32 y) const {
|
||||||
assert(x < width_);
|
assert(x < width_);
|
||||||
assert(y < height_);
|
assert(y < height_);
|
||||||
|
|
||||||
|
|
@ -43,24 +42,26 @@ class Image {
|
||||||
// NOLINTNEXTLINE(modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays)
|
// NOLINTNEXTLINE(modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays)
|
||||||
std::unique_ptr<Colour[]> buf_;
|
std::unique_ptr<Colour[]> buf_;
|
||||||
|
|
||||||
uint32_t width_;
|
u32 width_;
|
||||||
uint32_t height_;
|
u32 height_;
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr std::ostream& operator<<(std::ostream& os, const Image& img) {
|
constexpr std::ostream& operator<<(std::ostream& os, const Image& img) {
|
||||||
os << "P3\n" << img.width() << ' ' << img.height() << "\n255\n";
|
os << "P3" << newline;
|
||||||
|
os << img.width() << ' ' << img.height() << newline;
|
||||||
|
os << "255" << newline;
|
||||||
|
|
||||||
for (uint32_t j = 0; j < img.height(); j++) {
|
for (u32 j = 0; j < img.height(); j++) {
|
||||||
std::clog << "\rWriting line " << j << " of " << img.height() << std::flush;
|
std::clog << "\rWriting line " << j << " of " << img.height() << std::flush;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < img.width(); i++) {
|
for (u32 i = 0; i < img.width(); i++) {
|
||||||
const Colour col = img[i, j];
|
const Colour col = img[i, j];
|
||||||
|
|
||||||
os << FToU8(col.r()) << ' ' << FToU8(col.g()) << ' ' << FToU8(col.b()) << '\n';
|
os << col << newline;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::clog << "\rDone " << std::endl;
|
std::clog << "\rDone " << newline;
|
||||||
|
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
76
src/main.cc
76
src/main.cc
|
|
@ -1,26 +1,30 @@
|
||||||
#include <cstdint>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "camera.h"
|
||||||
#include "colour.h"
|
#include "colour.h"
|
||||||
#include "image.h"
|
#include "image.h"
|
||||||
#include "ray.h"
|
#include "ray.h"
|
||||||
|
#include "raytracer.h"
|
||||||
|
#include "renderobject.h"
|
||||||
|
#include "renderobjectlist.h"
|
||||||
|
#include "sphere.h"
|
||||||
#include "vec3.h"
|
#include "vec3.h"
|
||||||
|
|
||||||
bool IntersectsSphere(const Ray& r, const Point3& centre, double radius) {
|
Colour RayColour(const Ray& ray, const RenderObject& world) {
|
||||||
Vec3 oc = r.origin() - centre;
|
auto hit_record = world.hit(ray, 0.0, kInf);
|
||||||
|
|
||||||
double a = r.direction().squared();
|
if (hit_record.has_value()) {
|
||||||
double b = 2.0 * dot(oc, r.direction());
|
// assert(hit_record.front_face);
|
||||||
double c = oc.squared() - radius * radius;
|
|
||||||
|
|
||||||
auto discr = b * b - 4 * a * c;
|
Vec3 n = hit_record->normal;
|
||||||
|
|
||||||
return discr >= 0;
|
if (!hit_record->front_face) {
|
||||||
}
|
// return Colour{0.0, 0.0, 0.0};
|
||||||
|
return Colour{0.5 * (n + Vec3{1, 1, 1})};
|
||||||
|
}
|
||||||
|
|
||||||
Colour RayColour(const Ray& ray) {
|
return Colour{0.5 * (n + Vec3{1, 1, 1})};
|
||||||
if (IntersectsSphere(ray, -Vec3::e_z, 0.5)) {
|
|
||||||
return {1.0, 0.0, 0.0};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto unit_dir = ray.direction().normed();
|
auto unit_dir = ray.direction().normed();
|
||||||
|
|
@ -31,54 +35,42 @@ Colour RayColour(const Ray& ray) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int /* argc */, char* /* argv */[]) {
|
int main(int /* argc */, char* /* argv */[]) {
|
||||||
// image properties
|
// image
|
||||||
|
|
||||||
constexpr double aspect_ratio = 16.0 / 9.0;
|
constexpr double aspect_ratio = 16.0 / 9.0;
|
||||||
|
|
||||||
constexpr uint32_t image_width = 800;
|
constexpr u32 image_width = 800;
|
||||||
|
|
||||||
constexpr auto image_height = static_cast<uint32_t>(image_width / aspect_ratio);
|
constexpr auto image_height = static_cast<u32>(image_width / aspect_ratio);
|
||||||
|
|
||||||
static_assert(image_height >= 1);
|
static_assert(image_height >= 1);
|
||||||
|
|
||||||
|
Image img{image_width, image_height};
|
||||||
|
|
||||||
|
// world
|
||||||
|
|
||||||
|
RenderObjectList world;
|
||||||
|
|
||||||
|
world.Add(std::make_shared<Sphere>(Vec3{0, -100.5, -1}, 100));
|
||||||
|
world.Add(std::make_shared<Sphere>(-Vec3::e_z, 0.5));
|
||||||
|
|
||||||
// camera
|
// camera
|
||||||
|
|
||||||
constexpr double focal_length = 1.0;
|
constexpr double focal_length = 1.0;
|
||||||
|
|
||||||
constexpr double viewport_height = 2.0;
|
constexpr Point3 camera_centre{0.0, 0.0, 0.0};
|
||||||
constexpr double viewport_width =
|
|
||||||
viewport_height * static_cast<double>(image_width) / image_height;
|
|
||||||
|
|
||||||
Point3 camera_centre{0.0, 0.0, 0.0};
|
Camera camera{camera_centre, img.width(), img.height(), focal_length};
|
||||||
|
|
||||||
// viewport
|
|
||||||
|
|
||||||
constexpr Vec3 u_viewport = viewport_width * Vec3::e_x;
|
|
||||||
constexpr Vec3 v_viewport = -viewport_height * Vec3::e_y;
|
|
||||||
|
|
||||||
constexpr Vec3 d_u_pixel = u_viewport / image_width;
|
|
||||||
constexpr Vec3 d_v_pixel = v_viewport / image_height;
|
|
||||||
|
|
||||||
auto viewport_upper_left =
|
|
||||||
camera_centre - focal_length * Vec3::e_z - u_viewport / 2 - v_viewport / 2;
|
|
||||||
|
|
||||||
auto pixel_00 = viewport_upper_left + 0.5 * d_u_pixel + 0.5 * d_v_pixel;
|
|
||||||
|
|
||||||
// render
|
// render
|
||||||
|
|
||||||
Image img{image_width, image_height};
|
for (u32 j = 0; j < img.height(); j++) {
|
||||||
|
|
||||||
for (uint32_t j = 0; j < img.height(); j++) {
|
|
||||||
std::clog << "\rWriting line " << j << " of " << img.height() << std::flush;
|
std::clog << "\rWriting line " << j << " of " << img.height() << std::flush;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < img.width(); i++) {
|
for (u32 i = 0; i < img.width(); i++) {
|
||||||
auto pixel_centre = pixel_00 + i * d_u_pixel + j * d_v_pixel;
|
auto ray = camera.CastRay(i, j);
|
||||||
|
|
||||||
auto ray_direction = pixel_centre - camera_centre;
|
img[i, j] = RayColour(ray, world);
|
||||||
|
|
||||||
Ray r{camera_centre, ray_direction};
|
|
||||||
|
|
||||||
img[i, j] = RayColour(r);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,14 @@
|
||||||
|
|
||||||
class Ray {
|
class Ray {
|
||||||
public:
|
public:
|
||||||
Ray() = default;
|
constexpr Ray() = default;
|
||||||
|
|
||||||
Ray(const Point3& origin, const Vec3& direction) : orig_{origin}, dir_{direction} {}
|
constexpr Ray(const Point3& origin, const Vec3& direction) : orig_{origin}, dir_{direction} {}
|
||||||
|
|
||||||
Point3 origin() const { return orig_; }
|
Point3 origin() const { return orig_; }
|
||||||
Vec3 direction() const { return dir_; }
|
Vec3 direction() const { return dir_; }
|
||||||
|
|
||||||
Point3 At(double t) { return orig_ + t * dir_; }
|
constexpr Point3 At(double t) const { return orig_ + t * dir_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Point3 orig_;
|
Point3 orig_;
|
||||||
|
|
|
||||||
16
src/raytracer.h
Normal file
16
src/raytracer.h
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <limits>
|
||||||
|
#include <numbers>
|
||||||
|
|
||||||
|
using u32 = uint32_t;
|
||||||
|
|
||||||
|
constexpr double kInf = std::numeric_limits<double>::infinity();
|
||||||
|
constexpr double kPi = std::numbers::pi_v<double>;
|
||||||
|
|
||||||
|
constexpr char newline = '\n';
|
||||||
|
|
||||||
|
constexpr u32 FToU8(double x) { return static_cast<uint16_t>(255.999 * x); }
|
||||||
|
|
||||||
|
constexpr double deg2rad(double deg) { return deg * kPi / 180.0; }
|
||||||
31
src/renderobject.h
Normal file
31
src/renderobject.h
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#include "ray.h"
|
||||||
|
#include "vec3.h"
|
||||||
|
|
||||||
|
struct HitRecord {
|
||||||
|
Point3 p;
|
||||||
|
Vec3 normal;
|
||||||
|
double t = 0.0;
|
||||||
|
bool front_face = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RenderObject {
|
||||||
|
public:
|
||||||
|
RenderObject() = default;
|
||||||
|
|
||||||
|
RenderObject(const RenderObject& other) = default;
|
||||||
|
RenderObject& operator=(const RenderObject&) = default;
|
||||||
|
|
||||||
|
RenderObject(RenderObject&& other) = default;
|
||||||
|
RenderObject& operator=(RenderObject&&) = default;
|
||||||
|
|
||||||
|
virtual ~RenderObject() = default;
|
||||||
|
|
||||||
|
virtual std::optional<HitRecord> hit(const Ray& ray, double t_min, double t_max) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
using SharedRenderObject = std::shared_ptr<RenderObject>;
|
||||||
46
src/renderobjectlist.h
Normal file
46
src/renderobjectlist.h
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <optional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "ray.h"
|
||||||
|
#include "raytracer.h"
|
||||||
|
#include "renderobject.h"
|
||||||
|
|
||||||
|
class RenderObjectList : public RenderObject {
|
||||||
|
public:
|
||||||
|
constexpr RenderObjectList() = default;
|
||||||
|
// explicit RenderObjectList(const SharedRenderObject& obj) { Append(obj); }
|
||||||
|
RenderObjectList(std::initializer_list<SharedRenderObject> objs) : objs_{objs} {}
|
||||||
|
|
||||||
|
constexpr auto begin() { return objs_.begin(); }
|
||||||
|
constexpr auto end() { return objs_.end(); }
|
||||||
|
|
||||||
|
constexpr auto begin() const { return objs_.begin(); }
|
||||||
|
constexpr auto end() const { return objs_.end(); }
|
||||||
|
|
||||||
|
void Add(const SharedRenderObject& obj) { objs_.push_back(obj); }
|
||||||
|
|
||||||
|
void Clear() { objs_.clear(); }
|
||||||
|
|
||||||
|
std::optional<HitRecord> hit(const Ray& ray, double t_min, double t_max) const override {
|
||||||
|
std::optional<HitRecord> closest_hit_record = std::nullopt;
|
||||||
|
|
||||||
|
double closest_t = kInf;
|
||||||
|
|
||||||
|
for (const auto& obj : objs_) {
|
||||||
|
auto hit_record = obj->hit(ray, t_min, t_max);
|
||||||
|
|
||||||
|
if (hit_record.has_value() && hit_record->t < closest_t) {
|
||||||
|
closest_hit_record = hit_record;
|
||||||
|
closest_t = hit_record->t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return closest_hit_record;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<SharedRenderObject> objs_;
|
||||||
|
};
|
||||||
79
src/sphere.h
Normal file
79
src/sphere.h
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cmath>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#include "ray.h"
|
||||||
|
#include "renderobject.h"
|
||||||
|
#include "vec3.h"
|
||||||
|
|
||||||
|
class Sphere : public RenderObject {
|
||||||
|
public:
|
||||||
|
constexpr Sphere() = default;
|
||||||
|
constexpr Sphere(Point3 centre, double radius) : centre_{centre}, radius_{radius} {
|
||||||
|
assert(radius >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr Point3 centre() const { return centre_; }
|
||||||
|
constexpr double radius() const { return radius_; }
|
||||||
|
|
||||||
|
std::optional<HitRecord> hit(const Ray& ray, double t_min, double t_max) const override {
|
||||||
|
HitRecord hit_record;
|
||||||
|
|
||||||
|
Vec3 oc = ray.origin() - centre_;
|
||||||
|
|
||||||
|
double a = ray.direction().squared();
|
||||||
|
double b_half = dot(oc, ray.direction());
|
||||||
|
double c = oc.squared() - radius_ * radius_;
|
||||||
|
|
||||||
|
auto discr = b_half * b_half - a * c;
|
||||||
|
|
||||||
|
if (discr < 0) {
|
||||||
|
// miss
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// hit
|
||||||
|
|
||||||
|
// smaller of the ts that hit the sphere
|
||||||
|
double t = (-b_half - std::sqrt(discr)) / a;
|
||||||
|
|
||||||
|
if (t > t_max) {
|
||||||
|
// if the smaller t is already too large, we don't need to check the second one since it
|
||||||
|
// will be even larger
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t < t_min) {
|
||||||
|
// if the smaller t is too small, check the larger one
|
||||||
|
|
||||||
|
t = (-b_half + std::sqrt(discr)) / a;
|
||||||
|
|
||||||
|
if (t < t_min || t > t_max) {
|
||||||
|
// larger t also out of range: return false
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// smaller t hits front side, smaller t hits back side
|
||||||
|
// TODO: what if our hit t is less than 0? is that case even relevant?
|
||||||
|
hit_record.front_face = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
hit_record.t = t;
|
||||||
|
hit_record.p = ray.At(t);
|
||||||
|
hit_record.normal = (hit_record.p - centre_) / radius_;
|
||||||
|
|
||||||
|
if (!hit_record.front_face) {
|
||||||
|
hit_record.normal = -hit_record.normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hit_record;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Point3 centre_{};
|
||||||
|
double radius_ = 0.0;
|
||||||
|
};
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
constexpr uint32_t FToU8(double x) {
|
|
||||||
return static_cast<uint16_t>(255.999 * x);
|
|
||||||
}
|
|
||||||
13
src/vec3.h
13
src/vec3.h
|
|
@ -3,6 +3,7 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <cstddef>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
class Vec3 {
|
class Vec3 {
|
||||||
|
|
@ -86,9 +87,7 @@ constexpr Vec3 operator+(const Vec3& u, const Vec3& v) {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr Vec3 operator-(const Vec3& u, const Vec3& v) {
|
constexpr Vec3 operator-(const Vec3& u, const Vec3& v) { return u + (-v); }
|
||||||
return u + (-v);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Vec3 operator*(const Vec3& u, const Vec3& v) {
|
constexpr Vec3 operator*(const Vec3& u, const Vec3& v) {
|
||||||
return {u.x() * v.x(), u.y() * v.y(), u.z() * v.z()};
|
return {u.x() * v.x(), u.y() * v.y(), u.z() * v.z()};
|
||||||
|
|
@ -100,9 +99,7 @@ constexpr Vec3 operator*(double t, const Vec3& v) {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr Vec3 operator/(const Vec3& v, double t) {
|
constexpr Vec3 operator/(const Vec3& v, double t) { return (1 / t) * v; }
|
||||||
return (1 / t) * v;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr double dot(const Vec3& u, const Vec3& v) {
|
constexpr double dot(const Vec3& u, const Vec3& v) {
|
||||||
Vec3 tmp = u * v;
|
Vec3 tmp = u * v;
|
||||||
|
|
@ -114,6 +111,4 @@ constexpr Vec3 cross(const Vec3& u, const Vec3& v) {
|
||||||
u.x() * v.y() - u.y() - v.x()};
|
u.x() * v.y() - u.y() - v.x()};
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr Vec3 normed(const Vec3& v) {
|
constexpr Vec3 normed(const Vec3& v) { return v.normed(); }
|
||||||
return v.normed();
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue