init commit

This commit is contained in:
Moritz Gmeiner 2023-12-23 22:56:27 +01:00
commit a3e1542250
10 changed files with 360382 additions and 0 deletions

4
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,4 @@
{
"mesonbuild.configureOnOpen": false,
"C_Cpp.default.compileCommands": "/home/mg/00_Source/ray-tracer/debug/compile_commands.json"
}

360003
image.ppm Normal file

File diff suppressed because it is too large Load diff

20
meson.build Normal file
View file

@ -0,0 +1,20 @@
project('ray-tracer', 'cpp', default_options : [
'warning_level=3',
'werror=true',
'cpp_std=c++23',
'b_lto=true',
'b_lto_mode=thin',
])
add_project_arguments(
'-Wconversion',
language : 'cpp'
)
sources = []
subdir('src')
inc = include_directories('src')
executable('ray-tracer', sources, include_directories : inc)

54
src/colour.h Normal file
View file

@ -0,0 +1,54 @@
#pragma once
#include <cassert>
#include <iomanip>
#include <ios>
#include <ostream>
#include "util.h"
class Colour {
public:
static const Colour kBlack;
static const Colour kWhite;
constexpr Colour() = default;
constexpr Colour(double r, double g, double b) : r_{r}, g_{g}, b_{b} {
assert(0.0 <= r && r <= 1.0);
assert(0.0 <= g && g <= 1.0);
assert(0.0 <= b && b <= 1.0);
}
constexpr double& r() { return r_; }
constexpr double& g() { return g_; }
constexpr double& b() { return b_; }
constexpr double r() const { return r_; }
constexpr double g() const { return g_; }
constexpr double b() const { return b_; }
private:
double r_;
double g_;
double b_;
};
constexpr Colour Colour::kBlack{0.0, 0.0, 0.0};
constexpr Colour operator*(double t, Colour col) {
return {t * col.r(), t * col.g(), t * col.b()};
}
constexpr Colour operator+(Colour c1, Colour c2) {
return {c1.r() + c2.r(), c1.g() + c2.g(), c1.b() + c2.b()};
}
inline std::ostream& operator<<(std::ostream& out, Colour colour) {
out << '#';
out << std::hex << std::setfill('0') << std::setw(2) << FToU8(colour.r());
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;
}

66
src/image.h Normal file
View file

@ -0,0 +1,66 @@
#pragma once
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <iostream>
#include <memory>
#include <ostream>
#include "colour.h"
#include "util.h"
class Image {
public:
constexpr Image(uint32_t width, uint32_t height)
// NOLINTNEXTLINE(modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays)
: buf_(std::make_unique_for_overwrite<Colour[]>(static_cast<std::size_t>(width) * height)),
width_{width},
height_{height} {}
constexpr uint32_t width() const { return width_; }
constexpr uint32_t height() const { return height_; }
Colour& operator[](uint32_t x, uint32_t y) {
assert(x < width_);
assert(y < height_);
assert(buf_.get() != nullptr);
return buf_[y * width_ + x];
}
Colour operator[](uint32_t x, uint32_t y) const {
assert(x < width_);
assert(y < height_);
assert(buf_.get() != nullptr);
return buf_[y * width_ + x];
}
private:
// NOLINTNEXTLINE(modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays)
std::unique_ptr<Colour[]> buf_;
uint32_t width_;
uint32_t height_;
};
constexpr std::ostream& operator<<(std::ostream& os, const Image& img) {
os << "P3\n" << img.width() << ' ' << img.height() << "\n255\n";
for (uint32_t j = 0; j < img.height(); j++) {
std::clog << "\rWriting line " << j << " of " << img.height() << std::flush;
for (uint32_t i = 0; i < img.width(); i++) {
const Colour col = img[i, j];
os << FToU8(col.r()) << ' ' << FToU8(col.g()) << ' ' << FToU8(col.b()) << '\n';
}
}
std::clog << "\rDone " << std::endl;
return os;
}

88
src/main.cc Normal file
View file

