Cleans up intersection testing
This commit is contained in:
@@ -4,12 +4,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
namespace fgl::engine
|
||||
{
|
||||
|
||||
|
||||
struct CameraInfo
|
||||
{
|
||||
glm::mat4 projection { 1.0f };
|
||||
@@ -17,5 +14,4 @@ namespace fgl::engine
|
||||
glm::mat4 inverse_view { 1.0f };
|
||||
};
|
||||
|
||||
|
||||
} // namespace fgl::engine
|
||||
11
src/engine/math/intersections.hpp
Normal file
11
src/engine/math/intersections.hpp
Normal file
@@ -0,0 +1,11 @@
|
||||
//
|
||||
// Created by kj16609 on 10/28/24.
|
||||
//
|
||||
|
||||
#include "intersections/frustum/intersections.hpp"
|
||||
#include "intersections/line/intersections.hpp"
|
||||
|
||||
namespace fgl::engine
|
||||
{
|
||||
using namespace intersections;
|
||||
}
|
||||
8
src/engine/math/intersections/README.md
Normal file
8
src/engine/math/intersections/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
This folder structure follows the following pattern
|
||||
|
||||
```cpp
|
||||
bool intersects( Frustum frustum, OrientedBoundingBox& oob );
|
||||
```
|
||||
|
||||
would be placed in `frustum/obb`
|
||||
|
||||
29
src/engine/math/intersections/frustum/aabb.cpp
Normal file
29
src/engine/math/intersections/frustum/aabb.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// Created by kj16609 on 10/28/24.
|
||||
//
|
||||
|
||||
#include "engine/math/intersections/helpers.hpp"
|
||||
#include "engine/primitives/Frustum.hpp"
|
||||
#include "engine/primitives/boxes/AxisAlignedBoundingCube.hpp"
|
||||
|
||||
namespace fgl::engine::intersections
|
||||
{
|
||||
bool intersects( const Frustum& frustum, const AxisAlignedBoundingCube< CS::World >& aabc )
|
||||
{
|
||||
const auto box_points { aabc.points() };
|
||||
|
||||
if ( frustum.containsAnyPoint( box_points ) ) return true;
|
||||
|
||||
const auto frustum_points { frustum.points() };
|
||||
|
||||
if ( canPlotLine( frustum, frustum_points, box_points ) ) return false;
|
||||
|
||||
// Now to test every axis from the bounding box
|
||||
if ( testAxis( aabc.right(), frustum_points, box_points ) ) return false;
|
||||
if ( testAxis( aabc.forward(), frustum_points, box_points ) ) return false;
|
||||
if ( testAxis( aabc.up(), frustum_points, box_points ) ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace fgl::engine::intersections
|
||||
30
src/engine/math/intersections/frustum/aabc.cpp
Normal file
30
src/engine/math/intersections/frustum/aabc.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// Created by kj16609 on 10/28/24.
|
||||
//
|
||||
|
||||
#include "engine/math/intersections/helpers.hpp"
|
||||
#include "engine/primitives/Frustum.hpp"
|
||||
#include "engine/primitives/boxes/AxisAlignedBoundingBox.hpp"
|
||||
|
||||
namespace fgl::engine::intersections
|
||||
{
|
||||
|
||||
bool intersects( const Frustum& frustum, const AxisAlignedBoundingBox< CS::World >& aabb )
|
||||
{
|
||||
const auto box_points { aabb.points() };
|
||||
|
||||
if ( frustum.containsAnyPoint( box_points ) ) return true;
|
||||
|
||||
const auto frustum_points { frustum.points() };
|
||||
|
||||
if ( canPlotLine( frustum, frustum_points, box_points ) ) return false;
|
||||
|
||||
// Now to test every axis from the bounding box
|
||||
if ( testAxis( aabb.right(), frustum_points, box_points ) ) return false;
|
||||
if ( testAxis( aabb.forward(), frustum_points, box_points ) ) return false;
|
||||
if ( testAxis( aabb.up(), frustum_points, box_points ) ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace fgl::engine::intersections
|
||||
15
src/engine/math/intersections/frustum/intersections.hpp
Normal file
15
src/engine/math/intersections/frustum/intersections.hpp
Normal file
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// Created by kj16609 on 10/28/24.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include "engine/primitives/boxes/AxisAlignedBoundingCube.hpp"
|
||||
|
||||
namespace fgl::engine::intersections
|
||||
{
|
||||
|
||||
bool intersects( const Frustum& frustum, const AxisAlignedBoundingBox< CS::World >& aabb );
|
||||
bool intersects( const Frustum& frustum, const AxisAlignedBoundingCube< CS::World >& aabc );
|
||||
bool intersects( const Frustum& frustum, const OrientedBoundingBox< CS::World >& obb );
|
||||
|
||||
} // namespace fgl::engine::intersections
|
||||
30
src/engine/math/intersections/frustum/obb.cpp
Normal file
30
src/engine/math/intersections/frustum/obb.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// Created by kj16609 on 10/28/24.
|
||||
//
|
||||
|
||||
#include "engine/math/intersections/helpers.hpp"
|
||||
#include "engine/primitives/Frustum.hpp"
|
||||
#include "engine/primitives/boxes/OrientedBoundingBox.hpp"
|
||||
|
||||
namespace fgl::engine::intersections
|
||||
{
|
||||
|
||||
bool intersects( const Frustum& frustum, const OrientedBoundingBox< CS::World >& obb )
|
||||
{
|
||||
const auto box_points { obb.points() };
|
||||
|
||||
if ( frustum.containsAnyPoint( box_points ) ) return true;
|
||||
|
||||
const auto frustum_points { frustum.points() };
|
||||
|
||||
if ( canPlotLine( frustum, frustum_points, box_points ) ) return false;
|
||||
|
||||
// Now to test every axis from the bounding box
|
||||
if ( testAxis( obb.right(), frustum_points, box_points ) ) return false;
|
||||
if ( testAxis( obb.forward(), frustum_points, box_points ) ) return false;
|
||||
if ( testAxis( obb.up(), frustum_points, box_points ) ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace fgl::engine::intersections
|
||||
66
src/engine/math/intersections/helpers.hpp
Normal file
66
src/engine/math/intersections/helpers.hpp
Normal file
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// Created by kj16609 on 10/28/24.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include "engine/FGL_DEFINES.hpp"
|
||||
#include "engine/primitives/Frustum.hpp"
|
||||
#include "engine/primitives/vectors/NormalVector.hpp"
|
||||
|
||||
namespace fgl::engine
|
||||
{
|
||||
|
||||
//! Returns the max and min of a point along an axis
|
||||
std::pair< float, float > minMaxDot( const NormalVector axis, const auto points )
|
||||
{
|
||||
assert( points.size() > 2 );
|
||||
float min { std::numeric_limits< float >::infinity() };
|
||||
float max { -std::numeric_limits< float >::infinity() };
|
||||
|
||||
for ( std::size_t i = 0; i < points.size(); ++i )
|
||||
{
|
||||
const auto value { glm::dot( points[ i ].vec(), axis.vec() ) };
|
||||
|
||||
min = std::min( min, value );
|
||||
max = std::max( max, value );
|
||||
}
|
||||
|
||||
return std::make_pair( min, max );
|
||||
}
|
||||
|
||||
//! Returns true if we can draw a line between the two point sets.
|
||||
template < typename TL, typename TR >
|
||||
//TODO: Concept this to only allow for arrays/vectors
|
||||
bool testAxis( const NormalVector axis, const TL& left_points, const TR& right_points )
|
||||
{
|
||||
const auto [ min_left, max_left ] = minMaxDot( axis, left_points );
|
||||
const auto [ min_right, max_right ] = minMaxDot( axis, right_points );
|
||||
|
||||
//If there is an overlap then we are unable to draw a line between the two.
|
||||
return max_left < min_right || max_right < min_left;
|
||||
}
|
||||
|
||||
// Hyperplane Separation Theorem
|
||||
// Since the bounding box is oriented we need to test all points from it and 3 axis from the frustum and 3 axis from the box.
|
||||
// If we find 1 line that seperates then we fail the test and can early exit
|
||||
// This test might be more optimal to do then a pointInside check since it will early fail rather then early pass.
|
||||
// We can also make this more optimal by discarding overlapping points. For example, Testing the right axis vector on the Frustum means we can discard the 'low' points. Since the 'high' points would be identical.
|
||||
// Though this will likely be a micro-optimizaton in the long run anyways. But less tests means we might be able to almost half the points being tested.
|
||||
|
||||
//! Can plot line between frustum and a given set of points
|
||||
template < CoordinateSpace CType, std::uint64_t FrustumPointCount, std::uint64_t BoundingBoxPointCount >
|
||||
FGL_FLATTEN_HOT bool canPlotLine(
|
||||
const Frustum& frustum,
|
||||
const std::array< Coordinate< CType >, FrustumPointCount >& frustum_points,
|
||||
const std::array< Coordinate< CType >, BoundingBoxPointCount >& bounding_points )
|
||||
{
|
||||
return (
|
||||
testAxis( frustum.right.getDirection(), frustum_points, bounding_points )
|
||||
|| testAxis( frustum.left.getDirection(), frustum_points, bounding_points )
|
||||
|| testAxis( frustum.near.getDirection(), frustum_points, bounding_points )
|
||||
|| testAxis( frustum.far.getDirection(), frustum_points, bounding_points )
|
||||
|| testAxis( frustum.top.getDirection(), frustum_points, bounding_points )
|
||||
|| testAxis( frustum.bottom.getDirection(), frustum_points, bounding_points ) );
|
||||
}
|
||||
|
||||
} // namespace fgl::engine
|
||||
129
src/engine/math/intersections/line/frustum.cpp
Normal file
129
src/engine/math/intersections/line/frustum.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
//
|
||||
// Created by kj16609 on 10/28/24.
|
||||
//
|
||||
|
||||
#include "engine/primitives/Frustum.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "engine/primitives/lines/LineSegment.hpp"
|
||||
#include "engine/primitives/points/Coordinate.hpp"
|
||||
|
||||
namespace fgl::engine::intersection
|
||||
{
|
||||
|
||||
float signedDistance( const NormalVector direction, const WorldCoordinate& point, const WorldCoordinate& origin )
|
||||
{
|
||||
const glm::vec3 vector_between { point.vec() - origin.vec() };
|
||||
|
||||
const float dot { glm::dot( vector_between, direction.vec() ) };
|
||||
|
||||
if ( std::isnan( dot ) ) return 0.0f;
|
||||
|
||||
assert( !std::isinf( dot ) );
|
||||
|
||||
return dot;
|
||||
}
|
||||
|
||||
void processPlane(
|
||||
const Plane< CoordinateSpace::World >& plane,
|
||||
const LineSegment< CoordinateSpace::World >& line,
|
||||
std::vector< WorldCoordinate >& out_enter_intersections,
|
||||
std::vector< WorldCoordinate >& out_exit_intersections )
|
||||
{
|
||||
const WorldCoordinate intersection { line.intersection( plane ) };
|
||||
|
||||
if ( std::isnan( intersection.vec().x ) || std::isnan( intersection.vec().y )
|
||||
|| std::isnan( intersection.vec().z ) )
|
||||
return;
|
||||
|
||||
const float dot { glm::dot( line.getDirection().vec(), plane.getDirection().vec() ) };
|
||||
|
||||
assert( !std::isnan( dot ) );
|
||||
assert( !std::isinf( dot ) );
|
||||
|
||||
//! The line is entering if the line vector is pointing the same direction as the plane's vector
|
||||
const bool is_line_entering { dot > 0.0f };
|
||||
|
||||
if ( is_line_entering )
|
||||
out_enter_intersections.emplace_back( intersection );
|
||||
else
|
||||
out_exit_intersections.emplace_back( intersection );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
WorldCoordinate getFirstExit(
|
||||
const std::vector< WorldCoordinate >& exit_intersections, const LineSegment< CoordinateSpace::World >& line )
|
||||
{
|
||||
assert( exit_intersections.size() > 0 );
|
||||
|
||||
WorldCoordinate exit_point { exit_intersections.at( 0 ) };
|
||||
float distance { 0.0f };
|
||||
|
||||
for ( const auto intersection_point : exit_intersections )
|
||||
{
|
||||
const float exit_distance { signedDistance( line.getDirection(), intersection_point, line.getPosition() ) };
|
||||
|
||||
//if the distance is lower then it's before the previous
|
||||
if ( exit_distance < distance )
|
||||
{
|
||||
distance = exit_distance;
|
||||
exit_point = intersection_point;
|
||||
}
|
||||
}
|
||||
|
||||
return exit_point;
|
||||
}
|
||||
|
||||
WorldCoordinate getLastEnter(
|
||||
const std::vector< WorldCoordinate >& enter_intersections, const LineSegment< CoordinateSpace::World >& line )
|
||||
{
|
||||
assert( enter_intersections.size() > 0 );
|
||||
|
||||
WorldCoordinate first_exit { enter_intersections.at( 0 ) };
|
||||
float distance { signedDistance( line.getDirection(), line.getEnd(), line.getPosition() ) };
|
||||
//assert( distance > 0.0f );
|
||||
|
||||
for ( const auto intersection_point : enter_intersections )
|
||||
{
|
||||
const float enter_distance {
|
||||
signedDistance( line.getDirection(), intersection_point, line.getPosition() )
|
||||
};
|
||||
|
||||
//If the distance is higher then set it.
|
||||
if ( enter_distance > distance )
|
||||
{
|
||||
distance = enter_distance;
|
||||
first_exit = intersection_point;
|
||||
}
|
||||
}
|
||||
|
||||
return first_exit;
|
||||
}
|
||||
|
||||
bool intersects( const LineSegment< CS::World >& line, const Frustum& frustum )
|
||||
{
|
||||
std::vector< WorldCoordinate > enter_intersections { line.getPosition() };
|
||||
std::vector< WorldCoordinate > exit_intersections { line.getEnd() };
|
||||
|
||||
processPlane( frustum.near, line, enter_intersections, exit_intersections );
|
||||
processPlane( frustum.far, line, enter_intersections, exit_intersections );
|
||||
processPlane( frustum.left, line, enter_intersections, exit_intersections );
|
||||
processPlane( frustum.right, line, enter_intersections, exit_intersections );
|
||||
processPlane( frustum.top, line, enter_intersections, exit_intersections );
|
||||
processPlane( frustum.bottom, line, enter_intersections, exit_intersections );
|
||||
|
||||
if ( enter_intersections.size() == 0 ) return false;
|
||||
if ( exit_intersections.size() == 0 ) return false;
|
||||
|
||||
const auto first_exit { getFirstExit( exit_intersections, line ) };
|
||||
const auto last_enter { getLastEnter( enter_intersections, line ) };
|
||||
|
||||
const float distance_to_exit { signedDistance( line.getDirection(), first_exit, line.getPosition() ) };
|
||||
const float distance_to_enter { signedDistance( line.getDirection(), last_enter, line.getPosition() ) };
|
||||
|
||||
return distance_to_exit >= distance_to_enter;
|
||||
}
|
||||
|
||||
} // namespace fgl::engine::intersection
|
||||
18
src/engine/math/intersections/line/intersections.hpp
Normal file
18
src/engine/math/intersections/line/intersections.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// Created by kj16609 on 10/28/24.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include "engine/primitives/lines/LineSegment.hpp"
|
||||
|
||||
namespace fgl::engine
|
||||
{
|
||||
struct Frustum;
|
||||
}
|
||||
|
||||
namespace fgl::engine::intersections
|
||||
{
|
||||
|
||||
bool intersects( const LineSegment< CS::World >& line, const Frustum& frustum );
|
||||
|
||||
}
|
||||
33
src/engine/math/raycast/raycast.cpp
Normal file
33
src/engine/math/raycast/raycast.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// Created by kj16609 on 10/28/24.
|
||||
//
|
||||
|
||||
#include "raycast.hpp"
|
||||
|
||||
#include "engine/primitives/vectors/Vector.hpp"
|
||||
|
||||
namespace fgl::engine
|
||||
{
|
||||
Ray constructRay( WorldCoordinate& start, WorldCoordinate& end )
|
||||
{
|
||||
const Ray ray { start, start.vectorTo( end ).normalize() };
|
||||
return ray;
|
||||
}
|
||||
|
||||
bool rayHit( const Ray& ray, const OrientedBoundingBox< CS::World >& obb )
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
bool rayHit( const Ray& ray, const AxisAlignedBoundingBox< CS::World >& aabb )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
} // namespace fgl::engine
|
||||
26
src/engine/math/raycast/raycast.hpp
Normal file
26
src/engine/math/raycast/raycast.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// Created by kj16609 on 10/28/24.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include "engine/primitives/Rotation.hpp"
|
||||
#include "engine/primitives/boxes/OrientedBoundingBox.hpp"
|
||||
#include "engine/primitives/points/Coordinate.hpp"
|
||||
|
||||
namespace fgl::engine
|
||||
{
|
||||
class OctTreeNode;
|
||||
|
||||
struct Ray
|
||||
{
|
||||
WorldCoordinate start;
|
||||
NormalVector vector;
|
||||
};
|
||||
|
||||
Ray constructRay( WorldCoordinate& start, WorldCoordinate& end );
|
||||
|
||||
bool rayHit( const Ray& ray, const OrientedBoundingBox< CS::World >& obb, OctTreeNode* root );
|
||||
|
||||
bool rayHit( const Ray& ray, const AxisAlignedBoundingBox< CS::World >& aabb, OctTreeNode* root );
|
||||
|
||||
} // namespace fgl::engine
|
||||
@@ -14,4 +14,7 @@ namespace fgl::engine
|
||||
Camera,
|
||||
Screen
|
||||
};
|
||||
|
||||
using CS = CoordinateSpace;
|
||||
|
||||
} // namespace fgl::engine
|
||||
|
||||
@@ -6,8 +6,11 @@
|
||||
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
#include <iosfwd>
|
||||
#include <vector>
|
||||
|
||||
#include "boxes/AxisAlignedBoundingBox.hpp"
|
||||
#include "engine/debug/drawers.hpp"
|
||||
#include "engine/primitives/boxes/AxisAlignedBoundingBox.hpp"
|
||||
#include "engine/primitives/boxes/AxisAlignedBoundingCube.hpp"
|
||||
#include "engine/primitives/boxes/OrientedBoundingBox.hpp"
|
||||
#include "lines/InfiniteLine.hpp"
|
||||
@@ -25,128 +28,8 @@ namespace fgl::engine
|
||||
return result;
|
||||
}
|
||||
|
||||
float signedDistance( const NormalVector direction, const WorldCoordinate& point, const WorldCoordinate& origin )
|
||||
{
|
||||
const glm::vec3 vector_between { point.vec() - origin.vec() };
|
||||
|
||||
const float dot { glm::dot( vector_between, direction.vec() ) };
|
||||
|
||||
if ( std::isnan( dot ) ) return 0.0f;
|
||||
|
||||
assert( !std::isinf( dot ) );
|
||||
|
||||
return dot;
|
||||
}
|
||||
|
||||
void processPlane(
|
||||
const Plane< CoordinateSpace::World >& plane,
|
||||
const LineSegment< CoordinateSpace::World >& line,
|
||||
std::vector< WorldCoordinate >& out_enter_intersections,
|
||||
std::vector< WorldCoordinate >& out_exit_intersections )
|
||||
{
|
||||
const WorldCoordinate intersection { line.intersection( plane ) };
|
||||
|
||||
if ( std::isnan( intersection.vec().x ) || std::isnan( intersection.vec().y )
|
||||
|| std::isnan( intersection.vec().z ) )
|
||||
return;
|
||||
|
||||
const float dot { glm::dot( line.getDirection().vec(), plane.getDirection().vec() ) };
|
||||
|
||||
assert( !std::isnan( dot ) );
|
||||
assert( !std::isinf( dot ) );
|
||||
|
||||
//! The line is entering if the line vector is pointing the same direction as the plane's vector
|
||||
const bool is_line_entering { dot > 0.0f };
|
||||
|
||||
if ( is_line_entering )
|
||||
out_enter_intersections.emplace_back( intersection );
|
||||
else
|
||||
out_exit_intersections.emplace_back( intersection );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
WorldCoordinate getFirstExit(
|
||||
const std::vector< WorldCoordinate >& exit_intersections, const LineSegment< CoordinateSpace::World >& line )
|
||||
{
|
||||
assert( exit_intersections.size() > 0 );
|
||||
|
||||
WorldCoordinate exit_point { exit_intersections.at( 0 ) };
|
||||
float distance { 0.0f };
|
||||
|
||||
for ( const auto intersection_point : exit_intersections )
|
||||
{
|
||||
const float exit_distance { signedDistance( line.getDirection(), intersection_point, line.getPosition() ) };
|
||||
|
||||
//if the distance is lower then it's before the previous
|
||||
if ( exit_distance < distance )
|
||||
{
|
||||
distance = exit_distance;
|
||||
exit_point = intersection_point;
|
||||
}
|
||||
}
|
||||
|
||||
return exit_point;
|
||||
}
|
||||
|
||||
WorldCoordinate getLastEnter(
|
||||
const std::vector< WorldCoordinate >& enter_intersections, const LineSegment< CoordinateSpace::World >& line )
|
||||
{
|
||||
assert( enter_intersections.size() > 0 );
|
||||
|
||||
WorldCoordinate first_exit { enter_intersections.at( 0 ) };
|
||||
float distance { signedDistance( line.getDirection(), line.getEnd(), line.getPosition() ) };
|
||||
//assert( distance > 0.0f );
|
||||
|
||||
for ( const auto intersection_point : enter_intersections )
|
||||
{
|
||||
const float enter_distance {
|
||||
signedDistance( line.getDirection(), intersection_point, line.getPosition() )
|
||||
};
|
||||
|
||||
//If the distance is higher then set it.
|
||||
if ( enter_distance > distance )
|
||||
{
|
||||
distance = enter_distance;
|
||||
first_exit = intersection_point;
|
||||
}
|
||||
}
|
||||
|
||||
return first_exit;
|
||||
}
|
||||
|
||||
inline static bool show_intersect { false };
|
||||
|
||||
template <>
|
||||
bool Frustum::intersects( const LineSegment< CoordinateSpace::World >& line ) const
|
||||
{
|
||||
std::vector< WorldCoordinate > enter_intersections { line.getPosition() };
|
||||
std::vector< WorldCoordinate > exit_intersections { line.getEnd() };
|
||||
|
||||
processPlane( near, line, enter_intersections, exit_intersections );
|
||||
processPlane( far, line, enter_intersections, exit_intersections );
|
||||
processPlane( left, line, enter_intersections, exit_intersections );
|
||||
processPlane( right, line, enter_intersections, exit_intersections );
|
||||
processPlane( top, line, enter_intersections, exit_intersections );
|
||||
processPlane( bottom, line, enter_intersections, exit_intersections );
|
||||
|
||||
if ( enter_intersections.size() == 0 ) return false;
|
||||
if ( exit_intersections.size() == 0 ) return false;
|
||||
|
||||
const auto first_exit { getFirstExit( exit_intersections, line ) };
|
||||
const auto last_enter { getLastEnter( enter_intersections, line ) };
|
||||
|
||||
const float distance_to_exit { signedDistance( line.getDirection(), first_exit, line.getPosition() ) };
|
||||
const float distance_to_enter { signedDistance( line.getDirection(), last_enter, line.getPosition() ) };
|
||||
|
||||
if ( show_intersect ) [[unlikely]]
|
||||
{
|
||||
//TODO:
|
||||
}
|
||||
|
||||
return distance_to_exit >= distance_to_enter;
|
||||
}
|
||||
|
||||
FGL_FORCE_INLINE inline NormalVector Frustum::forwardVec() const
|
||||
{
|
||||
return near.getDirection();
|
||||
@@ -162,6 +45,41 @@ namespace fgl::engine
|
||||
return NormalVector( glm::cross( forwardVec().vec(), upVec().vec() ) );
|
||||
}
|
||||
|
||||
bool Frustum::containsPoint( const WorldCoordinate coord ) const
|
||||
{
|
||||
static_assert(
|
||||
CoordinateSpace::World == CoordinateSpace::World,
|
||||
"pointInside can only be called on World coordinate Frustums" );
|
||||
|
||||
//Ensure the point we are not trying to test a NaN point
|
||||
assert( coord.x != std::numeric_limits< decltype( coord.x ) >::quiet_NaN() );
|
||||
assert( coord.y != std::numeric_limits< decltype( coord.y ) >::quiet_NaN() );
|
||||
assert( coord.z != std::numeric_limits< decltype( coord.z ) >::quiet_NaN() );
|
||||
|
||||
//TODO: This is a biased approach.
|
||||
// Approaches for non-biased:
|
||||
// We can either make this non-biased by using a projection from distance shot down the FORWARD vector
|
||||
// Or we can use SIMD to check all the planes at once.
|
||||
|
||||
return near.isForward( coord ) && far.isForward( coord ) && bottom.isForward( coord ) && top.isForward( coord )
|
||||
&& right.isForward( coord ) && left.isForward( coord );
|
||||
}
|
||||
|
||||
bool Frustum::containsAnyPoint( const std::vector< WorldCoordinate >& coords ) const
|
||||
{
|
||||
for ( const auto coord : coords )
|
||||
if ( containsPoint( coord ) ) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Frustum::containsAnyPoint( const std::array< WorldCoordinate, interface::BoundingBox::POINT_COUNT >& coords )
|
||||
const
|
||||
{
|
||||
for ( const auto coord : coords )
|
||||
if ( containsPoint( coord ) ) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::array< Coordinate< CoordinateSpace::World >, 4 * 2 > Frustum::points() const
|
||||
{
|
||||
const NormalVector pv0 { glm::cross( top.getDirection().vec(), left.getDirection().vec() ) };
|
||||
@@ -214,12 +132,6 @@ namespace fgl::engine
|
||||
return lines;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool Frustum::intersects( const WorldCoordinate& t ) const
|
||||
{
|
||||
return pointInside( t );
|
||||
}
|
||||
|
||||
//TODO: Implement frustum debug menu
|
||||
[[maybe_unused]] inline static bool check_points { true };
|
||||
[[maybe_unused]] inline static bool check_lines { true };
|
||||
@@ -248,127 +160,6 @@ namespace fgl::engine
|
||||
*/
|
||||
}
|
||||
|
||||
template <>
|
||||
bool Frustum::intersects( const std::vector< WorldCoordinate >& point_cloud ) const
|
||||
{
|
||||
for ( const auto point : point_cloud )
|
||||
{
|
||||
if ( intersects( point ) ) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Returns the max and min of a point along an axis
|
||||
std::pair< float, float > minMaxDot( const NormalVector axis, const auto points )
|
||||
{
|
||||
assert( points.size() > 2 );
|
||||
float min { std::numeric_limits< float >::infinity() };
|
||||
float max { -std::numeric_limits< float >::infinity() };
|
||||
|
||||
for ( std::size_t i = 0; i < points.size(); ++i )
|
||||
{
|
||||
const auto value { glm::dot( points[ i ].vec(), axis.vec() ) };
|
||||
|
||||
min = std::min( min, value );
|
||||
max = std::max( max, value );
|
||||
}
|
||||
|
||||
return std::make_pair( min, max );
|
||||
}
|
||||
|
||||
//! Returns true if we can draw a line between the two point sets.
|
||||
template < typename TL, typename TR >
|
||||
//TODO: Concept this to only allow for arrays/vectors
|
||||
bool testAxis( const NormalVector axis, const TL& left_points, const TR& right_points )
|
||||
{
|
||||
const auto [ min_left, max_left ] = minMaxDot( axis, left_points );
|
||||
const auto [ min_right, max_right ] = minMaxDot( axis, right_points );
|
||||
|
||||
//If there is an overlap then we are unable to draw a line between the two.
|
||||
return max_left < min_right || max_right < min_left;
|
||||
}
|
||||
|
||||
// Dividing Hyperline Theorem
|
||||
// Since the bounding box is oriented we need to test all points from it and 3 axis from the frustum and 3 axis from the box.
|
||||
// If we find 1 line that seperates then we fail the test and can early exit
|
||||
// This test might be more optimal to do then a pointInside check since it will early fail rather then early pass.
|
||||
// We can also make this more optimal by discarding overlapping points. For example, Testing the right axis vector on the Frustum means we can discard the 'low' points. Since the 'high' points would be identical.
|
||||
// Though this will likely be a micro-optimizaton in the long run anyways. But less tests means we might be able to almost half the points being tested.
|
||||
|
||||
//! Can plot line between frustum and a given set of points
|
||||
template < CoordinateSpace CType, std::uint64_t FrustumPointCount, std::uint64_t BoundingBoxPointCount >
|
||||
FGL_FLATTEN_HOT bool canPlotLine(
|
||||
const Frustum& frustum,
|
||||
const std::array< Coordinate< CType >, FrustumPointCount >& frustum_points,
|
||||
const std::array< Coordinate< CType >, BoundingBoxPointCount >& bounding_points )
|
||||
{
|
||||
return (
|
||||
testAxis( frustum.right.getDirection(), frustum_points, bounding_points )
|
||||
|| testAxis( frustum.left.getDirection(), frustum_points, bounding_points )
|
||||
|| testAxis( frustum.near.getDirection(), frustum_points, bounding_points )
|
||||
|| testAxis( frustum.far.getDirection(), frustum_points, bounding_points )
|
||||
|| testAxis( frustum.top.getDirection(), frustum_points, bounding_points )
|
||||
|| testAxis( frustum.bottom.getDirection(), frustum_points, bounding_points ) );
|
||||
}
|
||||
|
||||
template <>
|
||||
FGL_FLATTEN bool Frustum::intersects( const OrientedBoundingBox< CoordinateSpace::World >& bounding_box ) const
|
||||
{
|
||||
const auto box_points { bounding_box.points() };
|
||||
|
||||
if ( intersects( box_points ) ) return true;
|
||||
|
||||
const auto frustum_points { this->points() };
|
||||
|
||||
if ( canPlotLine( *this, frustum_points, box_points ) ) return false;
|
||||
|
||||
// Now to test every axis from the bounding box
|
||||
if ( testAxis( bounding_box.right(), frustum_points, box_points ) ) return false;
|
||||
if ( testAxis( bounding_box.forward(), frustum_points, box_points ) ) return false;
|
||||
if ( testAxis( bounding_box.up(), frustum_points, box_points ) ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
FGL_FLATTEN bool Frustum::intersects( const AxisAlignedBoundingBox< CoordinateSpace::World >& bounding_box ) const
|
||||
{
|
||||
const auto box_points { bounding_box.points() };
|
||||
|
||||
if ( intersects( box_points ) ) return true;
|
||||
|
||||
const auto frustum_points { this->points() };
|
||||
|
||||
if ( canPlotLine( *this, frustum_points, box_points ) ) return false;
|
||||
|
||||
// Now to test every axis from the bounding box
|
||||
if ( testAxis( bounding_box.right(), frustum_points, box_points ) ) return false;
|
||||
if ( testAxis( bounding_box.forward(), frustum_points, box_points ) ) return false;
|
||||
if ( testAxis( bounding_box.up(), frustum_points, box_points ) ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
FGL_FLATTEN bool Frustum::intersects( const AxisAlignedBoundingCube< CoordinateSpace::World >& bounding_box ) const
|
||||
{
|
||||
const auto box_points { bounding_box.points() };
|
||||
|
||||
if ( intersects( box_points ) ) return true;
|
||||
|
||||
const auto frustum_points { this->points() };
|
||||
|
||||
if ( canPlotLine( *this, frustum_points, box_points ) ) return false;
|
||||
|
||||
// Now to test every axis from the bounding box
|
||||
if ( testAxis( bounding_box.right(), frustum_points, box_points ) ) return false;
|
||||
if ( testAxis( bounding_box.forward(), frustum_points, box_points ) ) return false;
|
||||
if ( testAxis( bounding_box.up(), frustum_points, box_points ) ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace debug
|
||||
{
|
||||
void drawFrustum( const Frustum& frustum )
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <ostream>
|
||||
#include <vector>
|
||||
|
||||
#include "engine/primitives/boxes/BoundingBox.hpp"
|
||||
#include "engine/primitives/planes/PointPlane.hpp"
|
||||
#include "engine/primitives/points/Coordinate.hpp"
|
||||
#include "vectors/Vector.hpp"
|
||||
@@ -89,38 +91,11 @@ namespace fgl::engine
|
||||
WorldCoordinate getPosition() const { return m_position; }
|
||||
|
||||
//! Tests if a point is inside of the frustum
|
||||
bool pointInside( const WorldCoordinate coord ) const
|
||||
{
|
||||
static_assert(
|
||||
CoordinateSpace::World == CoordinateSpace::World,
|
||||
"pointInside can only be called on World coordinate Frustums" );
|
||||
|
||||
//Ensure the point we are not trying to test a NaN point
|
||||
assert( coord.x != std::numeric_limits< decltype( coord.x ) >::quiet_NaN() );
|
||||
assert( coord.y != std::numeric_limits< decltype( coord.y ) >::quiet_NaN() );
|
||||
assert( coord.z != std::numeric_limits< decltype( coord.z ) >::quiet_NaN() );
|
||||
|
||||
//TODO: This is a biased approach.
|
||||
// Approaches for non-biased:
|
||||
// We can either make this non-biased by using a projection from distance shot down the FORWARD vector
|
||||
// Or we can use SIMD to check all the planes at once.
|
||||
|
||||
return near.isForward( coord ) && far.isForward( coord ) && bottom.isForward( coord )
|
||||
&& top.isForward( coord ) && right.isForward( coord ) && left.isForward( coord );
|
||||
}
|
||||
|
||||
//! Returns true if the frustum intersects type T
|
||||
template < typename T >
|
||||
bool intersects( const T& t ) const;
|
||||
|
||||
//! Itterates over all items in the array given, Returns false if **ANY** fail
|
||||
template < typename T, std::size_t N >
|
||||
bool intersects( const std::array< T, N >& ts ) const
|
||||
{
|
||||
for ( const auto& t : ts )
|
||||
if ( !intersects( t ) ) return false;
|
||||
return true;
|
||||
}
|
||||
bool containsPoint( const WorldCoordinate coord ) const;
|
||||
//! Returns true if ANY point is inside the frustum
|
||||
bool containsAnyPoint( const std::vector< WorldCoordinate >& coords ) const;
|
||||
//! Used for bounding box tests
|
||||
bool containsAnyPoint( const std::array< WorldCoordinate, interface::BoundingBox::POINT_COUNT >& coords ) const;
|
||||
|
||||
std::array< WorldCoordinate, 4 * 2 > points() const;
|
||||
std::array< LineSegment< CoordinateSpace::World >, ( ( 4 * 2 ) / 2 ) * 3 > lines() const;
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
namespace fgl::engine
|
||||
{
|
||||
|
||||
|
||||
NormalVector::NormalVector( const fgl::engine::Vector vector ) : NormalVector( vector.vec() )
|
||||
{}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#include "engine/primitives/CoordinateSpace.hpp"
|
||||
#include "engine/primitives/Rotation.hpp"
|
||||
|
||||
namespace fgl::engine
|
||||
{
|
||||
|
||||
@@ -20,6 +20,11 @@ namespace fgl::engine
|
||||
return *this;
|
||||
}
|
||||
|
||||
NormalVector Vector::normalize() const
|
||||
{
|
||||
return NormalVector( *this );
|
||||
}
|
||||
|
||||
glm::vec3 Vector::forward() const
|
||||
{
|
||||
//TODO: Figure out Z shit
|
||||
|
||||
@@ -72,6 +72,8 @@ namespace fgl::engine
|
||||
{
|
||||
return coord - *this;
|
||||
}
|
||||
|
||||
NormalVector normalize() const;
|
||||
};
|
||||
|
||||
inline Vector operator-( const Vector vec )
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "Shader.hpp"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "engine/debug/logging/logging.hpp"
|
||||
#include "engine/rendering/devices/Device.hpp"
|
||||
#include "shaders/Compiler.hpp"
|
||||
@@ -15,7 +17,7 @@ namespace fgl::engine
|
||||
{
|
||||
if ( auto ifs = std::ifstream( path, std::ios::binary | std::ios::ate ); ifs )
|
||||
{
|
||||
std::vector< std::byte > data;
|
||||
std::vector< std::byte > data {};
|
||||
data.resize( ifs.tellg() );
|
||||
ifs.seekg( 0, std::ios::beg );
|
||||
|
||||
@@ -23,8 +25,6 @@ namespace fgl::engine
|
||||
|
||||
ifs.read( reinterpret_cast< std::ifstream::char_type* >( data.data() ), data.size() );
|
||||
|
||||
// We now need to compile the shader before we use it.
|
||||
|
||||
return compileShader( path.filename().string(), data );
|
||||
}
|
||||
else
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <vulkan/vulkan_raii.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
namespace fgl::engine
|
||||
{
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "engine/debug/drawers.hpp"
|
||||
#include "engine/debug/profiling/counters.hpp"
|
||||
#include "engine/gameobjects/components/ModelComponent.hpp"
|
||||
#include "engine/math/intersections.hpp"
|
||||
#include "engine/tree/octtree/OctTreeNode.hpp"
|
||||
|
||||
namespace fgl::engine
|
||||
@@ -63,7 +64,7 @@ namespace fgl::engine
|
||||
matrix * primitive.getBoundingBox()
|
||||
};
|
||||
|
||||
if ( !frustum.intersects( world_bounding_box ) ) continue;
|
||||
if ( !intersects( frustum, world_bounding_box ) ) continue;
|
||||
|
||||
//assert( primitive.m_texture );
|
||||
const ModelMatrixInfo matrix_info { .model_matrix = matrix,
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "engine/assets/model/Model.hpp"
|
||||
#include "engine/clock.hpp"
|
||||
#include "engine/debug/drawers.hpp"
|
||||
#include "engine/math/intersections.hpp"
|
||||
#include "engine/primitives/Frustum.hpp"
|
||||
|
||||
namespace fgl::engine
|
||||
@@ -254,7 +255,7 @@ namespace fgl::engine
|
||||
bool OctTreeNode::isInFrustum( const Frustum& frustum ) const
|
||||
{
|
||||
#if ENABLE_IMGUI
|
||||
if ( !isEmpty() && frustum.intersects( m_fit_bounding_box ) )
|
||||
if ( !isEmpty() && intersects( frustum, m_fit_bounding_box ) )
|
||||
{
|
||||
if ( ( draw_inview_bounds || ( std::holds_alternative< OctTreeNodeLeaf >( this->m_node_data ) )
|
||||
|| draw_branches )
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
#include <bitset>
|
||||
|
||||
#include "engine/gameobjects/GameObject.hpp"
|
||||
#include "engine/primitives/boxes/AxisAlignedBoundingCube.hpp"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user