From da34d60f7ee178651374404851564f12e2bc3364 Mon Sep 17 00:00:00 2001 From: Johannes Schneider Date: Sat, 24 Jul 2021 17:54:18 +0200 Subject: [PATCH] [collision-solver] Avoid unnecessary memory allocations --- .../world/collision_solver.hpp | 22 ++++++------ src/vulkan-renderer/application.cpp | 5 ++- .../world/collision_solver.cpp | 36 +++++++++---------- 3 files changed, 30 insertions(+), 33 deletions(-) diff --git a/include/inexor/vulkan-renderer/world/collision_solver.hpp b/include/inexor/vulkan-renderer/world/collision_solver.hpp index d2eba8822..92d2810ab 100644 --- a/include/inexor/vulkan-renderer/world/collision_solver.hpp +++ b/include/inexor/vulkan-renderer/world/collision_solver.hpp @@ -16,44 +16,42 @@ namespace inexor::vulkan_renderer::world { class OctreeCollisionSolver { private: - std::vector, float>> m_collision_candidates{}; + const std::vector> m_worlds; + std::vector, float>> m_collision_candidates; std::shared_mutex m_collision_solver_mutex; /// @brief Find all collisions between the given ray and the given octrees, sorted by increasing distance between /// the octree and the camera. - /// @param worlds The octrees to check for collision /// @param position The start position of the ray /// @param direction The direction vector of the ray /// @return A vector of the found collisions. If no collisions were found, the vector is empty. [[nodiscard]] std::vector> - find_all_ray_octree_collisions(const std::vector> &worlds, glm::vec3 position, - glm::vec3 direction, bool find_only_one_collision = true); + find_all_ray_octree_collisions(glm::vec3 position, glm::vec3 direction, bool find_only_one_collision = true); public: + /// @brief Default constructor + /// @param worlds The octree worlds to test collision with + explicit OctreeCollisionSolver(const std::vector> &worlds); // TODO: Implement min/max collision distance if required. // TODO: Start sorting octrees by distance to camera only after a certain number of worlds. // TODO: Implement a bounding volume hierarchy (BVH) tree, for example an octree for all the octrees. /// @brief Find a collision between a ray and an octree which is closest to the camera. - /// @param worlds The octrees to check for collision /// @param position The start position of the ray /// @param direction The direction vector of the ray /// @return The collision data - [[nodiscard]] std::optional> - find_ray_octree_collision(const std::vector> &worlds, glm::vec3 position, - glm::vec3 direction); + [[nodiscard]] std::optional> find_ray_octree_collision(glm::vec3 position, + glm::vec3 direction); /// @brief Find all collisions between the given ray and the given octrees, sorted by increasing distance between /// the octree and the camera. /// @note Expect this method to be more costly than find_ray_octree_collision! - /// @param worlds The octrees to check for collision /// @param position The start position of the ray /// @param direction The direction vector of the ray /// @return A vector of the found collisions. If no collisions were found, the vector is empty. - [[nodiscard]] std::vector> - find_all_ray_octree_collisions(const std::vector> &worlds, glm::vec3 position, - glm::vec3 direction); + [[nodiscard]] std::vector> find_all_ray_octree_collisions(glm::vec3 position, + glm::vec3 direction); }; } // namespace inexor::vulkan_renderer::world diff --git a/src/vulkan-renderer/application.cpp b/src/vulkan-renderer/application.cpp index 73826105d..f8b1fbf2e 100644 --- a/src/vulkan-renderer/application.cpp +++ b/src/vulkan-renderer/application.cpp @@ -184,7 +184,7 @@ void Application::load_octree_geometry() { m_worlds.emplace_back(std::make_shared(1.0f, glm::vec3{0, 0, 0})); m_worlds.emplace_back(std::make_shared(1.6f, glm::vec3{0, 10, 0})); - m_collision_solver = std::make_unique(); + m_collision_solver = std::make_unique(m_worlds); m_worlds[0]->set_type(world::Cube::Type::OCTANT); m_worlds[1]->set_type(world::Cube::Type::SOLID); @@ -576,8 +576,7 @@ void Application::check_octree_collisions() { // TODO: Apply one big global octree for bounding volume hierarchy. // TODO: Implement a world manager which resolves multiple octree collision. - const auto collision = - m_collision_solver->find_ray_octree_collision(m_worlds, m_camera->position(), m_camera->front()); + const auto collision = m_collision_solver->find_ray_octree_collision(m_camera->position(), m_camera->front()); if (collision) { const auto cube_hit = collision.value().cube_intersection(); diff --git a/src/vulkan-renderer/world/collision_solver.cpp b/src/vulkan-renderer/world/collision_solver.cpp index 2d47739e1..00240b51e 100644 --- a/src/vulkan-renderer/world/collision_solver.cpp +++ b/src/vulkan-renderer/world/collision_solver.cpp @@ -9,27 +9,29 @@ namespace inexor::vulkan_renderer::world { +OctreeCollisionSolver::OctreeCollisionSolver(const std::vector> &worlds) + : m_worlds(worlds) { + assert(!worlds.empty()); + std::scoped_lock lock(m_collision_solver_mutex); + m_collision_candidates.reserve(worlds.size()); +} + std::vector> -OctreeCollisionSolver::find_all_ray_octree_collisions(const std::vector> &worlds, - const glm::vec3 position, const glm::vec3 direction, +OctreeCollisionSolver::find_all_ray_octree_collisions(const glm::vec3 position, const glm::vec3 direction, bool find_only_one_collision) { - if (worlds.empty()) { - return {}; - } - std::vector> found_collisions; - found_collisions.reserve(worlds.size()); + found_collisions.reserve(m_worlds.size()); // We need a critical section because we are modifying m_collision_candidates. { std::scoped_lock lock(m_collision_solver_mutex); - // TODO: Optimize this! Avoid memory re-allocation if possible and benchmark it. + // We must delete the entry from previous calls of this method so we can call emplace_back. + // This will not change the capacity of the vector which was set in the constructor. m_collision_candidates.clear(); - m_collision_candidates.reserve(worlds.size()); - for (const auto &world : worlds) { + for (const auto &world : m_worlds) { if (is_bounding_box_and_bounding_sphere_hit(world, position, direction)) { m_collision_candidates.emplace_back(std::make_pair(world, glm::distance2(position, direction))); } @@ -60,10 +62,9 @@ OctreeCollisionSolver::find_all_ray_octree_collisions(const std::vector> -OctreeCollisionSolver::find_ray_octree_collision(const std::vector> &worlds, - const glm::vec3 position, const glm::vec3 direction) { - const auto result = find_all_ray_octree_collisions(worlds, position, direction, true); +std::optional> OctreeCollisionSolver::find_ray_octree_collision(const glm::vec3 position, + const glm::vec3 direction) { + const auto result = find_all_ray_octree_collisions(position, direction, true); if (!result.empty()) { return result[0]; @@ -72,10 +73,9 @@ OctreeCollisionSolver::find_ray_octree_collision(const std::vector> -OctreeCollisionSolver::find_all_ray_octree_collisions(const std::vector> &worlds, - const glm::vec3 position, const glm::vec3 direction) { - return find_all_ray_octree_collisions(worlds, position, direction, false); +std::vector> OctreeCollisionSolver::find_all_ray_octree_collisions(const glm::vec3 position, + const glm::vec3 direction) { + return find_all_ray_octree_collisions(position, direction, false); } } // namespace inexor::vulkan_renderer::world