changed philox to rand

This commit is contained in:
Moritz Gmeiner 2023-12-30 12:37:27 +01:00
commit fa90f444ef
17 changed files with 177 additions and 45 deletions

3
.gitmodules vendored
View file

@ -1,6 +1,3 @@
[submodule "subprojects/philox"]
path = subprojects/philox
url = git@github.com:MorizzG/philox
[submodule "subprojects/rand"] [submodule "subprojects/rand"]
path = subprojects/rand path = subprojects/rand
url = git@github.com:MorizzG/rand url = git@github.com:MorizzG/rand

View file

@ -12,9 +12,24 @@ add_project_arguments(
language : 'cpp' language : 'cpp'
) )
if get_option('native')
add_global_arguments(
'-march=native',
philox_proj = subproject('philox', default_options : ['warning_level=0', 'werror=false']) language : 'c'
philox_dep = philox_proj.get_variable('philox_dep') )
add_global_arguments(
'-march=native',
language : 'cpp'
)
endif
rand_proj = subproject('rand', default_options : ['warning_level=0', 'werror=false'])
rand_dep = rand_proj.get_variable('rand_dep')
sources = [] sources = []
@ -22,4 +37,4 @@ subdir('src')
inc = include_directories('src') inc = include_directories('src')
executable('ray-tracer', sources, include_directories : inc, dependencies : [philox_dep]) executable('ray-tracer', sources, include_directories : inc, dependencies : [rand_dep])

1
meson.options Normal file
View file

@ -0,0 +1 @@
option('native', type : 'boolean', value : true)

BIN
perf.data Normal file

Binary file not shown.

BIN
perf.data.old Normal file

Binary file not shown.

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <cassert> #include <cassert>
#include <cmath>
#include <iomanip> #include <iomanip>
#include <ios> #include <ios>
#include <iostream> #include <iostream>
@ -43,6 +44,10 @@ class Colour {
return *this; return *this;
} }
constexpr Colour to_gamma2() const {
return Colour{std::sqrt(r()), std::sqrt(g()), std::sqrt(b())};
}
std::string to_string() const { std::string to_string() const {
std::stringstream ss; std::stringstream ss;
@ -74,8 +79,12 @@ constexpr Colour operator+(Colour c1, Colour c2) {
return out; return out;
} }
inline std::ostream& operator<<(std::ostream& os, Colour colour) { inline std::ostream& operator<<(std::ostream& os, Colour c) {
os << FToU8(colour.r()) << ' ' << FToU8(colour.g()) << ' ' << FToU8(colour.b()); double r = c.r();
double g = c.g();
double b = c.b();
os << FToU8(r) << ' ' << FToU8(g) << ' ' << FToU8(b);
return os; return os;
} }

View file

@ -52,18 +52,15 @@ constexpr std::ostream& operator<<(std::ostream& os, const Image& img) {
os << "255" << newline; os << "255" << newline;
for (u32 j = 0; j < img.height(); j++) { for (u32 j = 0; j < img.height(); j++) {
std::clog << "\rWriting line " << j << " of " << img.height() << std::flush;
for (u32 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];
col.CheckValid(); col.CheckValid();
os << col << newline; // apply gamma 2 transform
os << col.to_gamma2() << newline;
} }
} }
std::clog << "\rDone " << newline;
return os; return os;
} }

View file

