Fixes up bounding boxes for octree
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
#include "FileBrowser.hpp"
|
||||
#include "engine/assets/model/Model.hpp"
|
||||
#include "engine/debug/DEBUG_NAMES.hpp"
|
||||
#include "engine/debug/drawers.hpp"
|
||||
#include "engine/debug/profiling/counters.hpp"
|
||||
#include "engine/debug/timing/FlameGraph.hpp"
|
||||
#include "engine/descriptors/DescriptorPool.hpp"
|
||||
@@ -193,11 +194,60 @@ namespace fgl::engine::gui
|
||||
|
||||
static GameObject* selected_object { nullptr };
|
||||
|
||||
void itterateGameObjectNode( FrameInfo& info, const OctTreeNode& node )
|
||||
{
|
||||
if ( node.isLeaf() )
|
||||
{
|
||||
if ( node.itemCount() == 0 ) return;
|
||||
|
||||
const auto& objects { node.getLeaf() };
|
||||
for ( const GameObject& object : objects )
|
||||
{
|
||||
ImGui::PushID( object.getId() );
|
||||
|
||||
debug::drawLine( object.getPosition(), node.getFitCenter() );
|
||||
|
||||
if ( ImGui::TreeNodeEx( object.getName().c_str(), ImGuiTreeNodeFlags_Leaf ) )
|
||||
{
|
||||
ImGui::TreePop();
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
else if ( node.isBranch() )
|
||||
{
|
||||
const auto& branches { node.getBranches() };
|
||||
|
||||
for ( std::size_t x = 0; x < 2; ++x )
|
||||
{
|
||||
for ( std::size_t y = 0; y < 2; ++y )
|
||||
{
|
||||
for ( std::size_t z = 0; z < 2; ++z )
|
||||
{
|
||||
const auto item_count { branches[ x ][ y ][ z ]->itemCount() };
|
||||
const auto str { std::format( "{}x{}x{}: {}", x, y, z, item_count ) };
|
||||
|
||||
if ( ImGui::TreeNodeEx(
|
||||
str.c_str(),
|
||||
ImGuiTreeNodeFlags_DefaultOpen | ( item_count == 0 ? ImGuiTreeNodeFlags_Leaf : 0 ) ) )
|
||||
{
|
||||
itterateGameObjectNode( info, *( branches[ x ][ y ][ z ] ) );
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawEntityGUI( FrameInfo& info )
|
||||
{
|
||||
ZoneScoped;
|
||||
ImGui::Begin( OBJECT_TREE_VIEW_NAME );
|
||||
|
||||
itterateGameObjectNode( info, info.game_objects );
|
||||
|
||||
/*
|
||||
for ( OctTreeNodeLeaf* leaf : info.game_objects.getAllLeafs() )
|
||||
{
|
||||
for ( GameObject& entity : *leaf )
|
||||
@@ -212,6 +262,7 @@ namespace fgl::engine::gui
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// Created by kj16609 on 10/28/24.
|
||||
//
|
||||
|
||||
#include "intersections/aabb/intersections.hpp"
|
||||
#include "intersections/aabc/intersections.hpp"
|
||||
#include "intersections/frustum/intersections.hpp"
|
||||
#include "intersections/line/intersections.hpp"
|
||||
|
||||
|
||||
27
src/engine/math/intersections/aabb/coordinate.cpp
Normal file
27
src/engine/math/intersections/aabb/coordinate.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// Created by kj16609 on 10/31/24.
|
||||
//
|
||||
|
||||
#include "engine/primitives/points/Coordinate.hpp"
|
||||
|
||||
#include "engine/primitives/boxes/AxisAlignedBoundingBox.hpp"
|
||||
|
||||
namespace fgl::engine::intersections
|
||||
{
|
||||
|
||||
template < CS CType >
|
||||
bool contains( const AxisAlignedBoundingBox< CType >& aabb, const Coordinate< CType >& point )
|
||||
{
|
||||
const Coordinate< CType > centered_coordinate { point - aabb.getPosition() };
|
||||
|
||||
const bool top_in_range { glm::all( glm::lessThanEqual( centered_coordinate.vec(), aabb.scale() ) ) };
|
||||
const bool bottom_in_range { glm::all( glm::greaterThanEqual( centered_coordinate.vec(), -aabb.scale() ) ) };
|
||||
|
||||
return top_in_range && bottom_in_range;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template bool contains< CS::World >( const AxisAlignedBoundingBox< CS::World >&, const Coordinate< CS::World >& );
|
||||
|
||||
} // namespace fgl::engine::intersections
|
||||
13
src/engine/math/intersections/aabb/intersections.hpp
Normal file
13
src/engine/math/intersections/aabb/intersections.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// Created by kj16609 on 10/31/24.
|
||||
//
|
||||
|
||||
#include "engine/primitives/boxes/AxisAlignedBoundingBox.hpp"
|
||||
|
||||
namespace fgl::engine::intersections
|
||||
{
|
||||
|
||||
template < CS CType >
|
||||
bool contains( const AxisAlignedBoundingBox< CType >& aabb, const Coordinate< CType >& point );
|
||||
|
||||
} // namespace fgl::engine::intersections
|
||||
25
src/engine/math/intersections/aabc/coordinate.cpp
Normal file
25
src/engine/math/intersections/aabc/coordinate.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// Created by kj16609 on 10/31/24.
|
||||
//
|
||||
|
||||
#include "engine/primitives/points/Coordinate.hpp"
|
||||
|
||||
#include "engine/primitives/boxes/AxisAlignedBoundingCube.hpp"
|
||||
|
||||
namespace fgl::engine::intersections
|
||||
{
|
||||
|
||||
template < CS CType >
|
||||
bool contains( const AxisAlignedBoundingCube< CType >& aabc, const Coordinate< CType >& point )
|
||||
{
|
||||
const Coordinate< CType > centered_coordinate { point - aabc.getPosition() };
|
||||
|
||||
const bool top_in_range { glm::all( glm::lessThanEqual( centered_coordinate.vec(), aabc.scale() ) ) };
|
||||
const bool bottom_in_range { glm::all( glm::greaterThanEqual( centered_coordinate.vec(), -aabc.scale() ) ) };
|
||||
|
||||
return top_in_range && bottom_in_range;
|
||||
}
|
||||
|
||||
template bool contains< CS::World >( const AxisAlignedBoundingCube< CS::World >&, const Coordinate< CS::World >& );
|
||||
|
||||
} // namespace fgl::engine::intersections
|
||||
13
src/engine/math/intersections/aabc/intersections.hpp
Normal file
13
src/engine/math/intersections/aabc/intersections.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// Created by kj16609 on 10/31/24.
|
||||
//
|
||||
|
||||
#include "engine/primitives/boxes/AxisAlignedBoundingCube.hpp"
|
||||
|
||||
namespace fgl::engine::intersections
|
||||
{
|
||||
|
||||
template < CS CType >
|
||||
bool contains( const AxisAlignedBoundingCube< CType >& aabb, const Coordinate< CType >& point );
|
||||
|
||||
} // namespace fgl::engine::intersections
|
||||
20
src/engine/math/intersections/obb/coordinate.cpp
Normal file
20
src/engine/math/intersections/obb/coordinate.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// Created by kj16609 on 10/31/24.
|
||||
//
|
||||
|
||||
#include "engine/primitives/points/Coordinate.hpp"
|
||||
|
||||
#include "engine/primitives/boxes/OrientedBoundingBox.hpp"
|
||||
|
||||
namespace fgl::engine::intersections
|
||||
{
|
||||
|
||||
template < CS CType >
|
||||
bool contains( const OrientedBoundingBox< CType >& obb, const Coordinate< CType >& point )
|
||||
{
|
||||
FGL_UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
template bool contains< CS::World >( const OrientedBoundingBox< CS::World >&, const Coordinate< CS::World >& );
|
||||
|
||||
} // namespace fgl::engine::intersections
|
||||
13
src/engine/math/intersections/obb/intersections.hpp
Normal file
13
src/engine/math/intersections/obb/intersections.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// Created by kj16609 on 10/31/24.
|
||||
//
|
||||
|
||||
#include "engine/primitives/boxes/OrientedBoundingBox.hpp"
|
||||
|
||||
namespace fgl::engine::intersections
|
||||
{
|
||||
|
||||
template < CS CType >
|
||||
bool contains( const OrientedBoundingBox< CType >& aabb, const Coordinate< CType >& point );
|
||||
|
||||
} // namespace fgl::engine::intersections
|
||||
@@ -25,7 +25,7 @@ namespace fgl::engine
|
||||
|
||||
constexpr static auto SpaceType { CType };
|
||||
|
||||
explicit AxisAlignedBoundingBox(
|
||||
AxisAlignedBoundingBox(
|
||||
const Coordinate< CType > top_right_forward, const Coordinate< CType > bottom_left_back ) :
|
||||
m_top_right_forward( top_right_forward ),
|
||||
m_bottom_left_back( bottom_left_back )
|
||||
@@ -35,7 +35,7 @@ namespace fgl::engine
|
||||
assert( m_top_right_forward.z > m_bottom_left_back.z );
|
||||
}
|
||||
|
||||
explicit AxisAlignedBoundingBox( const Coordinate< CType > midpoint, const Scale scale ) :
|
||||
AxisAlignedBoundingBox( const Coordinate< CType > midpoint, const Scale scale ) :
|
||||
AxisAlignedBoundingBox( midpoint + scale, midpoint - scale )
|
||||
{
|
||||
assert( m_top_right_forward.x > m_bottom_left_back.x );
|
||||
@@ -43,6 +43,7 @@ namespace fgl::engine
|
||||
assert( m_top_right_forward.z > m_bottom_left_back.z );
|
||||
}
|
||||
|
||||
//TODO: This should be removed from access in favor of OBB::alignToWorld()
|
||||
explicit AxisAlignedBoundingBox( const OrientedBoundingBox< CType >& oobb );
|
||||
|
||||
AxisAlignedBoundingBox& combine( const AxisAlignedBoundingBox& other );
|
||||
|
||||
@@ -225,6 +225,12 @@ namespace fgl::engine
|
||||
return AxisAlignedBoundingBox< CType >( Coordinate< CType >( max ), Coordinate< CType >( min ) );
|
||||
}
|
||||
|
||||
template < CoordinateSpace CType >
|
||||
Coordinate< CType > OrientedBoundingBox< CType >::getPosition() const
|
||||
{
|
||||
return m_transform.translation;
|
||||
}
|
||||
|
||||
template < CoordinateSpace CType >
|
||||
std::array< LineSegment< CType >, interface::BoundingBox::LINE_COUNT > OrientedBoundingBox< CType >::lines() const
|
||||
{
|
||||
|
||||
@@ -111,6 +111,8 @@ namespace fgl::engine
|
||||
OrientedBoundingBox combine( const OrientedBoundingBox& other ) const;
|
||||
|
||||
AxisAlignedBoundingBox< CType > alignToWorld() const;
|
||||
|
||||
Coordinate< CType > getPosition() const;
|
||||
};
|
||||
|
||||
template < CoordinateSpace CType, MatrixType MType >
|
||||
|
||||
@@ -241,6 +241,9 @@ namespace fgl::engine
|
||||
}
|
||||
|
||||
objects.emplace_back( std::move( obj ) );
|
||||
|
||||
recalculateBounds();
|
||||
|
||||
return this;
|
||||
}
|
||||
else if ( std::holds_alternative< OctTreeNodeArray >( m_node_data ) )
|
||||
@@ -252,25 +255,59 @@ namespace fgl::engine
|
||||
FGL_UNREACHABLE();
|
||||
}
|
||||
|
||||
bool OctTreeNode::isLeaf() const
|
||||
{
|
||||
return std::holds_alternative< OctTreeNodeLeaf >( m_node_data );
|
||||
}
|
||||
|
||||
bool OctTreeNode::isBranch() const
|
||||
{
|
||||
return std::holds_alternative< OctTreeNodeArray >( m_node_data );
|
||||
}
|
||||
|
||||
std::size_t OctTreeNode::itemCount() const
|
||||
{
|
||||
//TODO: Store this value in the nodes itself
|
||||
if ( !isLeaf() )
|
||||
{
|
||||
std::size_t sum { 0 };
|
||||
|
||||
for ( std::size_t x = 0; x < 2; ++x )
|
||||
{
|
||||
for ( std::size_t y = 0; y < 2; ++y )
|
||||
{
|
||||
for ( std::size_t z = 0; z < 2; ++z )
|
||||
{
|
||||
sum += std::get< OctTreeNodeArray >( m_node_data )[ x ][ y ][ z ]->itemCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
return std::get< OctTreeNodeLeaf >( m_node_data ).size();
|
||||
}
|
||||
|
||||
const OctTreeNodeArray& OctTreeNode::getBranches() const
|
||||
{
|
||||
return std::get< OctTreeNodeArray >( m_node_data );
|
||||
}
|
||||
|
||||
const OctTreeNodeLeaf& OctTreeNode::getLeaf() const
|
||||
{
|
||||
return std::get< OctTreeNodeLeaf >( m_node_data );
|
||||
}
|
||||
|
||||
bool OctTreeNode::isInFrustum( const Frustum& frustum ) const
|
||||
{
|
||||
#if ENABLE_IMGUI
|
||||
if ( !isEmpty() && intersects( frustum, m_fit_bounding_box ) )
|
||||
{
|
||||
if ( ( draw_inview_bounds || ( std::holds_alternative< OctTreeNodeLeaf >( this->m_node_data ) )
|
||||
|| draw_branches )
|
||||
&& m_parent ) [[unlikely]]
|
||||
if ( isLeaf() && itemCount() > 0 ) [[unlikely]]
|
||||
{
|
||||
if ( draw_leaf_fit_bounds ) [[unlikely]]
|
||||
debug::drawBoundingBox( m_fit_bounding_box );
|
||||
/*
|
||||
debug::drawBoundingBox(
|
||||
m_fit_bounding_box,
|
||||
glm::vec3(
|
||||
m_fit_bounding_box.getPosition().x > 0.0f ? 1.0f : 0.0f,
|
||||
m_fit_bounding_box.getPosition().y > 0.0f ? 1.0f : 0.0f,
|
||||
m_fit_bounding_box.getPosition().z > 0.0f ? 1.0f : 0.0f ) );
|
||||
*/
|
||||
if ( draw_leaf_real_bounds ) [[unlikely]]
|
||||
debug::drawBoundingBox( m_bounds );
|
||||
}
|
||||
@@ -285,47 +322,42 @@ namespace fgl::engine
|
||||
#endif
|
||||
}
|
||||
|
||||
bool OctTreeNode::isEmpty() const
|
||||
{
|
||||
return std::holds_alternative< OctTreeNodeLeaf >( m_node_data )
|
||||
&& std::get< OctTreeNodeLeaf >( m_node_data ).empty();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return Returns true if the fit bounding box is larger then the virtual bounds
|
||||
*/
|
||||
void OctTreeNode::recalculateBounds()
|
||||
{
|
||||
m_fit_bounding_box = m_bounds;
|
||||
if ( isLeaf() )
|
||||
return recalculateLeafBounds();
|
||||
else if ( isBranch() )
|
||||
return recalculateNodeBounds();
|
||||
|
||||
if ( std::holds_alternative< NodeDataT >( m_node_data ) )
|
||||
{
|
||||
// We aren't a leaf. So we need to use the bounding box of the children below us
|
||||
FGL_UNREACHABLE();
|
||||
}
|
||||
|
||||
const auto& nodes { std::get< NodeDataT >( m_node_data ) };
|
||||
std::vector< OctTreeNodeLeaf* > OctTreeNode::getAllLeafs()
|
||||
{
|
||||
ZoneScoped;
|
||||
std::vector< OctTreeNodeLeaf* > leafs {};
|
||||
leafs.reserve( LEAF_RESERVE_SIZE );
|
||||
this->getAllLeafs( leafs );
|
||||
return leafs;
|
||||
}
|
||||
|
||||
for ( std::size_t x = 0; x < 2; ++x )
|
||||
{
|
||||
for ( std::size_t y = 0; y < 2; ++y )
|
||||
{
|
||||
for ( std::size_t z = 0; z < 2; ++z )
|
||||
{
|
||||
nodes[ x ][ y ][ z ]->recalculateBounds();
|
||||
m_fit_bounding_box = m_fit_bounding_box.combine( nodes[ x ][ y ][ z ]->m_fit_bounding_box );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( std::holds_alternative< LeafDataT >( m_node_data ) )
|
||||
{
|
||||
const auto& data { std::get< LeafDataT >( m_node_data ) };
|
||||
|
||||
for ( const auto& game_object : data )
|
||||
{
|
||||
auto model_components { game_object.getComponents< ModelComponent >() };
|
||||
|
||||
for ( const auto& model : model_components )
|
||||
{
|
||||
const OrientedBoundingBox model_bounding_box { ( *model )->getBoundingBox() };
|
||||
|
||||
const OrientedBoundingBox< CoordinateSpace::World > world_bounding_box { model->m_transform.mat()
|
||||
* model_bounding_box };
|
||||
|
||||
m_fit_bounding_box = m_fit_bounding_box.combine( world_bounding_box.alignToWorld() );
|
||||
}
|
||||
}
|
||||
}
|
||||
std::vector< OctTreeNodeLeaf* > OctTreeNode::getAllLeafsInFrustum( const Frustum& frustum )
|
||||
{
|
||||
ZoneScoped;
|
||||
std::vector< OctTreeNodeLeaf* > leafs {};
|
||||
leafs.reserve( LEAF_RESERVE_SIZE );
|
||||
this->getAllLeafsInFrustum( frustum, leafs );
|
||||
return leafs;
|
||||
}
|
||||
|
||||
void OctTreeNode::clear()
|
||||
@@ -338,12 +370,26 @@ namespace fgl::engine
|
||||
{
|
||||
const auto& node_array { std::get< OctTreeNodeArray >( this->m_node_data ) };
|
||||
|
||||
for ( std::size_t x = 0; x < 2; ++x )
|
||||
for ( std::size_t y = 0; y < 2; ++y )
|
||||
for ( std::size_t z = 0; z < 2; ++z ) node_array[ x ][ y ][ z ]->clear();
|
||||
FOR_EACH_OCTTREE_NODE
|
||||
{
|
||||
node_array[ x ][ y ][ z ]->clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WorldCoordinate OctTreeNode::getCenter() const
|
||||
{
|
||||
return m_bounds.getPosition();
|
||||
}
|
||||
|
||||
WorldCoordinate OctTreeNode::getFitCenter() const
|
||||
{
|
||||
return m_fit_bounding_box.getPosition();
|
||||
}
|
||||
|
||||
void OctTreeNode::drawDebug() const
|
||||
{}
|
||||
|
||||
OctTreeNode* OctTreeNode::findID( const GameObject::GameObjectID id )
|
||||
{
|
||||
ZoneScoped;
|
||||
@@ -352,33 +398,22 @@ namespace fgl::engine
|
||||
//We are the last node. Check if we have the ID
|
||||
const auto& game_objects { std::get< OctTreeNodeLeaf >( m_node_data ) };
|
||||
|
||||
if ( std::find_if(
|
||||
game_objects.begin(),
|
||||
game_objects.end(),
|
||||
[ id ]( const GameObject& obj ) { return obj.getId() == id; } )
|
||||
if ( std::ranges::find_if( game_objects, [ id ]( const GameObject& obj ) { return obj.getId() == id; } )
|
||||
!= game_objects.end() )
|
||||
{
|
||||
return this;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
else if ( std::holds_alternative< OctTreeNodeArray >( this->m_node_data ) )
|
||||
{
|
||||
const auto& node_array { std::get< OctTreeNodeArray >( this->m_node_data ) };
|
||||
|
||||
for ( std::size_t x = 0; x < 2; ++x )
|
||||
FOR_EACH_OCTTREE_NODE
|
||||
{
|
||||
for ( std::size_t y = 0; y < 2; ++y )
|
||||
{
|
||||
for ( std::size_t z = 0; z < 2; ++z )
|
||||
{
|
||||
const auto& node { node_array[ x ][ y ][ z ]->findID( id ) };
|
||||
if ( node != nullptr ) return node;
|
||||
}
|
||||
}
|
||||
const auto& node { node_array[ x ][ y ][ z ]->findID( id ) };
|
||||
if ( node != nullptr ) return node;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@@ -434,105 +469,14 @@ namespace fgl::engine
|
||||
{
|
||||
const auto& nodes { std::get< OctTreeNodeArray >( m_node_data ) };
|
||||
|
||||
for ( std::size_t x = 0; x < 2; ++x )
|
||||
FOR_EACH_OCTTREE_NODE
|
||||
{
|
||||
for ( std::size_t y = 0; y < 2; ++y )
|
||||
{
|
||||
for ( std::size_t z = 0; z < 2; ++z )
|
||||
{
|
||||
auto ret { nodes[ x ][ y ][ z ]->getAllLeafs() };
|
||||
out_leafs.insert( out_leafs.end(), ret.begin(), ret.end() );
|
||||
}
|
||||
}
|
||||
auto ret { nodes[ x ][ y ][ z ]->getAllLeafs() };
|
||||
out_leafs.insert( out_leafs.end(), ret.begin(), ret.end() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bool OctTreeNode::recalculateBoundingBoxes()
|
||||
{
|
||||
ZoneScoped;
|
||||
const auto old_bounds { m_fit_bounding_box };
|
||||
if ( std::holds_alternative< OctTreeNodeArray >( m_node_data ) )
|
||||
{
|
||||
ZoneScopedN( "Process Array" );
|
||||
bool bounding_box_changed { false };
|
||||
auto& nodes { std::get< OctTreeNodeArray >( m_node_data ) };
|
||||
for ( std::size_t x = 0; x < 2; ++x )
|
||||
{
|
||||
for ( std::size_t y = 0; y < 2; ++y )
|
||||
{
|
||||
for ( std::size_t z = 0; z < 2; ++z )
|
||||
{
|
||||
auto& node { nodes[ x ][ y ][ z ] };
|
||||
bounding_box_changed |= node->recalculateBoundingBoxes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( bounding_box_changed )
|
||||
{
|
||||
//We need to update our bounding box now.
|
||||
auto new_bounds { nodes[ 0 ][ 0 ][ 0 ]->m_fit_bounding_box };
|
||||
|
||||
for ( std::size_t x = 0; x < 2; ++x )
|
||||
{
|
||||
for ( std::size_t y = 0; y < 2; ++y )
|
||||
{
|
||||
for ( std::size_t z = 0; z < 2; ++z )
|
||||
{
|
||||
if ( x == 0 && y == 0 && z == 0 ) continue;
|
||||
auto& node { nodes[ x ][ y ][ z ] };
|
||||
new_bounds.combine( node->m_fit_bounding_box );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( new_bounds == old_bounds )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->m_fit_bounding_box = new_bounds;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else if ( std::holds_alternative< OctTreeNodeLeaf >( m_node_data ) )
|
||||
{
|
||||
ZoneScopedN( "Process Leaf" );
|
||||
auto& game_objects { std::get< OctTreeNodeLeaf >( m_node_data ) };
|
||||
|
||||
if ( game_objects.size() == 0 ) return false;
|
||||
|
||||
AxisAlignedBoundingBox< CoordinateSpace::World > new_bounds { game_objects[ 0 ].getPosition() };
|
||||
|
||||
FGL_ASSUME( game_objects.size() <= MAX_NODES_IN_LEAF );
|
||||
|
||||
for ( std::size_t i = 1; i < game_objects.size(); ++i )
|
||||
{
|
||||
FGL_ASSUME( i <= MAX_NODES_IN_LEAF ));
|
||||
new_bounds.combine( game_objects[ i ].getBoundingBox() );
|
||||
}
|
||||
|
||||
if ( new_bounds == old_bounds )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->m_fit_bounding_box = new_bounds;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
FGL_UNREACHABLE();
|
||||
}
|
||||
*/
|
||||
|
||||
std::size_t OctTreeNode::reorganize()
|
||||
{
|
||||
std::size_t counter { 0 };
|
||||
@@ -540,22 +484,17 @@ namespace fgl::engine
|
||||
{
|
||||
const auto& nodes { std::get< NodeDataT >( m_node_data ) };
|
||||
|
||||
for ( std::size_t x = 0; x < 2; ++x )
|
||||
FOR_EACH_OCTTREE_NODE
|
||||
{
|
||||
for ( std::size_t y = 0; y < 2; ++y )
|
||||
{
|
||||
for ( std::size_t z = 0; z < 2; ++z )
|
||||
{
|
||||
if ( x == 0 && y == 0 && z == 0 ) continue;
|
||||
const auto& node { nodes[ x ][ y ][ z ] };
|
||||
counter += node->reorganize();
|
||||
}
|
||||
}
|
||||
// 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 ] };
|
||||
counter += node->reorganize();
|
||||
}
|
||||
|
||||
return counter;
|
||||
}
|
||||
if ( std::holds_alternative< LeafDataT >( m_node_data ) )
|
||||
else if ( std::holds_alternative< LeafDataT >( m_node_data ) )
|
||||
{
|
||||
//Check if any of the nodes in this group need to be moved.
|
||||
|
||||
@@ -578,4 +517,85 @@ namespace fgl::engine
|
||||
FGL_UNREACHABLE();
|
||||
}
|
||||
|
||||
bool OctTreeNode::isBoundsExpanded()
|
||||
{
|
||||
return m_fit_bounding_box == m_bounds;
|
||||
/*
|
||||
const auto fit_points { m_fit_bounding_box.points() };
|
||||
for ( const auto& p : fit_points )
|
||||
{
|
||||
// Return true if a point is outside of the bounds. This indicates that out bounding box is bigger then our bounds.
|
||||
if ( !m_bounds.contains( p ) ) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
*/
|
||||
}
|
||||
|
||||
void OctTreeNode::recalculateNodeBounds()
|
||||
{
|
||||
FGL_ASSERT( std::holds_alternative< NodeDataT >( m_node_data ), "Node data was not an array!" );
|
||||
const auto& nodes { std::get< NodeDataT >( m_node_data ) };
|
||||
|
||||
// We start out by telling all of our children to recalculate their bounds
|
||||
m_fit_bounding_box = static_cast< AxisAlignedBoundingBox< CoordinateSpace::World > >( m_bounds );
|
||||
|
||||
FOR_EACH_OCTTREE_NODE
|
||||
{
|
||||
// If true then the bounds were bigger then the inital bounding box. So we should try to combine it with out current bounding box.
|
||||
m_fit_bounding_box = m_fit_bounding_box.combine( nodes[ x ][ y ][ z ]->m_fit_bounding_box );
|
||||
}
|
||||
|
||||
// if ( isBoundsExpanded() && m_parent )
|
||||
if ( m_parent ) m_parent->recalculateBounds();
|
||||
}
|
||||
|
||||
void OctTreeNode::recalculateLeafBounds()
|
||||
{
|
||||
FGL_ASSERT( std::holds_alternative< LeafDataT >( m_node_data ), "Node data was not a leaf!" );
|
||||
const auto& data { std::get< LeafDataT >( m_node_data ) };
|
||||
|
||||
if ( data.empty() )
|
||||
{
|
||||
m_fit_bounding_box = static_cast< AxisAlignedBoundingBox< CoordinateSpace::World > >( m_bounds );
|
||||
return;
|
||||
}
|
||||
|
||||
// If true, Then the fit has already been set and we should combine with it
|
||||
bool fit_set { false };
|
||||
|
||||
for ( const auto& game_object : data )
|
||||
{
|
||||
auto model_components { game_object.getComponents< ModelComponent >() };
|
||||
const Matrix< MatrixType::ModelToWorld > game_object_transform { game_object.getTransform().mat() };
|
||||
|
||||
for ( const auto& model : model_components )
|
||||
{
|
||||
const OrientedBoundingBox< CS::Model > model_bounding_box { ( *model )->getBoundingBox() };
|
||||
|
||||
const Matrix< MatrixType::ModelToWorld > model_transform { model->m_transform.mat() };
|
||||
|
||||
// Combine the game object and model transform
|
||||
const Matrix< MatrixType::ModelToWorld > combined_transform { model_transform * game_object_transform };
|
||||
|
||||
const OrientedBoundingBox< CoordinateSpace::World > world_bounding_box { combined_transform
|
||||
* model_bounding_box };
|
||||
|
||||
const auto aligned_bounding_box { world_bounding_box.alignToWorld() };
|
||||
|
||||
if ( fit_set )
|
||||
m_fit_bounding_box = m_fit_bounding_box.combine( aligned_bounding_box );
|
||||
else
|
||||
{
|
||||
m_fit_bounding_box = aligned_bounding_box;
|
||||
fit_set = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Have our parent recalculate it's bounds
|
||||
// if ( isBoundsExpanded() && m_parent )
|
||||
if ( m_parent ) m_parent->recalculateBounds();
|
||||
}
|
||||
|
||||
} // namespace fgl::engine
|
||||
@@ -4,8 +4,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
#include "engine/gameobjects/GameObject.hpp"
|
||||
#include "engine/primitives/boxes/AxisAlignedBoundingCube.hpp"
|
||||
|
||||
@@ -65,6 +63,9 @@ namespace fgl::engine
|
||||
OctTreeNode& operator=( const OctTreeNode& ) = delete;
|
||||
OctTreeNode& operator=( OctTreeNode&& ) = delete;
|
||||
void clear();
|
||||
WorldCoordinate getCenter() const;
|
||||
WorldCoordinate getFitCenter() const;
|
||||
void drawDebug() const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -89,11 +90,7 @@ namespace fgl::engine
|
||||
|
||||
bool isInFrustum( const Frustum& frustum ) const;
|
||||
|
||||
bool isEmpty() const
|
||||
{
|
||||
return std::holds_alternative< OctTreeNodeLeaf >( m_node_data )
|
||||
&& std::get< OctTreeNodeLeaf >( m_node_data ).empty();
|
||||
}
|
||||
bool isEmpty() const;
|
||||
|
||||
auto getGameObjectItter( GameObject::GameObjectID id );
|
||||
|
||||
@@ -109,30 +106,34 @@ namespace fgl::engine
|
||||
//! Rebuilds the tree checking if nodes have moved.
|
||||
std::size_t reorganize();
|
||||
|
||||
//! Returns true if the fixed bounding box is larger then the inital bounding box
|
||||
bool isBoundsExpanded();
|
||||
|
||||
void recalculateNodeBounds();
|
||||
|
||||
void recalculateLeafBounds();
|
||||
|
||||
void recalculateBounds();
|
||||
|
||||
constexpr static std::size_t LEAF_RESERVE_SIZE { 1024 };
|
||||
|
||||
[[nodiscard]] std::vector< OctTreeNodeLeaf* > getAllLeafs()
|
||||
{
|
||||
ZoneScoped;
|
||||
std::vector< OctTreeNodeLeaf* > leafs {};
|
||||
leafs.reserve( LEAF_RESERVE_SIZE );
|
||||
this->getAllLeafs( leafs );
|
||||
return leafs;
|
||||
}
|
||||
[[nodiscard]] std::vector< OctTreeNodeLeaf* > getAllLeafs();
|
||||
|
||||
[[nodiscard]] std::vector< OctTreeNodeLeaf* > getAllLeafsInFrustum( const Frustum& frustum )
|
||||
{
|
||||
ZoneScoped;
|
||||
std::vector< OctTreeNodeLeaf* > leafs {};
|
||||
leafs.reserve( LEAF_RESERVE_SIZE );
|
||||
this->getAllLeafsInFrustum( frustum, leafs );
|
||||
return leafs;
|
||||
}
|
||||
[[nodiscard]] std::vector< OctTreeNodeLeaf* > getAllLeafsInFrustum( const Frustum& frustum );
|
||||
|
||||
//! Adds a game object, Will split the node if the auto split threshold is reached
|
||||
OctTreeNode* addGameObject( GameObject&& obj );
|
||||
bool isLeaf() const;
|
||||
bool isBranch() const;
|
||||
|
||||
std::size_t itemCount() const;
|
||||
const OctTreeNodeArray& getBranches() const;
|
||||
const OctTreeNodeLeaf& getLeaf() const;
|
||||
};
|
||||
|
||||
#define FOR_EACH_OCTTREE_NODE \
|
||||
for ( std::size_t x = 0; x < 2; ++x ) \
|
||||
for ( std::size_t y = 0; y < 2; ++y ) \
|
||||
for ( std::size_t z = 0; z < 2; ++z )
|
||||
|
||||
} // namespace fgl::engine
|
||||
Reference in New Issue
Block a user