Adds optimization to octtree navigation

This commit is contained in:
2025-01-25 01:50:21 -05:00
parent e9affae3b3
commit 1ba02c6336
9 changed files with 138 additions and 14 deletions

View File

@@ -42,7 +42,6 @@ int main()
{
EngineContext engine_ctx {};
/*
EditorGuiContext editor_ctx { engine_ctx.getWindow() };
// We start by hooking into the imgui rendering.
@@ -90,7 +89,6 @@ int main()
}
engine_ctx.waitIdle();
*/
}
catch ( const vk::LayerNotPresentError& e )
{

View File

@@ -87,8 +87,8 @@ namespace fgl::engine
}
obj.getTransform().translation = WorldCoordinate(
-10.0f + ( static_cast< float >( x ) * offset ),
-10.0f + ( static_cast< float >( y ) * offset ),
10.0f + ( static_cast< float >( x ) * offset ),
10.0f + ( static_cast< float >( y ) * offset ),
0.0f );
m_game_objects_root.addGameObject( std::move( obj ) );

View File

@@ -5,8 +5,8 @@
#pragma once
//clang-format: off
#include <vulkan/vulkan.hpp>
#include <tracy/TracyVulkan.hpp>
#include <vulkan/vulkan.hpp>
//clang-format: on
#include "descriptors/Descriptor.hpp"
@@ -58,6 +58,7 @@ namespace fgl::engine
constexpr descriptors::AttachmentDescriptor metallic_descriptor { 3, FRAG_STAGE };
constexpr descriptors::AttachmentDescriptor emissive_descriptor { 4, FRAG_STAGE };
//TODO: Move this from being static, It being here prevents safe cleanup
inline static descriptors::DescriptorSetLayout gbuffer_set {
0, color_descriptor, position_descriptor, normal_descriptor, metallic_descriptor, emissive_descriptor
};

View File