@ -2,10 +2,11 @@
#include <memory> #include <memory>
#include "camera.h" #include "camera.h"
#include "colour.h"
#include "image.h" #include "image.h"
#include "material.h"
#include "raytracer.h" #include "raytracer.h"
#include "renderer.h" #include "renderer.h"
#include "renderobject.h"
#include "renderobjectlist.h" #include "renderobjectlist.h"
#include "sphere.h" #include "sphere.h"
#include "vec3.h" #include "vec3.h"
@ -15,14 +16,16 @@ int main(int /* argc */, char* /* argv */[]) {
RenderObjectList world; RenderObjectList world;
world.Add(std::make_shared<Sphere>(Vec3{0, -100.5, -1}, 100)); auto lamb = std::make_shared<Lambertian>(Colour{0.1, 0.4, 0.8});
world.Add(std::make_shared<Sphere>(-Vec3::e_z, 0.5));
world.Add(std::make_unique<Sphere>(Vec3{0, -100.5, -1}, 100, lamb));
world.Add(std::make_unique<Sphere>(-Vec3::e_z, 0.5, lamb));
// camera // camera
constexpr f64 aspect_ratio = 16.0 / 9.0; constexpr f64 aspect_ratio = 16.0 / 9.0;
constexpr u32 image_width = 800; constexpr u32 image_width = 600;
constexpr auto image_height = static_cast<u32>(image_width / aspect_ratio); constexpr auto image_height = static_cast<u32>(image_width / aspect_ratio);
// constexpr u32 image_width = 1920; // constexpr u32 image_width = 1920;

52
src/material.h Normal file
View file

@ -0,0 +1,52 @@
#pragma once
#include <optional>
#include <tuple>
#include "colour.h"
#include "rand.h"
#include "ray.h"
#include "renderobject.h"
class Material {
public:
constexpr Material() = default;
constexpr Material(const Material&) = default;
Material& operator=(const Material&) = default;
constexpr Material(Material&&) = default;
Material& operator=(Material&&) = default;
virtual ~Material() = default;
RandomGen& rand() const { return rand_; }
virtual std::optional<std::tuple<Colour, Ray>> Scatter(const Ray& in,
const HitRecord& hit_record) const = 0;
private:
mutable RandomGen rand_{};
};
class Lambertian : public Material {
public:
constexpr explicit Lambertian(Colour albedo) : albedo_{albedo} {}
std::optional<std::tuple<Colour, Ray>> Scatter(const Ray& /* in */,
const HitRecord& hit_record) const override {
auto scatter_dir = hit_record.normal + rand().GenOnUnitSphere();
// TODO: enable
/* if (scatter_dir.almost_zero()) {
scatter_dir = hit_record.normal;
} */
Ray scattered{hit_record.p, scatter_dir};
return std::make_tuple(albedo_, scattered);
}
private:
Colour albedo_;
};

View file

@ -10,6 +10,8 @@ using u64 = uint64_t;
using f64 = double; using f64 = double;
constexpr f64 kInf = std::numeric_limits<f64>::infinity(); constexpr f64 kInf = std::numeric_limits<f64>::infinity();
constexpr f64 kNan = std::numeric_limits<f64>::signaling_NaN();
constexpr f64 kPi = std::numbers::pi_v<f64>; constexpr f64 kPi = std::numbers::pi_v<f64>;
constexpr char newline = '\n'; constexpr char newline = '\n';

View file

@ -1,11 +1,15 @@
#pragma once #pragma once
#include <array>
#include <cassert>
#include <iostream> #include <iostream>
#include <thread>
#include "camera.h" #include "camera.h"
#include "colour.h" #include "colour.h"
#include "image.h" #include "image.h"
#include "interval.h" #include "interval.h"
#include "material.h"
#include "rand.h" #include "rand.h"
#include "ray.h" #include "ray.h"
#include "raytracer.h" #include "raytracer.h"
@ -14,28 +18,52 @@
class Renderer { class Renderer {
public: public:
constexpr explicit Renderer(Camera camera, u32 samples_per_pixel = 10) constexpr explicit Renderer(Camera camera, u32 samples_per_pixel = 100, u32 max_bounces = 50)
: camera_{camera}, samples_per_pixel_{samples_per_pixel} {} : camera_{camera}, samples_per_pixel_{samples_per_pixel}, max_bounces_{max_bounces} {}
constexpr Image Render(const RenderObject& world) { constexpr u32& samples_per_pixel() { return samples_per_pixel_; }
constexpr u32 samples_per_pixel() const { return samples_per_pixel_; }
constexpr u32& max_bounces() { return max_bounces_; }
constexpr u32 max_bounces() const { return max_bounces_; }
Image Render(const RenderObject& world) {
Image img{camera_.image_width(), camera_.image_height()}; Image img{camera_.image_width(), camera_.image_height()};
for (u32 j = 0; j < img.height(); j++) { constexpr u32 kNumThreads = 4;
std::clog << "\rWriting line " << j << " of " << img.height() << std::flush;
for (u32 i = 0; i < img.width(); i++) { auto render_thread = [this, &world, &img](u32 thread) {
Colour colour_sum{0.0, 0.0, 0.0}; for (u32 j = thread; j < img.height(); j += kNumThreads) {
std::clog << "\rWriting line " << j << " of " << img.height() << std::flush;
for (u32 num_sample = 0; num_sample < samples_per_pixel_; num_sample++) { for (u32 i = 0; i < img.width(); i++) {
auto ray = SampleRay(i, j); Colour colour_sum{0.0, 0.0, 0.0};
colour_sum += Cast(ray, world); for (u32 num_sample = 0; num_sample < samples_per_pixel_; num_sample++) {
auto ray = SampleRay(i, j);
colour_sum += Cast(ray, world, max_bounces_);
}
img[i, j] = colour_sum / samples_per_pixel_;
} }
img[i, j] = colour_sum / samples_per_pixel_;
} }
};
// render_thread(0);
std::array<std::thread, kNumThreads> render_threads;
for (u32 i = 0; i < kNumThreads; i++) {
render_threads[i] = std::thread{render_thread, i};
} }
for (auto& t : render_threads) {
t.join();
}
std::clog << "\rDone " << newline;
return img; return img;
} }
@ -53,22 +81,29 @@ class Renderer {
return Ray{camera_.centre(), ray_direction}; return Ray{camera_.centre(), ray_direction};
} }
constexpr Colour Cast(const Ray& ray, const RenderObject& world) { constexpr Colour Cast(const Ray& ray, const RenderObject& world, u32 bounces) {
auto hit_record = world.hit(ray, Interval::kPositive); auto hit_record = world.hit(ray, Interval{0.001, kInf});
if (hit_record.has_value()) { if (hit_record.has_value()) {
Vec3 normal = hit_record->normal; if (!hit_record->front_face || bounces == 0) {
if (!hit_record->front_face) {
return Colour::kBlack; return Colour::kBlack;
} }
/* Vec3 normal = hit_record->normal;
Vec3 new_origin = hit_record->p; Vec3 new_origin = hit_record->p;
Vec3 new_direction = rand_.GenOnHemisphere(normal);
Ray new_ray{new_origin, new_direction}; // Vec3 new_direction = rand_.GenOnHemisphere(normal);
Vec3 new_direction = normal + rand_.GenOnUnitSphere();
return 0.5 * Cast(new_ray, world); Ray new_ray{new_origin, new_direction}; */
auto res = hit_record->mat->Scatter(ray, hit_record.value());
auto [albedo, out_ray] = res.value();
assert(bounces > 0);
return 0.5 * Cast(out_ray, world, bounces - 1);
} }
auto unit_dir = ray.direction().normed(); auto unit_dir = ray.direction().normed();
@ -83,4 +118,5 @@ class Renderer {
RandomGen rand_{}; RandomGen rand_{};
u32 samples_per_pixel_; u32 samples_per_pixel_;
u32 max_bounces_;
}; };

View file

@ -5,12 +5,17 @@
#include "interval.h" #include "interval.h"
#include "ray.h" #include "ray.h"
#include "raytracer.h"
#include "vec3.h" #include "vec3.h"
class Material;
struct HitRecord { struct HitRecord {
Point3 p; Point3 p;
Vec3 normal; Vec3 normal;
f64 t = 0.0; const Material* mat = nullptr;
f64 t = kNan;
bool front_face = true; bool front_face = true;
}; };

View file

@ -1,18 +1,21 @@
#pragma once #pragma once
#include <initializer_list> #include <initializer_list>
#include <memory>
#include <optional> #include <optional>
#include <utility>
#include <vector> #include <vector>
#include "interval.h" #include "interval.h"
#include "ray.h" #include "ray.h"
#include "raytracer.h"
#include "renderobject.h" #include "renderobject.h"
class RenderObjectList : public RenderObject { class RenderObjectList : public RenderObject {
public: public:
constexpr RenderObjectList() = default; constexpr RenderObjectList() = default;
// explicit RenderObjectList(const SharedRenderObject& obj) { Append(obj); } // explicit RenderObjectList(const SharedRenderObject& obj) { Append(obj); }
RenderObjectList(std::initializer_list<SharedRenderObject> objs) : objs_{objs} {} // RenderObjectList(std::initializer_list<RenderObject> objs) : objs_{objs} {}
constexpr auto begin() { return objs_.begin(); } constexpr auto begin() { return objs_.begin(); }
constexpr auto end() { return objs_.end(); } constexpr auto end() { return objs_.end(); }
@ -20,7 +23,7 @@ class RenderObjectList : public RenderObject {
constexpr auto begin() const { return objs_.begin(); } constexpr auto begin() const { return objs_.begin(); }
constexpr auto end() const { return objs_.end(); } constexpr auto end() const { return objs_.end(); }
void Add(const SharedRenderObject& obj) { objs_.push_back(obj); } void Add(std::unique_ptr<RenderObject> obj) { objs_.emplace_back(std::move(obj)); }
void Clear() { objs_.clear(); } void Clear() { objs_.clear(); }
@ -43,5 +46,5 @@ class RenderObjectList : public RenderObject {
} }
private: private:
std::vector<SharedRenderObject> objs_; std::vector<std::unique_ptr<RenderObject>> objs_;
}; };

View file

@ -2,9 +2,11 @@
#include <cassert> #include <cassert>
#include <cmath> #include <cmath>
#include <memory>
#include <optional> #include <optional>
#include "interval.h" #include "interval.h"
#include "material.h"
#include "ray.h" #include "ray.h"
#include "raytracer.h" #include "raytracer.h"
#include "renderobject.h" #include "renderobject.h"
@ -13,7 +15,9 @@
class Sphere : public RenderObject { class Sphere : public RenderObject {
public: public:
constexpr Sphere() = default; constexpr Sphere() = default;
constexpr Sphere(Point3 centre, f64 radius) : centre_{centre}, radius_{radius} {
Sphere(Point3 centre, f64 radius, const std::shared_ptr<Material>& mat)
: centre_{centre}, radius_{radius}, mat_{mat} {
assert(radius >= 0); assert(radius >= 0);
} }
@ -21,7 +25,7 @@ class Sphere : public RenderObject {
constexpr f64 radius() const { return radius_; } constexpr f64 radius() const { return radius_; }
std::optional<HitRecord> hit(const Ray& ray, Interval ts) const override { std::optional<HitRecord> hit(const Ray& ray, Interval ts) const override {
HitRecord hit_record; HitRecord hit_record{};
Vec3 oc = ray.origin() - centre_; Vec3 oc = ray.origin() - centre_;
@ -66,6 +70,7 @@ class Sphere : public RenderObject {
hit_record.t = t; hit_record.t = t;
hit_record.p = ray.At(t); hit_record.p = ray.At(t);
hit_record.mat = mat_.get();
if (hit_record.front_face) { if (hit_record.front_face) {
hit_record.normal = (hit_record.p - centre_) / radius_; hit_record.normal = (hit_record.p - centre_) / radius_;
@ -79,4 +84,6 @@ class Sphere : public RenderObject {
private: private:
Point3 centre_{}; Point3 centre_{};
f64 radius_ = 0.0; f64 radius_ = 0.0;
std::shared_ptr<Material> mat_;
}; };

View file

@ -59,6 +59,12 @@ class Vec3 {
return *this; return *this;
} }
constexpr bool almost_zero() const {
f64 eps = 1e-8;
return std::fabs(x()) < eps && std::fabs(y()) < eps && std::fabs(z()) < eps;
}
constexpr f64 squared() const { return x() * x() + y() * y() + z() * z(); } constexpr f64 squared() const { return x() * x() + y() * y() + z() * z(); }
constexpr f64 norm() const { return std::sqrt(squared()); } constexpr f64 norm() const { return std::sqrt(squared()); }

@ -1 +0,0 @@
Subproject commit cf69284bd2d82b279c34fb1cf90543fd04b3a038

@ -1 +1 @@
Subproject commit 4d7680624857241aca166f58b957712b0583fa05 Subproject commit 8043050d3c871d241a1274be81bfaf1894f5edb2