@ -0,0 +1,88 @@
#include <cstdint>
#include <iostream>
#include "colour.h"
#include "image.h"
#include "ray.h"
#include "vec3.h"
bool IntersectsSphere(const Ray& r, const Point3& centre, double radius) {
Vec3 oc = r.origin() - centre;
double a = r.direction().squared();
double b = 2.0 * dot(oc, r.direction());
double c = oc.squared() - radius * radius;
auto discr = b * b - 4 * a * c;
return discr >= 0;
}
Colour RayColour(const Ray& ray) {
if (IntersectsSphere(ray, -Vec3::e_z, 0.5)) {
return {1.0, 0.0, 0.0};
}
auto unit_dir = ray.direction().normed();
double a = 0.5 * (unit_dir.y() + 1.0);
return (1.0 - a) * Colour{1.0, 1.0, 1.0} + a * Colour{0.5, 0.7, 1.0};
}
int main(int /* argc */, char* /* argv */[]) {
// image properties
constexpr double aspect_ratio = 16.0 / 9.0;
constexpr uint32_t image_width = 800;
constexpr auto image_height = static_cast<uint32_t>(image_width / aspect_ratio);
static_assert(image_height >= 1);
// camera
constexpr double focal_length = 1.0;
constexpr double viewport_height = 2.0;
constexpr double viewport_width =
viewport_height * static_cast<double>(image_width) / image_height;
Point3 camera_centre{0.0, 0.0, 0.0};
// 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
Image img{image_width, image_height};
for (uint32_t j = 0; j < img.height(); j++) {
std::clog << "\rWriting line " << j << " of " << img.height() << std::flush;
for (uint32_t i = 0; i < img.width(); i++) {
auto pixel_centre = pixel_00 + i * d_u_pixel + j * d_v_pixel;
auto ray_direction = pixel_centre - camera_centre;
Ray r{camera_centre, ray_direction};
img[i, j] = RayColour(r);
}
}
std::cout << img;
return 0;
}

3
src/meson.build Normal file
View file

@ -0,0 +1,3 @@
sources += files(
'main.cc',
)

19
src/ray.h Normal file
View file

@ -0,0 +1,19 @@
#pragma once
#include "vec3.h"
class Ray {
public:
Ray() = default;
Ray(const Point3& origin, const Vec3& direction) : orig_{origin}, dir_{direction} {}
Point3 origin() const { return orig_; }
Vec3 direction() const { return dir_; }
Point3 At(double t) { return orig_ + t * dir_; }
private:
Point3 orig_;
Vec3 dir_;
};

6
src/util.h Normal file
View file

@ -0,0 +1,6 @@
#pragma once
#include <cstdint>
constexpr uint32_t FToU8(double x) {
return static_cast<uint16_t>(255.999 * x);
}

119
src/vec3.h Normal file
View file

@ -0,0 +1,119 @@
#pragma once
#include <array>
#include <cassert>
#include <cmath>
#include <ostream>
class Vec3 {
public:
static const Vec3 e_x;
static const Vec3 e_y;
static const Vec3 e_z;
constexpr Vec3(double x, double y, double z) : xyz_{x, y, z} {}
constexpr Vec3() : Vec3{0, 0, 0} {}
constexpr double& x() { return xyz_[0]; }
constexpr double& y() { return xyz_[1]; }
constexpr double& z() { return xyz_[2]; }
constexpr double x() const { return xyz_[0]; }
constexpr double y() const { return xyz_[1]; }
constexpr double z() const { return xyz_[2]; }
constexpr Vec3 operator-() const { return Vec3{-x(), -y(), -z()}; }
constexpr double& operator[](std::size_t i) {
assert(i <= 3);
return xyz_[i];
}
constexpr double operator[](std::size_t i) const {
assert(i <= 3);
return xyz_[i];
}
constexpr Vec3& operator+=(const Vec3& v) {
x() += v.x();
y() += v.y();
z() += v.z();
return *this;
}
constexpr Vec3& operator*=(double t) {
x() *= t;
y() *= t;
z() *= t;
return *this;
}
constexpr Vec3& operator/=(double t) {
*this *= 1 / t;
return *this;
}
constexpr double squared() const { return x() * x() + y() * y() + z() * z(); }
constexpr double norm() const { return std::sqrt(squared()); }
constexpr Vec3 normed() const {
auto r = *this;
r /= norm();
return r;
}
private:
std::array<double, 3> xyz_;
};
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;
}
constexpr Vec3 operator-(const Vec3& u, const Vec3& v) {
return u + (-v);
}
constexpr Vec3 operator*(const Vec3& u, const Vec3& v) {
return {u.x() * v.x(), u.y() * v.y(), u.z() * v.z()};
}
constexpr Vec3 operator*(double t, const Vec3& v) {
Vec3 out = v;
out *= t;
return out;
}
constexpr Vec3 operator/(const Vec3& v, double t) {
return (1 / t) * v;
}
constexpr double dot(const Vec3& u, const Vec3& v) {
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()};
}
constexpr Vec3 normed(const Vec3& v) {
return v.normed();
}