1
Fork 0

Port to C++ modules

Still incomplete, but now builds in modules.
This commit is contained in:
Joshua Goins 2024-09-26 13:49:16 +02:00
parent f25d0e4c17
commit 6098f0dcca
14 changed files with 2883 additions and 158 deletions

View file

@ -8,16 +8,18 @@ find_package(SDL2 REQUIRED)
add_subdirectory(extern) add_subdirectory(extern)
add_executable(raytracer add_executable(raytracer)
include/camera.h target_sources(raytracer PRIVATE
include/intersections.h
include/lighting.h
include/ray.h
include/image.h
include/scene.h
include/aabb.h
include/octree.h
src/main.cpp src/main.cpp
PRIVATE FILE_SET CXX_MODULES FILES
src/aabb.cpp
src/camera.cpp
src/glm.cpp
src/image.cpp
src/intersections.cpp
src/lighting.cpp
src/octree.cpp
src/ray.cpp
src/scene.cpp) src/scene.cpp)
target_include_directories(raytracer PUBLIC include PRIVATE ${GLM_INCLUDE_DIR}) target_include_directories(raytracer PUBLIC include PRIVATE ${GLM_INCLUDE_DIR})
target_link_libraries(raytracer PUBLIC stb SDL2::Main imgui glad tinyobjloader) target_link_libraries(raytracer PUBLIC stb SDL2::Main imgui glad tinyobjloader)
@ -25,4 +27,5 @@ set_target_properties(raytracer PROPERTIES
CXX_STANDARD 23 CXX_STANDARD 23
CXX_STANDARD_REQUIRED YES CXX_STANDARD_REQUIRED YES
CXX_EXTENSIONS NO CXX_EXTENSIONS NO
CXX_SCAN_FOR_MODULES ON # For main.cpp, which is not in the module set technically
) )

View file

