From f7751e0424e5b58e314dc57830aaeb6a12d748bc Mon Sep 17 00:00:00 2001 From: Johannes Schneider Date: Sat, 4 Mar 2023 19:07:59 +0100 Subject: [PATCH 1/4] [cube] Store center of the cube instead of recalculating it --- include/inexor/vulkan-renderer/world/cube.hpp | 3 ++- src/vulkan-renderer/world/cube.cpp | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/inexor/vulkan-renderer/world/cube.hpp b/include/inexor/vulkan-renderer/world/cube.hpp index 20ca84d0f..7ccec20cb 100644 --- a/include/inexor/vulkan-renderer/world/cube.hpp +++ b/include/inexor/vulkan-renderer/world/cube.hpp @@ -67,6 +67,7 @@ class Cube : public std::enable_shared_from_this { Type m_type{Type::EMPTY}; float m_size{32}; glm::vec3 m_position{0.0f, 0.0f, 0.0f}; + glm::vec3 m_center{}; /// Root cube is empty. std::weak_ptr m_parent{}; @@ -126,7 +127,7 @@ class Cube : public std::enable_shared_from_this { [[nodiscard]] std::size_t count_geometry_cubes() const noexcept; [[nodiscard]] glm::vec3 center() const noexcept { - return m_position + 0.5f * m_size; + return m_center; } [[nodiscard]] glm::vec3 position() const noexcept { diff --git a/src/vulkan-renderer/world/cube.cpp b/src/vulkan-renderer/world/cube.cpp index c7b4982b2..f1b08f98f 100644 --- a/src/vulkan-renderer/world/cube.cpp +++ b/src/vulkan-renderer/world/cube.cpp @@ -7,6 +7,7 @@ void swap(inexor::vulkan_renderer::world::Cube &lhs, inexor::vulkan_renderer::wo std::swap(lhs.m_type, rhs.m_type); std::swap(lhs.m_size, rhs.m_size); std::swap(lhs.m_position, rhs.m_position); + std::swap(lhs.m_center, rhs.m_center); std::swap(lhs.m_parent, rhs.m_parent); std::swap(lhs.m_index_in_parent, rhs.m_index_in_parent); std::swap(lhs.m_indentations, rhs.m_indentations); @@ -171,7 +172,8 @@ void Cube::rotate<3>(const RotationAxis::Type &axis) { } } -Cube::Cube(const float size, const glm::vec3 &position) : m_size(size), m_position(position) {} +Cube::Cube(const float size, const glm::vec3 &position) + : m_size(size), m_position(position), m_center(position + glm::vec3{size, size, size}) {} Cube::Cube(std::weak_ptr parent, const std::uint8_t index, const float size, const glm::vec3 &position) : Cube(size, position) { From 2152adcb56dff19c86794057db73fe034044bf24 Mon Sep 17 00:00:00 2001 From: Johannes Schneider Date: Sat, 4 Mar 2023 19:13:51 +0100 Subject: [PATCH 2/4] [cube] Fix clang-tidy warnings --- include/inexor/vulkan-renderer/world/cube.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/inexor/vulkan-renderer/world/cube.hpp b/include/inexor/vulkan-renderer/world/cube.hpp index 7ccec20cb..97d83c45f 100644 --- a/include/inexor/vulkan-renderer/world/cube.hpp +++ b/include/inexor/vulkan-renderer/world/cube.hpp @@ -76,11 +76,11 @@ class Cube : public std::enable_shared_from_this { std::uint8_t m_index_in_parent{}; /// Indentations, should only be used if it is a geometry cube. - std::array m_indentations; + std::array m_indentations{}; std::array, Cube::SUB_CUBES> m_children; /// Only geometry cube (Type::SOLID and Type::Normal) have a polygon cache. - mutable PolygonCache m_polygon_cache; + mutable PolygonCache m_polygon_cache{}; mutable bool m_polygon_cache_valid{false}; /// Removes all children recursive. From f06a9f3d079770efdd0b10d4cea294cf3b388077 Mon Sep 17 00:00:00 2001 From: Johannes Schneider Date: Sat, 4 Mar 2023 19:16:52 +0100 Subject: [PATCH 3/4] [indentation] Small code improvements --- src/vulkan-renderer/world/indentation.cpp | 32 +++++++++++------------ 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/vulkan-renderer/world/indentation.cpp b/src/vulkan-renderer/world/indentation.cpp index c6ad821b9..7b14fc229 100644 --- a/src/vulkan-renderer/world/indentation.cpp +++ b/src/vulkan-renderer/world/indentation.cpp @@ -23,49 +23,49 @@ Indentation::Indentation(const std::uint8_t uid) noexcept { } bool Indentation::operator==(const Indentation &rhs) const { - return this->m_start == rhs.m_start && this->m_end == rhs.m_end; + return m_start == rhs.m_start && m_end == rhs.m_end; } bool Indentation::operator!=(const Indentation &rhs) const { return !(*this == rhs); } -void Indentation::set_start(std::uint8_t position) noexcept { - this->m_start = std::clamp(position, 0, Indentation::MAX); - this->m_end = std::clamp(this->m_end, this->m_start, Indentation::MAX); +void Indentation::set_start(const std::uint8_t position) noexcept { + m_start = std::clamp(position, 0, Indentation::MAX); + m_end = std::clamp(m_end, m_start, Indentation::MAX); } -void Indentation::set_end(std::uint8_t position) noexcept { - this->m_end = std::clamp(position, 0, Indentation::MAX); - this->m_start = std::clamp(this->m_start, 0, this->m_end); +void Indentation::set_end(const std::uint8_t position) noexcept { + m_end = std::clamp(position, 0, Indentation::MAX); + m_start = std::clamp(m_start, 0, m_end); } std::uint8_t Indentation::start_abs() const noexcept { - return this->m_start; + return m_start; } std::uint8_t Indentation::end_abs() const noexcept { - return this->m_end; + return m_end; } std::uint8_t Indentation::start() const noexcept { - return this->m_start; + return m_start; } std::uint8_t Indentation::end() const noexcept { - return Indentation::MAX - this->m_end; + return Indentation::MAX - m_end; } std::uint8_t Indentation::offset() const noexcept { - return this->m_end - this->m_start; + return m_end - m_start; } -void Indentation::indent_start(std::uint8_t steps) noexcept { - this->set_start(this->m_start + steps); +void Indentation::indent_start(const std::uint8_t steps) noexcept { + set_start(m_start + steps); } -void Indentation::indent_end(std::uint8_t steps) noexcept { - this->set_end(this->m_end - steps); +void Indentation::indent_end(const std::uint8_t steps) noexcept { + set_end(m_end - steps); } void Indentation::mirror() noexcept { From 6680b5104952cd76eed59a10c7e042f10c6e693f Mon Sep 17 00:00:00 2001 From: Johannes Schneider Date: Sat, 4 Mar 2023 19:31:32 +0100 Subject: [PATCH 4/4] [*] Remove old collision code --- benchmarks/CMakeLists.txt | 2 - benchmarks/world/cube_collision.cpp | 23 --- .../inexor/vulkan-renderer/application.hpp | 1 - .../vulkan-renderer/world/collision.hpp | 60 ------ .../vulkan-renderer/world/collision_query.hpp | 39 ---- src/CMakeLists.txt | 2 - src/vulkan-renderer/application.cpp | 22 +-- src/vulkan-renderer/world/collision.cpp | 183 ------------------ src/vulkan-renderer/world/collision_query.cpp | 132 ------------- tests/CMakeLists.txt | 1 - tests/world/cube_collision.cpp | 31 --- 11 files changed, 1 insertion(+), 495 deletions(-) delete mode 100644 benchmarks/world/cube_collision.cpp delete mode 100644 include/inexor/vulkan-renderer/world/collision.hpp delete mode 100644 include/inexor/vulkan-renderer/world/collision_query.hpp delete mode 100644 src/vulkan-renderer/world/collision.cpp delete mode 100644 src/vulkan-renderer/world/collision_query.cpp delete mode 100644 tests/world/cube_collision.cpp diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 33239ad05..a3437606a 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -1,7 +1,5 @@ set(INEXOR_BENCHMARKING_SOURCE_FILES engine_benchmark_main.cpp - - world/cube_collision.cpp ) add_executable(inexor-vulkan-renderer-benchmarks ${INEXOR_BENCHMARKING_SOURCE_FILES}) diff --git a/benchmarks/world/cube_collision.cpp b/benchmarks/world/cube_collision.cpp deleted file mode 100644 index 32b307559..000000000 --- a/benchmarks/world/cube_collision.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include - -#include -#include - -namespace inexor::vulkan_renderer { - -void CubeCollision(benchmark::State &state) { - for (auto _ : state) { - const glm::vec3 world_pos{0, 0, 0}; - world::Cube world(1.0f, world_pos); - world.set_type(world::Cube::Type::SOLID); - - glm::vec3 cam_pos{0.0f, 0.0f, 10.0f}; - glm::vec3 cam_direction{0.0f, 0.0f, -1.0f}; - - benchmark::DoNotOptimize(ray_cube_collision_check(world, cam_pos, cam_direction)); - } -} - -BENCHMARK(CubeCollision); - -} // namespace inexor::vulkan_renderer diff --git a/include/inexor/vulkan-renderer/application.hpp b/include/inexor/vulkan-renderer/application.hpp index 7190a475b..a9e9ecddd 100644 --- a/include/inexor/vulkan-renderer/application.hpp +++ b/include/inexor/vulkan-renderer/application.hpp @@ -2,7 +2,6 @@ #include "inexor/vulkan-renderer/input/keyboard_mouse_data.hpp" #include "inexor/vulkan-renderer/renderer.hpp" -#include "inexor/vulkan-renderer/world/collision_query.hpp" #include "inexor/vulkan-renderer/world/cube.hpp" #include diff --git a/include/inexor/vulkan-renderer/world/collision.hpp b/include/inexor/vulkan-renderer/world/collision.hpp deleted file mode 100644 index 707852512..000000000 --- a/include/inexor/vulkan-renderer/world/collision.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include - -#include -#include - -namespace inexor::vulkan_renderer::world { - -/// @brief A wrapper for collisions between a ray and octree geometry. -/// This class is used for octree collision, but it can be used for every cube-like data structure -/// @tparam T A template type which offers a size() and center() method. -template -class RayCubeCollision { - const T &m_cube; - - glm::vec3 m_intersection; - glm::vec3 m_selected_face; - glm::vec3 m_nearest_corner; - glm::vec3 m_nearest_edge; - -public: - /// @brief Calculate point of intersection, selected face, - /// nearest corner on that face, and nearest edge on that face. - /// @param cube The cube to check for collision. - /// @param ray_pos The start point of the ray. - /// @param ray_dir The direction of the ray. - RayCubeCollision(const T &cube, glm::vec3 ray_pos, glm::vec3 ray_dir); - - RayCubeCollision(const RayCubeCollision &) = delete; - - RayCubeCollision(RayCubeCollision &&other) noexcept; - - ~RayCubeCollision() = default; - - RayCubeCollision &operator=(const RayCubeCollision &) = delete; - RayCubeCollision &operator=(RayCubeCollision &&) = delete; - - [[nodiscard]] const T &cube() const noexcept { - return m_cube; - } - - [[nodiscard]] const glm::vec3 &intersection() const noexcept { - return m_intersection; - } - - [[nodiscard]] const glm::vec3 &face() const noexcept { - return m_selected_face; - } - - [[nodiscard]] const glm::vec3 &corner() const noexcept { - return m_nearest_corner; - } - - [[nodiscard]] const glm::vec3 &edge() const noexcept { - return m_nearest_edge; - } -}; - -} // namespace inexor::vulkan_renderer::world diff --git a/include/inexor/vulkan-renderer/world/collision_query.hpp b/include/inexor/vulkan-renderer/world/collision_query.hpp deleted file mode 100644 index bf96e0524..000000000 --- a/include/inexor/vulkan-renderer/world/collision_query.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include "inexor/vulkan-renderer/world/collision.hpp" - -#include - -#include - -// Forward declaration -namespace inexor::vulkan_renderer::world { -class Cube; -} // namespace inexor::vulkan_renderer::world - -namespace inexor::vulkan_renderer::world { - -// TODO: Implement PointCubeCollision - -/// @brief ``True`` of the ray build from the two vectors collides with the cube's bounding box. -/// @note There is no such function as glm::intersectRayBox. -/// @param box_bounds An array of two vectors which represent the edges of the bounding box. -/// @param pos The start position of the ray. -/// @param dir The direction of the ray. -/// @return ``True`` if the ray collides with the octree cube's bounding box. -[[nodiscard]] bool ray_box_collision(std::array &box_bounds, glm::vec3 &pos, glm::vec3 &dir); - -/// @brief Check for a collision between a camera ray and octree geometry. -/// @param cube The cube to check collisions with. -/// @param pos The camera position. -/// @param dir The camera view direction. -/// @param max_depth The maximum subcube iteration depth. If this depth is reached and the cube is an octant, it -/// will be treated as if it was a solid cube. This is the foundation for the implementation of grid size in octree -/// editor. -/// @note This does not account yet for octree indentation! -/// @return A std::optional which contains the collision data (if any found). -[[nodiscard]] std::optional> -ray_cube_collision_check(const Cube &cube, glm::vec3 pos, glm::vec3 dir, - std::optional max_depth = std::nullopt); - -} // namespace inexor::vulkan_renderer::world diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 026aadd14..bffa60d95 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -42,8 +42,6 @@ set(INEXOR_SOURCE_FILES vulkan-renderer/wrapper/window.cpp vulkan-renderer/wrapper/window_surface.cpp - vulkan-renderer/world/collision.cpp - vulkan-renderer/world/collision_query.cpp vulkan-renderer/world/cube.cpp vulkan-renderer/world/indentation.cpp) diff --git a/src/vulkan-renderer/application.cpp b/src/vulkan-renderer/application.cpp index c1118c5ff..5918f84ff 100644 --- a/src/vulkan-renderer/application.cpp +++ b/src/vulkan-renderer/application.cpp @@ -6,7 +6,6 @@ #include "inexor/vulkan-renderer/standard_ubo.hpp" #include "inexor/vulkan-renderer/tools/cla_parser.hpp" #include "inexor/vulkan-renderer/vk_tools/enumerate.hpp" -#include "inexor/vulkan-renderer/world/collision.hpp" #include "inexor/vulkan-renderer/world/cube.hpp" #include "inexor/vulkan-renderer/wrapper/cpu_texture.hpp" #include "inexor/vulkan-renderer/wrapper/descriptor_builder.hpp" @@ -584,26 +583,7 @@ void Application::process_mouse_input() { m_camera->set_movement_state(CameraMovement::RIGHT, m_input_data->is_key_pressed(GLFW_KEY_D)); } -void Application::check_octree_collisions() { - // Check for collision between camera ray and every octree - for (const auto &world : m_worlds) { - const auto collision = ray_cube_collision_check(*world, m_camera->position(), m_camera->front()); - - if (collision) { - const auto intersection = collision.value().intersection(); - const auto face_normal = collision.value().face(); - const auto corner = collision.value().corner(); - const auto edge = collision.value().edge(); - - spdlog::trace("pos {} {} {} | face {} {} {} | corner {} {} {} | edge {} {} {}", intersection.x, - intersection.y, intersection.z, face_normal.x, face_normal.y, face_normal.z, corner.x, - corner.y, corner.z, edge.x, edge.y, edge.z); - - // Break after one collision. - break; - } - } -} +void Application::check_octree_collisions() {} void Application::run() { spdlog::trace("Running Application"); diff --git a/src/vulkan-renderer/world/collision.cpp b/src/vulkan-renderer/world/collision.cpp deleted file mode 100644 index 613f95bd0..000000000 --- a/src/vulkan-renderer/world/collision.cpp +++ /dev/null @@ -1,183 +0,0 @@ -#include - -#include - -#include -#include - -#include -#include -#include -#include - -namespace inexor::vulkan_renderer::world { - -template -RayCubeCollision::RayCubeCollision(RayCubeCollision &&other) noexcept : m_cube{other.m_cube} { - m_intersection = other.m_intersection; - m_selected_face = other.m_selected_face; - m_nearest_corner = other.m_nearest_corner; - m_nearest_edge = other.m_nearest_edge; -} - -template -RayCubeCollision::RayCubeCollision(const T &cube, const glm::vec3 ray_pos, const glm::vec3 ray_dir) : m_cube(cube) { - - // This lambda adjusts the center points on a cube's face to the size of the octree, - // so collision works with cubes of any size. This does not yet account for rotations! - const auto adjust_coordinates = [&](const glm::vec3 pos) { - // TODO: Take rotation of the cube into account. - return m_cube.center() + pos * (m_cube.size() / 2); - }; - - // x: left/right, y: front/back, z: top/bottom. - static constexpr std::array BBOX_DIRECTIONS{ - glm::vec3(-1.0f, 0.0f, 0.0f), // left - glm::vec3(1.0f, 0.0f, 0.0f), // right - glm::vec3(0.0f, -1.0f, 0.0f), // front - glm::vec3(0.0f, 1.0f, 0.0f), // back - glm::vec3(0.0f, 0.0f, 1.0f), // top - glm::vec3(0.0f, 0.0f, -1.0f) // bottom - }; - - // The coordinates of the center of every face of the cube. - const std::array bbox_face_centers{adjust_coordinates(BBOX_DIRECTIONS[0]), // left - adjust_coordinates(BBOX_DIRECTIONS[1]), // right - adjust_coordinates(BBOX_DIRECTIONS[2]), // front - adjust_coordinates(BBOX_DIRECTIONS[3]), // back - adjust_coordinates(BBOX_DIRECTIONS[4]), // top - adjust_coordinates(BBOX_DIRECTIONS[5])}; // bottom - - const std::array bbox_corners{adjust_coordinates({-1.0f, -1.0f, -1.0f}), // left front bottom - adjust_coordinates({-1.0f, -1.0f, 1.0f}), // left front top - adjust_coordinates({-1.0f, 1.0f, -1.0f}), // left back bottom - adjust_coordinates({-1.0f, 1.0f, 1.0f}), // left back top - adjust_coordinates({1.0f, -1.0f, -1.0f}), // right front bottom - adjust_coordinates({1.0f, -1.0f, 1.0f}), // right front top - adjust_coordinates({1.0f, 1.0f, 1.0f}), // right back bottom - adjust_coordinates({1.0f, 1.0f, -1.0f})}; // right back top - - using bbox_corner_on_face_index = std::array; - - // These indices specify which 4 points describe the corners on the given face. - static constexpr std::array BBOX_CORNERS_ON_FACE_INDICES{ - bbox_corner_on_face_index{0, 1, 2, 3}, // left - bbox_corner_on_face_index{4, 5, 6, 7}, // right - bbox_corner_on_face_index{0, 1, 4, 5}, // front - bbox_corner_on_face_index{2, 3, 6, 7}, // back - bbox_corner_on_face_index{1, 3, 5, 7}, // top - bbox_corner_on_face_index{0, 2, 4, 6} // bottom - }; - - // The coordinates of the center of every edge of the cube. - const std::array bbox_edges{adjust_coordinates({-1.0f, 0.0f, 1.0f}), // left top - adjust_coordinates({-1.0f, 1.0f, 0.0f}), // left front - adjust_coordinates({-1.0f, 0.0f, -1.0f}), // left bottom - adjust_coordinates({-1.0f, -1.0f, 0.0f}), // left back - adjust_coordinates({1.0f, 0.0f, 1.0f}), // right top - adjust_coordinates({1.0f, 1.0f, 0.0f}), // right front - adjust_coordinates({1.0f, 0.0f, -1.0f}), // right bottom - adjust_coordinates({1.0f, -1.0f, 0.0f}), // right back - adjust_coordinates({0.0f, -1.0f, -1.0f}), // middle bottom front - adjust_coordinates({0.0f, 1.0f, -1.0f}), // middle bottom back - adjust_coordinates({0.0f, -1.0f, 1.0f}), // middle top front - adjust_coordinates({0.0f, 1.0f, 1.0f})}; // middle top back - - using edge_on_face_index = std::array; - - // These indices specify which 4 edges are associated with a given face of the bounding box. - static constexpr std::array BBOX_EDGE_ON_FACE_INDICES{ - edge_on_face_index{0, 1, 2, 3}, // left - edge_on_face_index{4, 5, 6, 7}, // right - edge_on_face_index{1, 5, 8, 11}, // front - edge_on_face_index{3, 7, 9, 11}, // back - edge_on_face_index{0, 4, 10, 11}, // top - edge_on_face_index{2, 6, 8, 9} // bottom - }; - - /// @brief Determine the intersection point between a ray and a plane. - /// @note This function is not available in glm. - /// @param plane_pos The position of the plane. - /// @param plane_norm The normal vector of the plane. - /// @param ray_pos Point a on the ray. - /// @param ray_dir Point b on the ray. - const auto ray_plane_intersection_point = [&](const glm::vec3 &plane_pos, const glm::vec3 &plane_norm, - const glm::vec3 &ray_pos, const glm::vec3 &ray_dir) { - return ray_pos - ray_dir * (glm::dot((ray_pos - plane_pos), plane_norm) / glm::dot(ray_dir, plane_norm)); - }; - - /// @brief As soon as we determined which face is selected and we calculated the intersection point between the - /// ray and the face plane, we need to determine the nearest corner in that face and the nearest edge on that - /// face. In order to determine the nearest corner on a selected face for example, we would iterate through all - /// corners on the selected face and calculate the distance between the intersection point and the corner's - /// coordinates. The corner which is closest to the intersection point is the selected corner. - /// However, we should not use ``glm::distance`` for this, because it performs a ``sqrt`` calculation on the - /// vector coordinates. This is not necessary in this case, as we are not interested in the exact distance but - /// rather in a value which allows us to determine the nearest corner. This means we can use the squared - /// distance, which allows us to avoid the costly call of ``sqrt``. - /// @param pos1 The first point. - /// @param pos2 The second point. - const auto square_of_distance = [&](const std::array &points) { - return glm::distance2(points[0], points[1]); - }; - - float shortest_squared_distance{std::numeric_limits::max()}; - float squared_distance{std::numeric_limits::max()}; - - // The index of the array which contains the coordinates of the face centers of the cube's bounding box. - std::size_t selected_face_index{0}; - - // Loop though all faces of the cube and check for collision between ray and face plane. - for (std::size_t i = 0; i < 6; i++) { - - // Check if the cube side is facing the camera: if the dot product of the two vectors is smaller than - // zero, the corresponding angle is smaller than 90 degrees, so the side is facing the camera. Check the - // references page for a detailed explanation of this formula. - if (glm::dot(BBOX_DIRECTIONS[i], ray_dir) < 0.0f) { - - const auto intersection = - ray_plane_intersection_point(bbox_face_centers[i], BBOX_DIRECTIONS[i], ray_pos, ray_dir); - - squared_distance = square_of_distance({m_cube.center(), intersection}); - - if (squared_distance < shortest_squared_distance) { - selected_face_index = i; - shortest_squared_distance = squared_distance; - m_intersection = intersection; - m_selected_face = bbox_face_centers[i]; - } - } - } - - // Reset value to maximum for the search of the closest corner. - shortest_squared_distance = std::numeric_limits::max(); - - // Loop through all corners of this face and check for the nearest one. - for (const auto corner_index : BBOX_CORNERS_ON_FACE_INDICES[selected_face_index]) { - squared_distance = square_of_distance({bbox_corners[corner_index], m_intersection}); - - if (squared_distance < shortest_squared_distance) { - shortest_squared_distance = squared_distance; - m_nearest_corner = bbox_corners[corner_index]; - } - } - - // Reset value to maximum for the search of the closest edge. - shortest_squared_distance = std::numeric_limits::max(); - - // Iterate through all edges on this face and select the nearest one. - for (const auto edge_index : BBOX_EDGE_ON_FACE_INDICES[selected_face_index]) { - - squared_distance = square_of_distance({bbox_edges[edge_index], m_intersection}); - - if (squared_distance < shortest_squared_distance) { - shortest_squared_distance = squared_distance; - m_nearest_edge = bbox_edges[edge_index]; - } - } -} - -// Explicit instantiation -template RayCubeCollision::RayCubeCollision(const Cube &, const glm::vec3, const glm::vec3); - -} // namespace inexor::vulkan_renderer::world diff --git a/src/vulkan-renderer/world/collision_query.cpp b/src/vulkan-renderer/world/collision_query.cpp deleted file mode 100644 index 977bd6907..000000000 --- a/src/vulkan-renderer/world/collision_query.cpp +++ /dev/null @@ -1,132 +0,0 @@ -#include "inexor/vulkan-renderer/world/collision_query.hpp" - -#include - -#include -#include - -namespace inexor::vulkan_renderer::world { - -bool ray_box_collision(const std::array &box_bounds, const glm::vec3 &position, - const glm::vec3 &direction) { - glm::vec3 inverse_dir{1 / direction.x, 1 / direction.y, 1 / direction.z}; - std::array sign{static_cast(inverse_dir.x < 0), - static_cast(inverse_dir.y < 0), - static_cast(inverse_dir.z < 0)}; - - float tmin{(box_bounds[sign[0]].x - position.x) * inverse_dir.x}; - float tmax{(box_bounds[1 - sign[0]].x - position.x) * inverse_dir.x}; - float tymin{(box_bounds[sign[1]].y - position.y) * inverse_dir.y}; - float tymax{(box_bounds[1 - sign[1]].y - position.y) * inverse_dir.y}; - - if ((tmin > tymax) || (tymin > tmax)) { - return false; - } - if (tymin > tmin) { - tmin = tymin; - } - if (tymax < tmax) { - tmax = tymax; - } - - float tzmin{(box_bounds[sign[2]].z - position.z) * inverse_dir.z}; - float tzmax{(box_bounds[1 - sign[2]].z - position.z) * inverse_dir.z}; - - return !((tmin > tzmax) || (tzmin > tmax)); -} - -std::optional> ray_cube_collision_check(const Cube &cube, const glm::vec3 pos, - const glm::vec3 dir, - const std::optional max_depth) { - // If the cube is empty, a collision with a ray is not possible, - // and there are no sub cubes to check for collision either. - if (cube.type() == Cube::Type::EMPTY) { - // No collision found. - return std::nullopt; - } - - // We need to pass this into glm::intersectRaySphere by reference, - // although we are not interested into it. - auto intersection_distance{0.0f}; - - const auto bounding_sphere_radius = static_cast(glm::sqrt(3) * cube.size()) / 2.0f; - - const auto sphere_radius_squared = static_cast(std::pow(bounding_sphere_radius, 2)); - - // First, check if ray collides with bounding sphere. - // This is much easier to calculate than a collision with a bounding box. - if (!glm::intersectRaySphere(pos, dir, cube.center(), sphere_radius_squared, intersection_distance)) { - // No collision found. - return std::nullopt; - } - - // Second, check if ray collides with bounding box. - // This again is also much faster than to check for collision with every one of the 8 sub cubes. - // TODO: This is an axis aligned bounding box! Alignment must account for rotation in the future! - if (!ray_box_collision(cube.bounding_box(), pos, dir)) { - // No collision found. - return std::nullopt; - } - - if (cube.type() == Cube::Type::OCTANT) { - std::size_t hit_candidate_count{0}; - std::size_t collision_subcube_index{0}; - float m_nearest_square_distance = std::numeric_limits::max(); - auto subcubes = cube.children(); - - if (max_depth.has_value()) { - // Check if the maximum depth is reached. - if (max_depth.value() == 0) { - // If the maximum depth is reached but the cube is empty, no collision was found. - if (cube.type() == Cube::Type::EMPTY) { - return std::nullopt; - } - - // The current cube is of type OCTANT but not of type SOLID, but since we reached the maximum depth of - // iteration, we treat it as type SOLID. - return std::make_optional>(cube, pos, dir); - } - } - - // Iterate through all sub cubes and check for collision. - for (std::int32_t i = 0; i < 8; i++) { - if (subcubes[i]->type() != Cube::Type::EMPTY) { - const std::optional next_depth = - max_depth.has_value() ? std::make_optional(max_depth.value() - 1) : std::nullopt; - - // No value for maximum depth given. Continue iterating until you find a leaf node of type SOLID. - if (ray_cube_collision_check(*subcubes[i], pos, dir, next_depth)) { - hit_candidate_count++; - - // If a ray collides with an octant, it can collide with multiple child cubes as it goes - // through it. We need to find the cube which is nearest to the camera and also in front of - // the camera. - const auto squared_distance = glm::distance2(subcubes[i]->center(), pos); - - if (squared_distance < m_nearest_square_distance) { - collision_subcube_index = i; - m_nearest_square_distance = squared_distance; - } - } - } - - // If a ray goes through a cube of 8 subcubes, no more than 4 collisions can take place. - if (hit_candidate_count == 4) { - break; - } - } - - if (hit_candidate_count > 0) { - return std::make_optional>(*subcubes[collision_subcube_index], pos, dir); - } - } else if (cube.type() == Cube::Type::SOLID) { - // We found a leaf collision. Now we need to determine the selected face, - // nearest corner to intersection point and nearest edge to intersection point. - return std::make_optional>(cube, pos, dir); - } - - // No collision found. - return std::nullopt; -} - -} // namespace inexor::vulkan_renderer::world diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6f38ab32d..fc0c68b39 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,7 +5,6 @@ set(INEXOR_UNIT_TEST_SOURCE_FILES swapchain/choose_settings.cpp - world/cube_collision.cpp world/cube.cpp ) diff --git a/tests/world/cube_collision.cpp b/tests/world/cube_collision.cpp deleted file mode 100644 index ce319d676..000000000 --- a/tests/world/cube_collision.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include - -#include -#include - -namespace inexor::vulkan_renderer { - -TEST(CubeCollision, CollisionCheck) { - const glm::vec3 world_pos{0, 0, 0}; - world::Cube world(1.0f, world_pos); - world.set_type(world::Cube::Type::SOLID); - - glm::vec3 cam_pos{0.0f, 0.0f, 10.0f}; - glm::vec3 cam_direction{0.0f, 0.0f, 0.0f}; - - auto collision1 = ray_cube_collision_check(world, cam_pos, cam_direction); - bool collision_found = collision1.has_value(); - - // There must be no collision for this data setup. - EXPECT_FALSE(collision_found); - - cam_direction = {0.0f, 0.0f, -1.0f}; - - auto collision2 = ray_cube_collision_check(world, cam_pos, cam_direction); - collision_found = collision2.has_value(); - - // Since we are now directly looking down on the cube, we collide with it. - EXPECT_TRUE(collision_found); -} - -} // namespace inexor::vulkan_renderer