@@ -27,9 +27,9 @@ namespace fgl::engine::descriptors
binding.stageFlags = descriptor.m_stage_flags;
binding.pImmutableSamplers = VK_NULL_HANDLE;
bindings.emplace_back( binding );
m_bindings.emplace_back( binding );
flags.emplace_back( descriptor.m_binding_flags );
m_flags.emplace_back( descriptor.m_binding_flags );
}
}
@@ -47,11 +47,11 @@ namespace fgl::engine::descriptors
vk::raii::DescriptorSetLayout DescriptorSetLayout::createLayout() const
{
vk::DescriptorSetLayoutBindingFlagsCreateInfo flags_info {};
flags_info.setBindingFlags( flags );
flags_info.setBindingFlags( m_flags );
vk::DescriptorSetLayoutCreateInfo info {};
info.setFlags( vk::DescriptorSetLayoutCreateFlagBits::eUpdateAfterBindPool );
info.setBindings( bindings );
info.setBindings( m_bindings );
info.setPNext( &flags_info );
return Device::getInstance()->createDescriptorSetLayout( info );

View File

@@ -19,8 +19,8 @@ namespace fgl::engine::descriptors
class DescriptorSetLayout
{
std::vector< vk::DescriptorSetLayoutBinding > bindings {};
std::vector< vk::DescriptorBindingFlags > flags {};
std::vector< vk::DescriptorSetLayoutBinding > m_bindings {};
std::vector< vk::DescriptorBindingFlags > m_flags {};
std::optional< vk::raii::DescriptorSetLayout > m_layout { std::nullopt };
@@ -45,7 +45,7 @@ namespace fgl::engine::descriptors
DescriptorSetLayout( set_idx, std::vector< std::reference_wrapper< const Descriptor > > { descriptors... } )
{}
[[nodiscard]] std::size_t count() const { return bindings.size(); }
[[nodiscard]] std::size_t count() const { return m_bindings.size(); }
std::unique_ptr< DescriptorSet > create();
[[nodiscard]] vk::raii::DescriptorSetLayout createLayout() const;

View File

@@ -0,0 +1,9 @@
//
// Created by kj16609 on 1/24/25.
//
#include "BVHTree.hpp"
namespace fgl::engine
{
}

View File

@@ -0,0 +1,43 @@
//
// Created by kj16609 on 1/24/25.
//
#pragma once
#include <cstdint>
#include <vector>
#include "glm/vec3.hpp"
namespace fgl::engine
{
using BVHIndex = std::uint32_t;
class BVHTree
{
struct GameObjectInfo
{};
struct BVHNode
{
using FlagType = std::uint8_t;
enum Masks : FlagType
{
Flag_None = 0,
//! This node was visible during the last test
Flag_Previously_Visible = 1 << 0,
//! This node was not visible during the last test
Flag_Previously_Invisible = 1 << 1,
};
FlagType m_flags { Masks::Flag_None };
glm::vec3 m_centerpoint;
//! Index to try next if we hit this index.
BVHIndex m_hit;
//! Index t otry if we fail this index.
BVHIndex m_miss;
};
public:
};
} // namespace fgl::engine

View File

@@ -34,7 +34,6 @@ namespace fgl::engine
void imGuiOctTreeSettings( const FrameInfo& info )
{
#if ENABLE_IMGUI
if ( ImGui::CollapsingHeader( "OctTree debug settings" ) )
{
ImGui::Checkbox( "Draw leaf fitted bounding boxes", &draw_leaf_fit_bounds );
@@ -61,13 +60,17 @@ namespace fgl::engine
time = std::chrono::duration_cast< std::chrono::microseconds >( time_diff );
}
if ( ImGui::Button( "Optimize Octree Travel" ) )
{
info.game_objects.optimizePath();
}
if ( time.has_value() )
{
ImGui::Text( "Time spent reorganizing: %.2ldus", time.value().count() );
ImGui::Text( "Moved %ld objects", number_moved );
}
}
#endif
}
void OctTreeNode::getAllLeafsInFrustum( const Frustum& frustum, std::vector< OctTreeNodeLeaf* >& out_leafs )
@@ -87,6 +90,12 @@ namespace fgl::engine
const OctTreeNodeArray& node_array { std::get< OctTreeNodeArray >( m_node_data ) };
//Search deeper
if ( m_skip != nullptr )
{
m_skip->getAllLeafsInFrustum( frustum, out_leafs );
return;
}
node_array[ LEFT ][ FORWARD ][ TOP ]->getAllLeafsInFrustum( frustum, out_leafs );
node_array[ LEFT ][ FORWARD ][ BOTTOM ]->getAllLeafsInFrustum( frustum, out_leafs );
@@ -464,6 +473,8 @@ namespace fgl::engine
if ( std::holds_alternative< OctTreeNodeArray >( this->m_node_data ) )
{
if ( m_skip != nullptr ) return m_skip->findID( id );
const auto& node_array { std::get< OctTreeNodeArray >( this->m_node_data ) };
FOR_EACH_OCTTREE_NODE
@@ -532,8 +543,16 @@ namespace fgl::engine
}
else
{
if ( m_skip != nullptr )
{
m_skip->getAllLeafs( out_leafs );
return;
}
const auto& nodes { std::get< OctTreeNodeArray >( m_node_data ) };
// If we have a node to skip to, Skip to it.
FOR_EACH_OCTTREE_NODE
{
auto ret { nodes[ x ][ y ][ z ]->getAllLeafs() };
@@ -542,8 +561,56 @@ namespace fgl::engine
}
}
OctTreeNode* OctTreeNode::optimizePath()
{
ZoneScoped;
// The node returned here will be the optimal node to jump to. If we return nullptr then that means this node has multiple paths it can take.
if ( std::holds_alternative< NodeDataT >( m_node_data ) )
{
const auto& nodes { std::get< NodeDataT >( m_node_data ) };
OctTreeNode* optimal { nullptr };
FOR_EACH_OCTTREE_NODE
{
// Why did I skip the 0,0,0 node previously?
// if ( x == 0 && y == 0 && z == 0 ) continue;
const auto& node { nodes[ x ][ y ][ z ] };
if ( auto* optimal_ret = node->optimizePath(); optimal_ret != nullptr )
{
// If the node returns nullptr, Then it means that this node shouldn't jump to any node directly.
if ( optimal != nullptr )
{
m_skip = nullptr;
return this;
}
optimal = optimal_ret;
}
}
m_skip = optimal;
return optimal;
}
if ( std::holds_alternative< LeafDataT >( m_node_data ) )
{
const auto& leaf_data { std::get< LeafDataT >( m_node_data ) };
if ( leaf_data.empty() ) return nullptr;
return this;
}
FGL_UNREACHABLE();
}
std::size_t OctTreeNode::reorganize()
{
ZoneScoped;
std::size_t counter { 0 };
if ( std::holds_alternative< NodeDataT >( m_node_data ) )
{

View File

@@ -52,6 +52,11 @@ namespace fgl::engine
OctTreeNode* m_parent;
//! Node to skip too when attempting to parse this node.
//! This is done in order to prevent navigating through an empty set of nodes.
//! This is only set if there is only one leaf filled with data.
OctTreeNode* m_skip { nullptr };
public:
OctTreeNode() = delete;
@@ -106,6 +111,7 @@ namespace fgl::engine
//! Rebuilds the tree checking if nodes have moved.
std::size_t reorganize();
OctTreeNode* optimizePath();
//! Returns true if the fixed bounding box is larger then the inital bounding box
bool isBoundsExpanded() const;