@ -1,2 +1,10 @@
add_library(tinyobjloader INTERFACE) add_library(tinyobjloader STATIC)
target_include_directories(tinyobjloader INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) target_sources(tinyobjloader PUBLIC
FILE_SET CXX_MODULES FILES
src/tiny_obj_loader.cpp)
target_include_directories(tinyobjloader PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
set_target_properties(tinyobjloader PROPERTIES
CXX_STANDARD 23
CXX_STANDARD_REQUIRED YES
CXX_EXTENSIONS NO
)

View file

@ -0,0 +1,15 @@
module;
#define TINYOBJLOADER_IMPLEMENTATION
#include <tiny_obj_loader.h>
export module tiny_obj_loader;
export namespace tinyobj {
using ::tinyobj::mesh_t;
using ::tinyobj::attrib_t;
using ::tinyobj::shape_t;
using ::tinyobj::material_t;
using ::tinyobj::index_t;
using ::tinyobj::LoadObj;
}

View file

@ -1,113 +0,0 @@
#pragma once
#include <array>
#include <glm/glm.hpp>
#include <optional>
#include <random>
#include <print>
#include <tiny_obj_loader.h>
#include "intersections.h"
#include "lighting.h"
#include "octree.h"
#include "ray.h"
constexpr glm::vec3 light_position = glm::vec3(5);
constexpr float light_bias = 0.01f;
constexpr int max_depth = 2;
inline int num_indirect_samples = 4;
struct TriangleBox {
uint64_t vertice_index = 0;
tinyobj::mesh_t* mesh;
AABB extent;
};
struct Object;
glm::vec3 fetch_position(const Object& object, const tinyobj::mesh_t& mesh, int32_t index, int32_t vertex);
glm::vec3 fetch_normal(const Object& object, const tinyobj::mesh_t& mesh, int32_t index, int32_t vertex);
struct Object {
glm::vec3 position = glm::vec3(0);
glm::vec3 color = glm::vec3(1);
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::unique_ptr<Octree<TriangleBox>> octree;
void create_octree() {
octree = std::make_unique<Octree<TriangleBox>>(glm::vec3(-2), glm::vec3(2));
for (auto& shape : shapes) {
for (size_t i = 0; i < shape.mesh.num_face_vertices.size(); i++) {
const glm::vec3 v0 = fetch_position(*this, shape.mesh, i, 0);
const glm::vec3 v1 = fetch_position(*this, shape.mesh, i, 1);
const glm::vec3 v2 = fetch_position(*this, shape.mesh, i, 2);
AABB extent{};
extent.min = glm::min(v0, v1);
extent.min = glm::min(extent.min, v2);
extent.max = glm::max(v0, v1);
extent.max = glm::max(extent.max, v2);
TriangleBox box = {};
box.vertice_index = i;
box.extent = extent;
box.mesh = &shape.mesh;
octree->add(box, box.extent);
}
}
}
};
struct Scene {
std::vector<std::unique_ptr<Object>> objects;
std::random_device rd;
std::mt19937 gen;
std::uniform_real_distribution<> dis;
Scene() : gen(rd()), dis(0.0, 1.0) {}
double distribution() {
return dis(gen);
}
Object& load_from_file(const std::string_view path) {
auto o = std::make_unique<Object>();
std::string err;
if (!tinyobj::LoadObj(&o->attrib, &o->shapes, &o->materials, &err, path.data())) [[unlikely]]
std::println("Could not load obj: {}", err);
return *objects.emplace_back(std::move(o));
}
void generate_acceleration() {
for (auto& object : objects) {
object->create_octree();
}
}
};
struct HitResult {
glm::vec3 position, normal;
const Object* object = nullptr;
};
std::optional<HitResult> test_mesh(Ray ray, const Object& object, const tinyobj::mesh_t& mesh, float& tClosest);
std::optional<HitResult> test_scene(Ray ray, const Scene& scene);
std::optional<HitResult> test_scene_octree(Ray ray, const Scene& scene);
struct SceneResult {
HitResult hit;
glm::vec3 direct, indirect, reflect, combined;
};
std::optional<SceneResult> cast_scene(Ray ray, Scene& scene, bool use_bvh, int depth = 0);

View file

@ -1,6 +1,13 @@
#pragma once module;
struct AABB { #include <cmath>
export module aabb;
import ray;
import glm;
export struct AABB {
glm::vec3 min, max; glm::vec3 min, max;
[[nodiscard]] glm::vec3 center() const { [[nodiscard]] glm::vec3 center() const {

View file

@ -1,8 +1,13 @@
#pragma once module;
#include "ray.h" #include <cstdint>
class Camera { export module camera;
import ray;
import glm;
export class Camera {
public: public:
Camera() : position(glm::vec3(0)), direction(glm::vec3(0)) {} Camera() : position(glm::vec3(0)), direction(glm::vec3(0)) {}
@ -20,7 +25,7 @@ public:
const float h2 = height / 2.0f; const float h2 = height / 2.0f;
const float w2 = width / 2.0f; const float w2 = width / 2.0f;
const glm::vec3 ray_dir = position + (h2 / tan(glm::radians(fov) / 2)) * direction + (y - h2) * up + const glm::vec3 ray_dir = position + static_cast<float>(h2 / glm::tan(glm::radians(fov) / 2)) * direction + (y - h2) * up +
static_cast<float>(x - w2) * right; static_cast<float>(x - w2) * right;
return Ray(position, ray_dir); return Ray(position, ray_dir);
} }

2676
src/glm.cpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,11 @@
#pragma once module;
#include <cstdint>
#include <array> #include <array>
#include <glm/glm.hpp>
template<class T, int Width, int Height> class Image { export module image;
export template<class T, int Width, int Height> class Image {
public: public:
void reset() { void reset() {
array = {}; array = {};

View file

@ -1,12 +1,15 @@
#pragma once module;
#include <glm/glm.hpp> #include <limits>
#include "ray.h" export module intersections;
constexpr float epsilon = std::numeric_limits<float>::epsilon(); import ray;
import glm;
namespace intersections { export constexpr float epsilon = std::numeric_limits<float>::epsilon();
export namespace intersections {
inline bool ray_sphere(const Ray ray, const glm::vec4 sphere) { inline bool ray_sphere(const Ray ray, const glm::vec4 sphere) {
const glm::vec3 diff = ray.origin - glm::vec3(sphere); const glm::vec3 diff = ray.origin - glm::vec3(sphere);
const float b = glm::dot(ray.direction, diff); const float b = glm::dot(ray.direction, diff);

View file

@ -1,8 +1,10 @@
#pragma once module;
#include <glm/glm.hpp> import glm;
namespace lighting { export module lighting;
export namespace lighting {
inline float point_light(const glm::vec3 pos, const glm::vec3 light, const glm::vec3 normal) { inline float point_light(const glm::vec3 pos, const glm::vec3 light, const glm::vec3 normal) {
const glm::vec3 dir = glm::normalize(light - pos); const glm::vec3 dir = glm::normalize(light - pos);
const float n_dot_l = glm::max(glm::dot(normal, dir), 0.0f); const float n_dot_l = glm::max(glm::dot(normal, dir), 0.0f);

View file

@ -1,24 +1,22 @@
import camera;
import glm;
import scene;
import image;
import ray;
import octree;
#include <SDL.h> #include <SDL.h>
#include <array> #include <array>
#include <future> #include <future>
#include <glm/glm.hpp>
#include <vector> #include <vector>
#define STB_IMAGE_WRITE_IMPLEMENTATION #define STB_IMAGE_WRITE_IMPLEMENTATION
#include <stb_image_write.h> #include <stb_image_write.h>
#include "camera.h"
#include "glad/glad.h" #include "glad/glad.h"
#include "image.h"
#include "imgui.h" #include "imgui.h"
#include "imgui_impl_opengl3.h" #include "imgui_impl_opengl3.h"
#include "imgui_impl_sdl.h" #include "imgui_impl_sdl.h"
#include "intersections.h"
#include "lighting.h"
#include "scene.h"
#define TINYOBJLOADER_IMPLEMENTATION
#include <tiny_obj_loader.h>
// scene information // scene information
constexpr int32_t width = 256, height = 256; constexpr int32_t width = 256, height = 256;

View file

@ -1,8 +1,12 @@
#pragma once module;
#include <memory> #include <memory>
#include <vector>
#include "aabb.h" export module octree;
import aabb;
import glm;
constexpr int max_contained_types = 16; constexpr int max_contained_types = 16;
constexpr int max_octree_depth = 2; constexpr int max_octree_depth = 2;
@ -18,7 +22,7 @@ constexpr std::array child_pattern = {
glm::vec3(-1, +1, +1), glm::vec3(-1, +1, +1),
}; };
template<typename UnderlyingType> struct Node { export template<typename UnderlyingType> struct Node {
using NodeType = Node<UnderlyingType>; using NodeType = Node<UnderlyingType>;
AABB extent; AABB extent;
@ -72,7 +76,7 @@ template<typename UnderlyingType> struct Node {
} }
}; };
template<typename UnderlyingType> struct Octree { export template<typename UnderlyingType> struct Octree {
using NodeType = Node<UnderlyingType>; using NodeType = Node<UnderlyingType>;
NodeType root; NodeType root;

View file

@ -1,8 +1,8 @@
#pragma once export module ray;
#include <glm/glm.hpp> import glm;
struct Ray { export struct Ray {
Ray(const glm::vec3 origin, const glm::vec3 direction) : origin(origin), direction(direction) {} Ray(const glm::vec3 origin, const glm::vec3 direction) : origin(origin), direction(direction) {}
glm::vec3 origin, direction; glm::vec3 origin, direction;

View file

@ -1,7 +1,122 @@
#include "scene.h" module;
#include <functional> #include <functional>
#include <numbers> #include <numbers>
#include <memory>
#include <array>
#include <optional>
#include <random>
#include <print>
export module scene;
import aabb;
import octree;
import ray;
import intersections;
import lighting;
import tiny_obj_loader;
import glm;
constexpr glm::vec3 light_position = glm::vec3(5);
constexpr float light_bias = 0.01f;
constexpr int max_depth = 2;
export inline int num_indirect_samples = 4;
struct TriangleBox {
uint64_t vertice_index = 0;
tinyobj::mesh_t* mesh;
AABB extent;
};
export struct Object;
glm::vec3 fetch_position(const Object& object, const tinyobj::mesh_t& mesh, int32_t index, int32_t vertex);
glm::vec3 fetch_normal(const Object& object, const tinyobj::mesh_t& mesh, int32_t index, int32_t vertex);
struct Object {
glm::vec3 position = glm::vec3(0);
glm::vec3 color = glm::vec3(1);
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::unique_ptr<Octree<TriangleBox>> octree;
void create_octree() {
octree = std::make_unique<Octree<TriangleBox>>(glm::vec3(-2), glm::vec3(2));
for (auto& shape : shapes) {
for (size_t i = 0; i < shape.mesh.num_face_vertices.size(); i++) {
const glm::vec3 v0 = fetch_position(*this, shape.mesh, i, 0);
const glm::vec3 v1 = fetch_position(*this, shape.mesh, i, 1);
const glm::vec3 v2 = fetch_position(*this, shape.mesh, i, 2);
AABB extent{};
extent.min = glm::min(v0, v1);
extent.min = glm::min(extent.min, v2);
extent.max = glm::max(v0, v1);
extent.max = glm::max(extent.max, v2);
TriangleBox box = {};
box.vertice_index = i;
box.extent = extent;
box.mesh = &shape.mesh;
octree->add(box, box.extent);
}
}
}
};
export struct Scene {
std::vector<std::unique_ptr<Object>> objects;
std::random_device rd;
std::mt19937 gen;
std::uniform_real_distribution<> dis;
Scene() : gen(rd()), dis(0.0, 1.0) {}
double distribution() {
return dis(gen);
}
Object& load_from_file(const std::string_view path) {
auto o = std::make_unique<Object>();
std::string err;
if (!tinyobj::LoadObj(&o->attrib, &o->shapes, &o->materials, &err, path.data())) [[unlikely]]
std::println("Could not load obj: {}", err);
return *objects.emplace_back(std::move(o));
}
void generate_acceleration() {
for (auto& object : objects) {
object->create_octree();
}
}
};
struct HitResult {
glm::vec3 position, normal;
const Object* object = nullptr;
};
std::optional<HitResult> test_mesh(Ray ray, const Object& object, const tinyobj::mesh_t& mesh, float& tClosest);
std::optional<HitResult> test_scene(Ray ray, const Scene& scene);
std::optional<HitResult> test_scene_octree(Ray ray, const Scene& scene);
struct SceneResult {
HitResult hit;
glm::vec3 direct, indirect, reflect, combined;
};
export std::optional<SceneResult> cast_scene(Ray ray, Scene& scene, bool use_bvh, int depth = 0);
glm::vec3 fetch_position(const Object& object, const tinyobj::mesh_t& mesh, const int32_t index, const int32_t vertex) { glm::vec3 fetch_position(const Object& object, const tinyobj::mesh_t& mesh, const int32_t index, const int32_t vertex) {
const tinyobj::index_t idx = mesh.indices[(index * 3) + vertex]; const tinyobj::index_t idx = mesh.indices[(index * 3) + vertex];