diff --git a/CMakeLists.txt b/CMakeLists.txt index b7da388..936033f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,17 +11,6 @@ set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/external/vcpkg/scripts/buil project(RayTracer) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/build) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/build) -#Workaround for vs, because it places artifacts into an additional subfolder -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_SOURCE_DIR}/build) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_SOURCE_DIR}/build) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_CURRENT_SOURCE_DIR}/build) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL ${CMAKE_CURRENT_SOURCE_DIR}/build) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_SOURCE_DIR}/build) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_SOURCE_DIR}/build) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_CURRENT_SOURCE_DIR}/build) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL ${CMAKE_CURRENT_SOURCE_DIR}/build) find_package(assimp CONFIG REQUIRED) find_package(glfw3 CONFIG REQUIRED) @@ -29,6 +18,7 @@ find_package(glm CONFIG REQUIRED) find_package(Ktx CONFIG REQUIRED) add_executable(RayTracer "") +target_include_directories(RayTracer PUBLIC src/) target_link_libraries(RayTracer PUBLIC assimp::assimp) target_link_libraries(RayTracer PUBLIC glfw) target_link_libraries(RayTracer PUBLIC glm::glm) diff --git a/cube.fbx b/cube.fbx new file mode 100644 index 0000000..0c8add8 Binary files /dev/null and b/cube.fbx differ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b42a2ac..0c915d9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,3 +4,4 @@ target_sources(RayTracer add_subdirectory(scene/) add_subdirectory(window/) +add_subdirectory(util/) diff --git a/src/main.cpp b/src/main.cpp index 90d2268..69ebc94 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,11 @@ #include "window/Window.h" +#include "util/ModelLoader.h" +#include "scene/BVH.h" int main() { + BVH bvh; + bvh.addModels(ModelLoader::loadModel("../../cube.fbx")); + bvh.generate(); Window w(1920, 1080); while (true) { w.update(); diff --git a/src/scene/AABB.h b/src/scene/AABB.h new file mode 100644 index 0000000..f11ea1e --- /dev/null +++ b/src/scene/AABB.h @@ -0,0 +1,38 @@ +#pragma once +#include +#include + +struct AABB +{ + glm::vec3 min = glm::vec3(std::numeric_limits::max()); + glm::vec3 max = glm::vec3(std::numeric_limits::lowest()); + float surfaceArea() const + { + glm::vec3 d = glm::vec3(max.x - min.x, max.y - min.y, max.z - min.z); + return 2.0f * (d.x * d.y + d.y * d.z + d.z * d.x); + } + void adjust(glm::vec3 pos) + { + min.x = std::min(min.x, pos.x); + min.y = std::min(min.y, pos.y); + min.z = std::min(min.z, pos.z); + + max.x = std::max(max.x, pos.x); + max.y = std::max(max.y, pos.y); + max.z = std::max(max.z, pos.z); + } + static AABB combine(AABB lhs, AABB rhs) + { + AABB result; + + result.min.x = std::min(lhs.min.x, rhs.min.x); + result.min.y = std::min(lhs.min.y, rhs.min.y); + result.min.z = std::min(lhs.min.z, rhs.min.z); + + result.max.x = std::max(lhs.max.x, rhs.max.x); + result.max.y = std::max(lhs.max.y, rhs.max.y); + result.max.z = std::max(lhs.max.z, rhs.max.z); + + return result; + } +}; diff --git a/src/scene/BVH.cpp b/src/scene/BVH.cpp index 6e24743..e0c1703 100644 --- a/src/scene/BVH.cpp +++ b/src/scene/BVH.cpp @@ -1 +1,51 @@ -#include "BVH.h" \ No newline at end of file +#include "BVH.h" +#include + +void BVH::addModel(PModel model) { models.push_back(std::move(model)); } + +void BVH::addModels(std::vector _models) +{ + for (int i = 0; i < _models.size(); ++i) + { + models.push_back(std::move(_models[i])); + } +} + +void BVH::generate() +{ + std::vector pendingNodes; + while (!models.empty()) + { + pendingNodes.push_back(std::make_unique(std::move(models.back()))); + models.pop_back(); + } + while (pendingNodes.size() > 1) + { + int lhs = pendingNodes.size(); + int rhs = pendingNodes.size(); + float minSurface = std::numeric_limits::max(); + for (int i = 0; i < pendingNodes.size(); ++i) + { + for (int j = 0; j < pendingNodes.size(); ++j) + { + if (i == j) + continue; + AABB combined = AABB::combine(pendingNodes[i]->aabb, pendingNodes[j]->aabb); + float surface = combined.surfaceArea(); + if (minSurface > surface) + { + lhs = i; + rhs = j; + minSurface = surface; + } + } + } + PNode newNode = std::make_unique(AABB::combine(pendingNodes[lhs]->aabb, pendingNodes[rhs]->aabb)); + newNode->left = std::move(pendingNodes[lhs]); + newNode->right = std::move(pendingNodes[rhs]); + pendingNodes.erase(pendingNodes.begin() + lhs); + pendingNodes.erase(pendingNodes.begin() + rhs); + pendingNodes.push_back(std::move(newNode)); + } + hierarchy = std::move(pendingNodes[0]); +} diff --git a/src/scene/BVH.h b/src/scene/BVH.h index 5aae953..28cb6f9 100644 --- a/src/scene/BVH.h +++ b/src/scene/BVH.h @@ -1,15 +1,26 @@ #pragma once -#include +#include "AABB.h" +#include "util/Model.h" #include -struct AABB { - glm::vec3 min; - glm::vec3 max; -}; - class BVH { -public: -private: - std::vector boundingBoxes; + public: + void addModel(PModel model); + void addModels(std::vector models); + void generate(); + + private: + DECLARE_REF(Node) + struct Node + { + PNode left; + PNode right; + AABB aabb; + PModel model; + Node(AABB aabb) : aabb(aabb) {} + Node(PModel model) : aabb(model->boundingBox), model(std::move(model)) {} + }; + PNode hierarchy; + std::vector models; }; \ No newline at end of file diff --git a/src/scene/CMakeLists.txt b/src/scene/CMakeLists.txt index 3319d65..2156aa6 100644 --- a/src/scene/CMakeLists.txt +++ b/src/scene/CMakeLists.txt @@ -1,4 +1,7 @@ target_sources(RayTracer PRIVATE + AABB.h + BVH.h + BVH.cpp Scene.h Scene.cpp) \ No newline at end of file diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 8e79e3f..4d96c4f 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -4,4 +4,5 @@ target_sources(RayTracer Model.cpp ModelLoader.h ModelLoader.cpp + Ray.h ) \ No newline at end of file diff --git a/src/util/Model.h b/src/util/Model.h index efee0e6..8d884d4 100644 --- a/src/util/Model.h +++ b/src/util/Model.h @@ -1,11 +1,12 @@ #pragma once #include "Minimal.h" +#include "scene/AABB.h" #include -#include class Model { public: + AABB boundingBox; std::vector positions; std::vector indices; }; diff --git a/src/util/ModelLoader.cpp b/src/util/ModelLoader.cpp index 793d2a3..b96b618 100644 --- a/src/util/ModelLoader.cpp +++ b/src/util/ModelLoader.cpp @@ -8,22 +8,28 @@ std::vector ModelLoader::loadModel(std::string_view filename) { Assimp::Importer importer; - const aiScene* scene = importer.ReadFile(filename, 0); + const aiScene* scene = importer.ReadFile(std::string(filename), aiProcess_Triangulate); + std::vector result; for (int m = 0; m < scene->mNumMeshes; ++m) { - PModel result = std::make_unique(); + PModel model = std::make_unique(); const aiMesh* mesh = scene->mMeshes[m]; + AABB aabb; for (int v = 0; v < mesh->mNumVertices; ++v) { auto aiVert = mesh->mVertices[v]; - result->positions.add(glm::vec3(aiVert.x, aiVert.y, aiVert.z)); + model->positions.push_back(glm::vec3(aiVert.x, aiVert.y, aiVert.z)); + aabb.adjust(model->positions.back()); } for (int i = 0; i < mesh->mNumFaces; ++i) { auto face = mesh->mFaces[i]; - result->indices.add(face.mIndices[0]); - result->indices.add(face.mIndices[1]); - result->indices.add(face.mIndices[2]); + model->indices.push_back(face.mIndices[0]); + model->indices.push_back(face.mIndices[1]); + model->indices.push_back(face.mIndices[2]); } + model->boundingBox = aabb; + result.push_back(std::move(model)); } + return result; } diff --git a/src/util/ModelLoader.h b/src/util/ModelLoader.h index 4632a5a..a1c0476 100644 --- a/src/util/ModelLoader.h +++ b/src/util/ModelLoader.h @@ -1,5 +1,6 @@ #pragma once #include "Model.h" +#include class ModelLoader { diff --git a/src/util/Ray.h b/src/util/Ray.h new file mode 100644 index 0000000..e69de29