Gets frustum culling via line intersection mostly working

This commit is contained in:
2024-02-26 02:53:59 -05:00
parent 40cbffc450
commit 3a38e50b72
23 changed files with 480 additions and 559 deletions

View File

@@ -3,20 +3,6 @@
file(GLOB_RECURSE CPP_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/**.cpp")
add_library(FGLEngine STATIC ${CPP_SOURCES})
target_precompile_headers(FGLEngine PRIVATE
<vector>
<iostream>
<vulkan/vulkan.h>
<tracy/Tracy.hpp>
<vma/vma_impl.hpp>
<glm/glm.hpp>
<glm/gtc/matrix_transform.hpp>
<glm/gtc/constants.hpp>
<array>
<chrono>
<optional>
<imgui/imgui.h>
)
target_compile_definitions(FGLEngine PUBLIC VULKAN_HPP_FLAGS_MASK_TYPE_AS_PUBLIC)

View File

@@ -9,6 +9,7 @@
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/string_cast.hpp>
#include <tracy/Tracy.hpp>
#include <cassert>
#include <limits>
@@ -27,7 +28,6 @@ namespace fgl::engine
void Camera::setPerspectiveProjection( float fovy, float aspect, float near, float far )
{
ZoneScoped;
projection_matrix = Matrix< MatrixType::CameraToScreen >( glm::perspectiveLH_ZO( fovy, aspect, near, far ) );
base_frustum = createFrustum( aspect, fovy, near, far );

View File

@@ -61,8 +61,8 @@ namespace fgl::engine
PerFrameSuballocation< HostSingleT< PointLight > > point_lights { global_ubo_buffer,
SwapChain::MAX_FRAMES_IN_FLIGHT };
constexpr std::uint32_t matrix_default_size { 16_MiB };
constexpr std::uint32_t draw_parameter_default_size { 16_MiB };
constexpr std::uint32_t matrix_default_size { 64_MiB };
constexpr std::uint32_t draw_parameter_default_size { 64_MiB };
std::vector< Buffer > matrix_info_buffers {};
@@ -94,6 +94,7 @@ namespace fgl::engine
}
Camera camera {};
debug::setDebugDrawingCamera( camera );
auto viewer { GameObject::createGameObject() };
viewer.transform.translation = constants::WORLD_CENTER + glm::vec3( 0.0f, 0.0f, -2.5f );
@@ -246,6 +247,11 @@ namespace fgl::engine
inputRVec3( "Rotation", Camera::frustum_alt_transform.rotation );
ImGui::PopID();
}
if ( camera.update_using_alt || !camera.update_frustums )
{
debug::world::drawFrustum();
}
}
if ( ImGui::CollapsingHeader( "View Frustum" ) )
@@ -409,8 +415,8 @@ namespace fgl::engine
TracyVkZone( tracy_ctx, command_buffer, "ImGui Rendering" );
#endif
debug::world::drawPointText(
Coordinate< CoordinateSpace::World >( 0.0f, 0.0f, 0.0f ), camera, { 1.0f, 0.0f, 0.0f } );
debug::world::
drawPointText( Coordinate< CoordinateSpace::World >( 0.0f, 0.0f, 0.0f ), { 1.0f, 0.0f, 0.0f } );
ImGui::End();
ImGui::Render();
@@ -465,9 +471,11 @@ namespace fgl::engine
model->syncBuffers( command_buffer );
for ( int x = 0; x < 32; ++x )
int val { 2 };
for ( int x = 0; x < val; ++x )
{
for ( int y = 0; y < 32; ++y )
for ( int y = 0; y < val; ++y )
{
auto sponza = GameObject::createGameObject();
sponza.model = model;

View File

@@ -5,6 +5,7 @@
#pragma once
#include <memory>
#include <thread>
#include <vector>
#include "Device.hpp"

View File

@@ -4,7 +4,9 @@
#include "KeyboardMovementController.hpp"
#include <chrono>
#include <functional>
#include <iostream>
#include "engine/primitives/Vector.hpp"

View File

@@ -14,6 +14,7 @@
#include <cstring>
#include <iostream>
#include <map>
#include <memory>
#include <stdexcept>
#include <unordered_map>

View File

@@ -6,6 +6,8 @@
#include <vulkan/vulkan.hpp>
#include <memory>
namespace fgl::engine
{

View File

@@ -8,26 +8,38 @@
#include "engine/model/BoundingBox.hpp"
#include "engine/primitives/Line.hpp"
#include "engine/primitives/Vector.hpp"
#include "imgui/imgui.h"
#include "tracy_colors.hpp"
#if ENABLE_IMGUI_DRAWERS
namespace fgl::engine::debug
{
inline static std::optional< Camera* > debug_camera { std::nullopt };
Camera& getDebugDrawingCamera()
{
return *debug_camera.value();
}
void setDebugDrawingCamera( Camera& cam )
{
debug_camera = &cam;
}
const ImVec2 windowSize()
{
return ImGui::GetMainViewport()->Size;
}
Coordinate< CoordinateSpace::Screen >
toScreenSpace( Coordinate< CoordinateSpace::World > world_point, const Camera& camera )
Coordinate< CoordinateSpace::Screen > toScreenSpace( Coordinate< CoordinateSpace::World > world_point )
{
const ImVec2 window_size { windowSize() };
const Coordinate< CoordinateSpace::Screen > screen_point { glm::projectZO(
static_cast< glm::vec3 >( world_point ),
glm::mat4( 1.0f ),
camera.getProjectionViewMatrix(),
getDebugDrawingCamera().getProjectionViewMatrix(),
glm::vec4( 0.0f, 0.0f, window_size.x, window_size.y ) ) };
return screen_point;
@@ -58,27 +70,36 @@ namespace fgl::engine::debug
namespace world
{
void drawBoundingBox( const BoundingBox< CoordinateSpace::World >& box, Camera& camera, const glm::vec3 color )
inline void drawLineI( const Line< CoordinateSpace::World > line, const glm::vec3 color )
{
//Check if the line in intersecting the frustum
if ( getDebugDrawingCamera().getFrustumBounds().intersects( line ) )
drawLine( line, glm::vec3( 0.0f, 1.0f, 0.0f ) );
else
drawLine( line, color );
}
void drawBoundingBox( const BoundingBox< CoordinateSpace::World >& box, const glm::vec3 color )
{
ZoneScopedC( TRACY_DRAWER_FUNC_COLOR );
for ( const auto [ p1, p2 ] : box.lines() )
{
drawLine( p1, p2, camera, color );
drawLineI( { p1, p2 }, color );
}
for ( const auto point : box.points() )
{
drawPointText( point, camera, color );
drawPointText( point, color );
}
}
inline void drawLine( const Line< CoordinateSpace::World > line, const Camera& camera, const glm::vec3 color )
inline void drawLine( const Line< CoordinateSpace::World > line, const glm::vec3 color )
{
const Coordinate< CoordinateSpace::Screen > start_screen { toScreenSpace( line.start, camera ) };
const Coordinate< CoordinateSpace::Screen > end_screen { toScreenSpace( line.end, camera ) };
const Coordinate< CoordinateSpace::Screen > start_screen { toScreenSpace( line.start ) };
const Coordinate< CoordinateSpace::Screen > end_screen { toScreenSpace( line.end ) };
if ( !inView( start_screen ) && !inView( end_screen ) ) return;
if ( isBehind( start_screen ) || isBehind( end_screen ) ) return;
ImGui::GetForegroundDrawList()
@@ -88,20 +109,18 @@ namespace fgl::engine::debug
void drawLine(
const Coordinate< CoordinateSpace::World > start,
const Coordinate< CoordinateSpace::World > end,
const Camera& camera,
const glm::vec3 color )
{
drawLine( { start, end }, camera, color );
drawLine( { start, end }, color );
}
void drawPointText(
const Coordinate< CoordinateSpace::World > point, const Camera& camera, const glm::vec3 color )
void drawPointText( const Coordinate< CoordinateSpace::World > point, const glm::vec3 color )
{
const glm::vec3 screen_point { toScreenSpace( point, camera ) };
const glm::vec3 screen_point { toScreenSpace( point ) };
if ( !inView( screen_point ) ) return;
drawPoint( point, camera, "", color );
drawPoint( point, "", color );
const std::string text { "World: (" + std::to_string( point.x ) + ", " + std::to_string( point.y ) + ", "
+ std::to_string( point.z ) + ")" };
@@ -114,16 +133,15 @@ namespace fgl::engine::debug
screen::drawText( glm::vec2( screen_point.x, screen_point.y ), text2, color, glm::vec2( 0.0f, 30.0f ) );
const Frustum frustum { camera.getFrustumBounds() };
const Frustum frustum { getDebugDrawingCamera().getFrustumBounds() };
const bool in_view { frustum.pointInside( point ) };
drawBoolAlpha( point, camera, in_view, glm::vec2( 0.0f, 40.0f ) );
drawBoolAlpha( point, in_view, glm::vec2( 0.0f, 40.0f ) );
}
void drawPointLabel(
const Coordinate< CoordinateSpace::World > point, const std::string label, const Camera& camera )
void drawPointLabel( const Coordinate< CoordinateSpace::World > point, const std::string label )
{
const glm::vec3 screen_point { toScreenSpace( point, camera ) };
const glm::vec3 screen_point { toScreenSpace( point ) };
if ( !inView( screen_point ) ) return;
@@ -131,27 +149,20 @@ namespace fgl::engine::debug
}
void drawPoint(
const Coordinate< CoordinateSpace::World > point,
const Camera& camera,
const std::string label,
const glm::vec3 color )
const Coordinate< CoordinateSpace::World > point, const std::string label, const glm::vec3 color )
{
const auto screen_point { toScreenSpace( point, camera ) };
const auto screen_point { toScreenSpace( point ) };
if ( !inView( screen_point ) ) return;
ImGui::GetForegroundDrawList()
->AddCircleFilled( glmToImgui( screen_point ), 5.0f, ImColor( color.x, color.y, color.z ) );
drawPointLabel( point, label, camera );
drawPointLabel( point, label );
}
void drawBoolAlpha(
const Coordinate< CoordinateSpace::World > point,
const Camera& camera,
const bool value,
const glm::vec2 offset )
void drawBoolAlpha( const Coordinate< CoordinateSpace::World > point, const bool value, const glm::vec2 offset )
{
const auto screen_point { toScreenSpace( point, camera ) };
const auto screen_point { toScreenSpace( point ) };
const auto color { value ? glm::vec3( 0.0f, 1.0f, 0.0f ) : glm::vec3( 1.0f, 0.0f, 0.0f ) };
@@ -161,14 +172,14 @@ namespace fgl::engine::debug
void drawVector(
const Coordinate< CoordinateSpace::World > point,
Vector vector,
const Camera& camera,
const std::string label,
const glm::vec3 color )
{
drawLine( point, point + glm::normalize( vector ), camera, color );
drawPoint( point + glm::normalize( vector ), camera, label, color );
drawPointLabel( point, label, camera );
drawPointText( point + glm::normalize( vector ), camera );
drawLine( point, point + glm::normalize( vector ), color );
drawPoint( point + glm::normalize( vector ), label, color );
drawPoint( point, "", color );
//drawPointLabel( point, label );
//drawPointText( point + glm::normalize( vector ) );
//Draw ending lines for the vector (two perpendicular lines)
const glm::vec3 perpendicular_vector { glm::normalize( glm::cross( vector, glm::vec3( 0.0f, 1.0f, 0.0f ) ) )
@@ -179,37 +190,33 @@ namespace fgl::engine::debug
drawLine(
point + glm::normalize( vector ) + perpendicular_vector,
point + glm::normalize( vector ) - perpendicular_vector,
camera,
color );
drawLine(
point + glm::normalize( vector ) + perpendicular_vector2,
point + glm::normalize( vector ) - perpendicular_vector2,
camera,
color );
}
void drawFrustum(
const Frustum< CoordinateSpace::World >& frustum, const Camera& camera, const WorldCoordinate point )
void drawFrustum( const Frustum< CoordinateSpace::World >& frustum, const WorldCoordinate point )
{
drawPlane( frustum.near, point, camera, "near" );
drawPlane( frustum.far, point, camera, "far" );
drawPlane( frustum.top, point, camera, "top" );
drawPlane( frustum.bottom, point, camera, "bottom" );
drawPlane( frustum.right, point, camera, "right" );
drawPlane( frustum.left, point, camera, "left" );
drawPlane( frustum.near, point, "near" );
drawPlane( frustum.far, point, "far" );
drawPlane( frustum.top, point, "top" );
drawPlane( frustum.bottom, point, "bottom" );
drawPlane( frustum.right, point, "right" );
drawPlane( frustum.left, point, "left" );
}
void drawFrustum( const Camera& camera )
void drawFrustum()
{
const Frustum frustum { camera.getFrustumBounds() };
drawFrustum( frustum, camera, camera.getFrustumPosition() );
const Frustum frustum { getDebugDrawingCamera().getFrustumBounds() };
drawFrustum( frustum, getDebugDrawingCamera().getFrustumPosition() );
}
void drawPlane(
const Plane< CoordinateSpace::World >& plane,
const WorldCoordinate point,
const Camera& camera,
const std::string label,
const glm::vec3 color )
{
@@ -217,8 +224,8 @@ namespace fgl::engine::debug
assert( point != constants::DEFAULT_VEC3 );
drawLine( point, point + normal, camera, color );
drawPoint( point + normal, camera, label, color );
drawLine( point, point + normal, color );
drawPoint( point + normal, label, color );
}
} // namespace world

View File

@@ -33,59 +33,46 @@ namespace fgl::engine
#if ENABLE_IMGUI_DRAWERS
namespace fgl::engine::debug
{
Camera& getDebugDrawingCamera();
void setDebugDrawingCamera( Camera& );
namespace world
{
void drawBoundingBox(
const BoundingBox< CoordinateSpace::World >& box,
Camera& camera,
const glm::vec3 color = { 1.0f, 1.0f, 1.0f } );
const BoundingBox< CoordinateSpace::World >& box, const glm::vec3 color = { 1.0f, 1.0f, 1.0f } );
void drawLine(
const Coordinate< CoordinateSpace::World > start,
const Coordinate< CoordinateSpace::World > end,
const Camera& camera,
const glm::vec3 color = { 1.0f, 1.0f, 1.0f } );
void drawPointLabel(
const Coordinate< CoordinateSpace::World > point, const std::string label, const Camera& camera );
void drawPointLabel( const Coordinate< CoordinateSpace::World > point, const std::string label );
void drawLine(
const Line< CoordinateSpace::World > line,
const Camera& camera,
const glm::vec3 color = { 1.0f, 1.0f, 1.0f } );
void drawLineI( const Line< CoordinateSpace::World > line, const glm::vec3 color = { 1.0f, 1.0f, 1.0f } );
void drawLine( const Line< CoordinateSpace::World > line, const glm::vec3 color = { 1.0f, 1.0f, 1.0f } );
void drawPointText(
const Coordinate< CoordinateSpace::World > point,
const Camera& camera,
const glm::vec3 color = { 1.0f, 1.0f, 1.0f } );
const Coordinate< CoordinateSpace::World > point, const glm::vec3 color = { 1.0f, 1.0f, 1.0f } );
void drawBoolAlpha(
const Coordinate< CoordinateSpace::World > point,
const Camera& camera,
const bool value,
const glm::vec2 offset = {} );
const Coordinate< CoordinateSpace::World > point, const bool value, const glm::vec2 offset = {} );
void drawPoint(
const Coordinate< CoordinateSpace::World > point,
const Camera& camera,
const std::string label = "",
const glm::vec3 color = { 1.0f, 1.0f, 1.0f } );
void drawVector(
const Coordinate< CoordinateSpace::World > point,
Vector vector,
const Camera& camera,
const std::string label = "",
const glm::vec3 color = { 1.0f, 1.0f, 1.0f } );
void drawFrustum(
const Frustum< CoordinateSpace::World >& frustum, const Camera& camera, const WorldCoordinate coordinate );
void drawFrustum( const Camera& camera );
void drawFrustum( const Frustum< CoordinateSpace::World >& frustum, const WorldCoordinate coordinate );
void drawFrustum();
void drawPlane(
const Plane< CoordinateSpace::World >& plane,
const WorldCoordinate point,
const Camera& camera,
const std::string label = "",
const glm::vec3 color = { 1.0f, 1.0f, 1.0f } );

View File

@@ -6,6 +6,7 @@
#include <glm/mat4x4.hpp>
#include <stdexcept>
#include <tuple>
#include <utility>

View File

@@ -124,4 +124,10 @@ namespace glm
return Coordinate< CType >( static_cast< glm::vec3 >( lhs ) - static_cast< glm::vec3 >( rhs ) );
}
inline float
distance( const Coordinate< CoordinateSpace::World > coord, const Coordinate< CoordinateSpace::World > other )
{
return glm::distance( static_cast< glm::vec3 >( coord ), static_cast< glm::vec3 >( other ) );
}
} // namespace glm

View File

@@ -4,36 +4,104 @@
#include "Frustum.hpp"
#include "engine/debug/drawers.hpp"
#include "engine/model/BoundingBox.hpp"
namespace fgl::engine
{
float signedDistance( const Vector direction, const WorldCoordinate& point, const WorldCoordinate& origin )
{
const glm::vec3 vector_between { point - origin };
float dot { glm::dot( vector_between, static_cast< glm::vec3 >( glm::normalize( direction ) ) ) };
return dot;
}
void processPlane(
const Plane< CoordinateSpace::World > plane,
const Line< CoordinateSpace::World > line,
std::vector< WorldCoordinate >& out_enter_intersections,
std::vector< WorldCoordinate >& out_exit_intersections )
{
const WorldCoordinate intersection { plane.intersection( line ) };
if ( std::isnan( intersection.x ) || std::isnan( intersection.y ) || std::isnan( intersection.z ) ) return;
//! The line is entering if the line vector is pointing the same direction as the plane's vector
const bool is_line_entering {
glm::dot( glm::normalize( line.direction() ), glm::normalize( plane.direction() ) ) > 0.0f
};
if ( is_line_entering )
{
// debug::world::drawVector( intersection, line.direction() );
// debug::world::drawVector( intersection, plane.direction(), "", glm::vec3( 0.0f, 1.0f, 0.0f ) );
out_enter_intersections.emplace_back( intersection );
}
else
{
// debug::world::drawVector( intersection, line.direction() );
// debug::world::drawVector( intersection, plane.direction(), "", glm::vec3( 1.0f, 0.0f, 0.0f ) );
out_exit_intersections.emplace_back( intersection );
}
}
template <>
template <>
bool Frustum< CoordinateSpace::World >::intersects( const Line< CoordinateSpace::World > line ) const
{
const bool top_intersects { top.intersects( line ) };
const bool bottom_intersects { bottom.intersects( line ) };
std::vector< WorldCoordinate > enter_intersections { line.start };
std::vector< WorldCoordinate > exit_intersections { line.end };
const bool left_intersects { left.intersects( line ) };
const bool right_intersects { right.intersects( line ) };
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 );
const bool near_intersects { near.intersects( line ) };
const bool far_intersects { far.intersects( line ) };
if ( enter_intersections.size() == 0 ) return false;
if ( exit_intersections.size() == 0 ) return false;
//Check if the line passes through the frustum
const bool intersects_left_right { left_intersects && right_intersects };
const bool intersects_top_bottom { top_intersects && bottom_intersects };
WorldCoordinate last_enter { enter_intersections.at( 0 ) };
float last_enter_distance { 0.0f };
const bool line_within_near_far { !near_intersects && !far_intersects };
WorldCoordinate first_exit { exit_intersections.at( 0 ) };
float first_exit_distance { signedDistance( line.direction(), line.end, line.start ) };
assert( first_exit_distance > 0.0f );
const bool line_outside_top_bottom { !top_intersects && !bottom_intersects };
const bool line_outside_left_right { !left_intersects && !right_intersects };
//Determine the first exit
for ( const auto exit_point : exit_intersections )
{
const float exit_distance { signedDistance( line.direction(), exit_point, line.start ) };
const bool line_outside_range { line_outside_top_bottom && line_outside_left_right };
if ( first_exit_distance > exit_distance )
{
//The point happens before the previous exit point
first_exit_distance = exit_distance;
first_exit = exit_point;
}
}
return line_within_near_far && !( line_outside_range ) && ( intersects_top_bottom || intersects_left_right );
for ( const auto enter_point : enter_intersections )
{
const float enter_distance { signedDistance( line.direction(), enter_point, line.start ) };
if ( last_enter_distance < enter_distance )
{
last_enter_distance = enter_distance;
last_enter = enter_point;
}
}
const float distance_to_exit { signedDistance( line.direction(), first_exit, line.start ) };
const float distance_to_enter { signedDistance( line.direction(), last_enter, line.start ) };
debug::world::drawVector( last_enter, line.direction(), "", glm::vec3( 0.f, 1.f, 0.0f ) );
debug::world::drawVector( first_exit, line.direction(), "", glm::vec3( 1.f, 0.f, 0.0f ) );
return distance_to_exit >= distance_to_enter;
}
template <>
@@ -49,6 +117,7 @@ namespace fgl::engine
//Slow check for checking lines
for ( const auto line : box.lines() )
{
//intersects( line );
if ( intersects( line ) ) return true;
}

View File

@@ -5,6 +5,7 @@
#pragma once
#include "Coordinate.hpp"
#include "Vector.hpp"
namespace fgl::engine
{
@@ -14,7 +15,13 @@ namespace fgl::engine
Coordinate< CType > start;
Coordinate< CType > end;
Vector direction() const { return Vector( static_cast< glm::vec3 >( end - start ) ); }
Line( const Coordinate< CType > start, const Coordinate< CType > end ) : start( start ), end( end ) {}
Line( const glm::vec3 start, glm::vec3 end ) : start( start ), end( end ) {}
inline Line< CType > flip() const { return { end, start }; }
};
} // namespace fgl::engine

View File

@@ -4,13 +4,17 @@
#include "Plane.hpp"
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/intersect.hpp>
#include <glm/gtx/vector_angle.hpp>
#include "Line.hpp"
namespace fgl::engine
{
template <>
double Plane< CoordinateSpace::World >::distanceFrom( const WorldCoordinate coord ) const
float Plane< CoordinateSpace::World >::distanceFrom( const WorldCoordinate coord ) const
{
return glm::dot( m_direction, coord ) - m_distance;
}
@@ -18,7 +22,29 @@ namespace fgl::engine
template <>
bool OriginDistancePlane< CoordinateSpace::World >::intersects( const Line< CoordinateSpace::World > line ) const
{
return isBehind( line.start ) != isBehind( line.end );
return isForward( line.start ) != isForward( line.end );
}
template <>
Coordinate< CoordinateSpace::World > OriginDistancePlane<
CoordinateSpace::World >::intersection( const Line< CoordinateSpace::World > line ) const
{
const WorldCoordinate line_start { line.start };
const Vector direction { line.direction() };
const float line_dot { glm::dot( this->direction(), line_start ) };
const float direction_dot { glm::dot( this->direction(), direction ) };
// if the dot product of the direction of the plane and the direction of the line is zero, Then there will never be an intersection
if ( direction_dot <= std::numeric_limits< float >::epsilon()
&& direction_dot >= -std::numeric_limits< float >::epsilon() )
return { WorldCoordinate( std::numeric_limits< float >::quiet_NaN() ) };
const float t { -( line_dot - this->distance() ) / direction_dot };
const WorldCoordinate intersection_point { line.start + ( t * direction ) };
return intersection_point;
}
} // namespace fgl::engine

View File

@@ -44,7 +44,7 @@ namespace fgl::engine
Coordinate< CType > getPosition() const { return Coordinate< CType >( 0.0f ) + ( m_direction * m_distance ); }
//! Returns the distance from a point to the plane. Negative if behind, positive if in front
double distanceFrom( const WorldCoordinate coord ) const;
float distanceFrom( const WorldCoordinate coord ) const;
bool isForward( const WorldCoordinate coord ) const { return distanceFrom( coord ) > 0.0; }
@@ -61,8 +61,20 @@ namespace fgl::engine
}
bool intersects( const Line< CType > line ) const;
Coordinate< CType > intersection( const Line< CType > line ) const;
Coordinate< CType > mapToPlane( const Coordinate< CType > point ) const;
};
template < CoordinateSpace CType >
Coordinate< CType > OriginDistancePlane< CType >::mapToPlane( const Coordinate< CType > point ) const
{
const float distance { distanceFrom( point ) };
return point - ( this->m_direction * distance );
}
template < CoordinateSpace CType >
inline std::ostream& operator<<( std::ostream& os, const OriginDistancePlane< CType > plane )
{

View File

@@ -75,7 +75,7 @@ namespace glm
inline glm::vec3 cross( const fgl::engine::Vector vec, const glm::vec3 other )
{
return glm::cross( static_cast< glm::vec3 >( vec ), other );
return ::glm::cross( static_cast< glm::vec3 >( vec ), other );
}
template < CoordinateSpace CType >
@@ -84,4 +84,9 @@ namespace glm
return Coordinate< CType >( static_cast< glm::vec3 >( lhs ) + static_cast< glm::vec3 >( rhs ) );
}
inline float dot( const fgl::engine::Vector a, const fgl::engine::Vector b )
{
return ::glm::dot( static_cast< glm::vec3 >( a ), static_cast< glm::vec3 >( b ) );
}
} // namespace glm

View File

@@ -36,7 +36,7 @@ namespace fgl::engine
if ( obj.is_visible )
{
//Draw the bounding box for debug
debug::world::drawBoundingBox( model_bounding_box, info.camera );
debug::world::drawBoundingBox( model_bounding_box );
}
}
}

View File

@@ -4,6 +4,8 @@
#pragma once
#include <thread>
#include "engine/FrameInfo.hpp"
namespace fgl::engine

View File

@@ -90,6 +90,8 @@ namespace fgl::engine
std::set< DrawPair > draw_pairs;
std::uint64_t tri_counter { 0 };
for ( auto& [ key, obj ] : info.game_objects )
{
if ( obj.model == nullptr ) continue;
@@ -98,6 +100,8 @@ namespace fgl::engine
for ( const auto& primitive : obj.model->m_primitives )
{
tri_counter += ( primitive.m_index_buffer.count() / 3 );
const ModelMatrixInfo matrix_info { .model_matrix = obj.transform.mat4(),
.texture_idx = primitive.m_texture->getID() };
//.normal_matrix = obj.transform.normalMatrix() };
@@ -131,6 +135,8 @@ namespace fgl::engine
}
}
ImGui::Text( "Tris: %lu", tri_counter );
if ( draw_pairs.empty() )
{
std::cout << "Nothing to draw!" << std::endl;

View File

@@ -6,6 +6,9 @@
#include <vulkan/vulkan.hpp>
#include <cstdint>
#include <memory>
namespace fgl::engine
{
class ImageView;

View File

@@ -0,0 +1,15 @@
//
// Created by kj16609 on 2/25/24.
//
#pragma once
#include "constants.hpp"
namespace fgl::engine::uconstants
{
//! How fast an object falls with zero air resistance per second
constexpr float EARTH_GRAVITY { 9.80665f };
} // namespace fgl::engine::uconstants

View File

@@ -8,465 +8,32 @@
#define EXPOSE_CAMERA_INTERNAL
#include "engine/Camera.hpp"
#include "engine/model/BoundingBox.hpp"
#include "engine/primitives/Frustum.hpp"
#include "gtest_printers.hpp"
using namespace fgl::engine;
TEST_CASE( "Planes", "[frustum][rotation][translation]" )
{
WHEN( "Given a default constructed Plane" )
{
Plane< CoordinateSpace::World > plane {};
THEN( "Distance should be DEFAULT_FLOAT" )
{
REQUIRE( plane.distance() == constants::DEFAULT_FLOAT );
}
THEN( "Direction should be WORLD_FORWARD" )
{
REQUIRE( plane.direction() == constants::WORLD_FORWARD );
}
THEN( "Position should be Y+ infinity" )
{
REQUIRE( plane.getPosition() == constants::DEFAULT_VEC3 * constants::WORLD_FORWARD );
}
}
GIVEN( "A Plane pointing at WORLD_FORWARD with a distance of 0.5" )
{
const Plane< CoordinateSpace::Model > plane { constants::WORLD_FORWARD, 0.5f };
TransformComponent component { WorldCoordinate( constants::WORLD_CENTER ),
glm::vec3( 1.0f ),
{ 0.0f, 0.0f, 0.0f } };
WHEN( "Translated forward 1U" )
{
component.translation += constants::WORLD_FORWARD;
const auto translated_plane { component.mat() * plane };
THEN( "The distance should be 0.5 + 1" )
{
REQUIRE( translated_plane.distance() == 0.5f + 1.0f );
}
THEN( "The direction should be WORLD_BACKWARD" )
{
REQUIRE( translated_plane.direction() == constants::WORLD_FORWARD );
}
THEN( "The position should be 0.5U behind the origin" )
{
REQUIRE( translated_plane.getPosition() == constants::WORLD_FORWARD * 1.5f );
}
}
WHEN( "Translated backwards 1U" )
{
component.translation -= constants::WORLD_FORWARD;
const auto translated_plane { component.mat() * plane };
THEN( "The distance should be 0.5 - 1" )
{
REQUIRE( translated_plane.distance() == 0.5f - 1.0f );
}
THEN( "The direction should be WORLD_BACKWARD" )
{
REQUIRE( translated_plane.direction() == constants::WORLD_FORWARD );
}
THEN( "The position should be 0.5U behind the origin" )
{
REQUIRE( translated_plane.getPosition() == constants::WORLD_FORWARD * -0.5f );
}
}
WHEN( "Rotated +90 Yaw" )
{
component.translation = constants::WORLD_CENTER;
component.rotation.yaw() += glm::radians( 90.0f );
THEN( "Distance should not change" )
{
REQUIRE( ( component.mat() * plane ).distance() == plane.distance() );
}
THEN( "Direction should be WORLD_RIGHT" )
{
REQUIRE( ( component.mat() * plane ).direction() == constants::WORLD_RIGHT );
}
}
WHEN( "Rotated +90 Yaw and translated 1U Right" )
{
component.translation += constants::WORLD_RIGHT;
component.rotation.yaw() += glm::radians( 90.0f );
const auto matrix { component.mat() };
const auto translated_plane { matrix * plane };
THEN( "new_direction should be WORLD_RIGHT" )
{
REQUIRE( matrix * plane.direction() == constants::WORLD_RIGHT );
}
REQUIRE( static_cast< glm::vec3 >( matrix * plane.getPosition() ) == constants::WORLD_RIGHT * 1.5f );
THEN( "The distance should be 0.5 + 1" )
{
REQUIRE( translated_plane.distance() == 0.5f + 1.0f );
}
THEN( "The direction should be WORLD_RIGHT" )
{
REQUIRE( translated_plane.direction() == constants::WORLD_RIGHT );
}
THEN( "The position should be 0.5U behind the origin" )
{
REQUIRE( translated_plane.getPosition() == constants::WORLD_RIGHT * 1.5f );
}
}
}
}
constexpr int height { 1080 };
constexpr int width { 1920 };
constexpr float ASPECT_RATIO { static_cast< float >( width ) / static_cast< float >( height ) };
TEST_CASE( "Frustum", "[frustum][rotation][translation]" )
{
Camera camera;
Camera camera {};
camera.setPerspectiveProjection( 90.0f, ASPECT_RATIO, constants::NEAR_PLANE, constants::FAR_PLANE );
const auto base_frustum { camera.getBaseFrustum() };
GIVEN( "A default camera with a 90 deg fov and a 1920/1080 aspect ratio." )
GIVEN( "A default frustum from a default camera" )
{
const auto frustum { camera.getFrustumBounds() };
THEN( "The near plane should be facing WORLD_FORWARD" )
const auto base_frustum { camera.getBaseFrustum() };
THEN( "The near plane should have a distance of constants::NEAR_PLANE" )
{
REQUIRE( frustum.near.direction() == constants::WORLD_FORWARD );
REQUIRE( frustum.near.distance() == constants::NEAR_PLANE );
REQUIRE( base_frustum.near.distance() == constants::NEAR_PLANE );
}
THEN( "The far plane should be facing WORLD_BACKWARD" )
THEN( "The far plane should have a distance of -constants::FAR_PLANE" )
{
REQUIRE( frustum.far.direction() == constants::WORLD_BACKWARD );
REQUIRE( frustum.far.distance() == -constants::FAR_PLANE );
}
}
WHEN( "Camera is translated backwards" )
{
camera.setView( constants::WORLD_BACKWARD, Rotation( 0.0f, 0.0f, 0.0f ) );
//Translate backwards by 1 world unit
const auto translated_backwards { camera.getFrustumBounds() };
//Verify that during a translation the direction isn't changed
THEN( "Direction is the same" )
{
REQUIRE( translated_backwards.near.direction() == base_frustum.near.direction() );
}
const auto matrix { camera.frustumTranslationMatrix() };
const auto plane { camera.getBaseFrustum().near };
const Vector new_direction { glm::normalize( matrix * plane.direction() ) };
const glm::vec3 new_center { matrix * plane.getPosition() };
const float new_distance { glm::dot( new_center, static_cast< glm::vec3 >( new_direction ) ) };
CAPTURE( plane.direction() );
CAPTURE( new_direction );
CAPTURE( plane.getPosition() );
CAPTURE( new_center );
CAPTURE( new_distance );
REQUIRE( new_distance != constants::NEAR_PLANE );
THEN( "The near plane distance should be 1U less" )
{
REQUIRE( translated_backwards.near.distance() == constants::NEAR_PLANE - 1.0f );
}
THEN( "The far plane should be translated backwards" )
{
const glm::vec3 target_far { ( constants::WORLD_FORWARD * constants::FAR_PLANE )
- constants::WORLD_FORWARD };
REQUIRE( translated_backwards.far.getPosition() == target_far );
REQUIRE( translated_backwards.far.direction() == constants::WORLD_BACKWARD );
REQUIRE( translated_backwards.far.distance() == -( constants::FAR_PLANE - 1.0f ) );
// The distance for the far plane should be negative. Due to the fact
// that it is pointing toward the origin, So in order for the center to be positive
// the distance must also be negative
}
}
WHEN( "Translated Forward" )
{
camera.setView( constants::WORLD_CENTER + constants::WORLD_FORWARD, Rotation( 0.0f, 0.0f, 0.0f ) );
//Translate forward by 1 world unit
const auto translated_forward { camera.getFrustumBounds() };
THEN( "Direction is the same" )
{
//Verify that during a translation the direction isn't changed
REQUIRE( translated_forward.near.direction() == base_frustum.near.direction() );
}
THEN( "The near plane should be translated backwards" )
{
REQUIRE( translated_forward.near.direction() == constants::WORLD_FORWARD );
REQUIRE( translated_forward.near.distance() == constants::NEAR_PLANE + 1.0f );
REQUIRE(
translated_forward.near.getPosition()
== ( constants::WORLD_FORWARD * ( constants::NEAR_PLANE + 1.0f ) ) );
}
THEN( "The far plane should be translated backwards" )
{
REQUIRE( translated_forward.far.direction() == constants::WORLD_BACKWARD );
REQUIRE( translated_forward.far.distance() == -( constants::FAR_PLANE + 1.0f ) );
REQUIRE(
translated_forward.far.getPosition()
== ( constants::WORLD_FORWARD * ( constants::FAR_PLANE + 1.0f ) ) );
}
}
WHEN( "Translated Up" )
{
camera.setView( constants::WORLD_CENTER + constants::WORLD_UP, Rotation( 0.0f, 0.0f, 0.0f ) );
//Translate up by 1 world unit
const auto translated_up { camera.getFrustumBounds() };
THEN( "Direction is the same" )
{
//Verify that during a translation the direction isn't changed
REQUIRE( translated_up.near.direction() == base_frustum.near.direction() );
}
REQUIRE( translated_up.near.direction() == constants::WORLD_FORWARD );
REQUIRE( translated_up.near.distance() == constants::NEAR_PLANE );
REQUIRE( translated_up.far.direction() == constants::WORLD_BACKWARD );
REQUIRE( translated_up.far.distance() == -constants::FAR_PLANE );
}
const Frustum< fgl::engine::CoordinateSpace::World > frustum { Matrix< MatrixType::ModelToWorld > { 1.0f }
* camera.getBaseFrustum() };
WHEN( "A point is above the frustum" )
{
const WorldCoordinate far_up { constants::WORLD_UP * 1000.0f };
THEN( "The point should be outside the frustum" )
{
REQUIRE_FALSE( frustum.pointInside( far_up ) );
}
THEN( "The point should be infront of the bottom plane" )
{
REQUIRE( frustum.bottom.distanceFrom( far_up ) > 500.0f );
}
THEN( "The point should be behind the top plane" )
{
REQUIRE( frustum.top.distanceFrom( far_up ) < -500.0f );
}
}
WHEN( "A point is below the frustum" )
{
const WorldCoordinate far_down { constants::WORLD_DOWN * 1000.0f };
THEN( "The point should be outside the frustum" )
{
REQUIRE_FALSE( frustum.pointInside( far_down ) );
}
THEN( "The point should be infront of the top plane" )
{
REQUIRE( frustum.top.distanceFrom( far_down ) > 500.0f );
}
THEN( "The point should be behind the bottom plane" )
{
REQUIRE( frustum.bottom.distanceFrom( far_down ) < -500.0f );
}
}
//The point FORWARD should be in the frustum
WHEN( "A point infront of the frustum" )
{
GIVEN( "A distance of 2 units" )
{
const WorldCoordinate point { constants::WORLD_FORWARD * 2.0f };
THEN( "The point should be inside the frustum" )
{
REQUIRE( frustum.pointInside( point ) );
}
}
GIVEN( "A distance of 500 units" )
{
const WorldCoordinate point { constants::WORLD_FORWARD * 500.0f };
THEN( "The point should be behind the far plane" )
{
CAPTURE( frustum.far.distanceFrom( point ) );
REQUIRE( frustum.far.distanceFrom( point ) < 0.0f );
REQUIRE_FALSE( frustum.far.isForward( point ) );
}
THEN( "The point should be outside the frustum" )
{
REQUIRE_FALSE( frustum.pointInside( point ) );
}
}
}
//A point FORWARD and 0.2 units to the left should be farther from the right plane
GIVEN( "A point FORWARD and 0.2 units to the left" )
{
const WorldCoordinate point { ( constants::WORLD_FORWARD * 2.0f ) + constants::WORLD_LEFT * 0.2f };
THEN( "The point should be farther from the right plane" )
{
REQUIRE( frustum.right.distanceFrom( point ) > frustum.left.distanceFrom( point ) );
}
THEN( "The point should be in the frustum" )
{
REQUIRE( frustum.pointInside( point ) );
}
}
//A point FORWARD and 0.2 units to the right should be farther from the left plane
GIVEN( "A point FORWARD and 0.2 units to the right" )
{
const WorldCoordinate point { ( constants::WORLD_FORWARD * 2.0f ) + constants::WORLD_RIGHT * 0.2f };
THEN( "The point should be farther from the left plane" )
{
REQUIRE( frustum.left.distanceFrom( point ) > frustum.right.distanceFrom( point ) );
}
THEN( "The point should be in the frustum" )
{
REQUIRE( frustum.pointInside( point ) );
}
}
//A point FORWARD and down 0.2 units should be closer to the bottom plane
GIVEN( "A point FORWARD and down 0.2 units" )
{
const WorldCoordinate point { ( constants::WORLD_FORWARD * 2.0f ) + ( constants::WORLD_DOWN * 0.2f ) };
THEN( "The point should be closer to the bottom plane" )
{
REQUIRE( frustum.bottom.distanceFrom( point ) < frustum.top.distanceFrom( point ) );
}
THEN( "The point should be in the frustum" )
{
REQUIRE( frustum.pointInside( point ) );
}
}
SECTION( "Rotations" )
{
//Testing rotation of the camera
SECTION( "Pitch" )
{
Rotation rotation { 0.0f, 0.0f, 0.0f };
rotation.pitch() -= glm::radians( 90.0f );
camera.setView( constants::CENTER, rotation );
const auto rotated_frustum = camera.getFrustumBounds();
//The point DOWN should be in the frustum
const WorldCoordinate point { constants::WORLD_DOWN * 2.0f };
//NEAR should be looking down or approaching
//FAR should be looking up or away
REQUIRE( rotated_frustum.near.direction() == constants::WORLD_DOWN );
REQUIRE( rotated_frustum.far.direction() == constants::WORLD_UP );
REQUIRE( rotated_frustum.near.distanceFrom( point ) > 0.0f );
REQUIRE( rotated_frustum.far.distanceFrom( point ) > 0.0f );
REQUIRE( rotated_frustum.top.distanceFrom( point ) > 0.0f );
REQUIRE( rotated_frustum.bottom.distanceFrom( point ) > 0.0f );
REQUIRE( rotated_frustum.right.distanceFrom( point ) > 0.0f );
REQUIRE( rotated_frustum.left.distanceFrom( point ) > 0.0f );
REQUIRE( rotated_frustum.pointInside( point ) );
}
SECTION( "Yaw" )
{
Rotation rotation { 0.0f, 0.0f, 0.0f };
rotation.yaw() += glm::radians( 90.0f );
camera.setView( constants::CENTER, rotation );
const auto rotated_frustum = camera.getFrustumBounds();
//The point RIGHT should be in the frustum
const WorldCoordinate point { constants::WORLD_RIGHT * 2.0f };
//NEAR should be looking right or approaching
//FAR should be looking left or away
//Precision issues. So I can't write the tests yet
REQUIRE( rotated_frustum.near.distanceFrom( point ) > 0.0f );
REQUIRE( rotated_frustum.far.distanceFrom( point ) > 0.0f );
REQUIRE( rotated_frustum.top.distanceFrom( point ) > 0.0f );
REQUIRE( rotated_frustum.bottom.distanceFrom( point ) > 0.0f );
REQUIRE( rotated_frustum.right.distanceFrom( point ) > 0.0f );
REQUIRE( rotated_frustum.left.distanceFrom( point ) > 0.0f );
REQUIRE( rotated_frustum.pointInside( point ) );
//LEFT should be behind, Thus out outside
REQUIRE_FALSE( rotated_frustum.pointInside( WorldCoordinate( constants::WORLD_LEFT ) ) );
}
SECTION( "Roll" )
{
Rotation rotation { 0.0f, 0.0f, 0.0f };
rotation.roll() -= glm::radians( 90.0f );
camera.setView( constants::CENTER, rotation );
const auto rotated_frustum = camera.getFrustumBounds();
//The point FORWARD should be in the frustum
const WorldCoordinate point { constants::WORLD_FORWARD * 2.0f };
REQUIRE( rotated_frustum.near.distanceFrom( point ) > 0.0f );
REQUIRE( rotated_frustum.far.distanceFrom( point ) > 0.0f );
REQUIRE( rotated_frustum.top.distanceFrom( point ) > 0.0f );
REQUIRE( rotated_frustum.bottom.distanceFrom( point ) > 0.0f );
REQUIRE( rotated_frustum.right.distanceFrom( point ) > 0.0f );
REQUIRE( rotated_frustum.left.distanceFrom( point ) > 0.0f );
REQUIRE( rotated_frustum.pointInside( point ) );
REQUIRE( base_frustum.far.distance() == -constants::FAR_PLANE );
}
}
}

208
tests/src/PlaneTests.cpp Normal file
View File

@@ -0,0 +1,208 @@
//
// Created by kj16609 on 2/25/24.
//
#include <catch2/catch_all.hpp>
#include <iostream>
#define EXPOSE_CAMERA_INTERNAL
#include "engine/Camera.hpp"
#include "engine/primitives/Frustum.hpp"
#include "gtest_printers.hpp"
using namespace fgl::engine;
TEST_CASE( "Planes", "[frustum][rotation][translation]" )
{
WHEN( "Given a default constructed Plane" )
{
Plane< CoordinateSpace::World > plane {};
THEN( "Distance should be DEFAULT_FLOAT" )
{
REQUIRE( plane.distance() == constants::DEFAULT_FLOAT );
}
THEN( "Direction should be WORLD_FORWARD" )
{
REQUIRE( plane.direction() == constants::WORLD_FORWARD );
}
THEN( "Position should be Y+ infinity" )
{
REQUIRE( plane.getPosition() == constants::DEFAULT_VEC3 * constants::WORLD_FORWARD );
}
}
GIVEN( "A Plane pointing at WORLD_FORWARD with a distance of 0.5" )
{
const Plane< CoordinateSpace::Model > plane { constants::WORLD_FORWARD, 0.5f };
TransformComponent component { WorldCoordinate( constants::WORLD_CENTER ),
glm::vec3( 1.0f ),
{ 0.0f, 0.0f, 0.0f } };
WHEN( "Translated forward 1U" )
{
component.translation += constants::WORLD_FORWARD;
const auto translated_plane { component.mat() * plane };
THEN( "The distance should be 0.5 + 1" )
{
REQUIRE( translated_plane.distance() == 0.5f + 1.0f );
}
THEN( "The direction should be WORLD_BACKWARD" )
{
REQUIRE( translated_plane.direction() == constants::WORLD_FORWARD );
}
THEN( "The position should be 0.5U behind the origin" )
{
REQUIRE( translated_plane.getPosition() == constants::WORLD_FORWARD * 1.5f );
}
}
WHEN( "Translated backwards 1U" )
{
component.translation -= constants::WORLD_FORWARD;
const auto translated_plane { component.mat() * plane };
THEN( "The distance should be 0.5 - 1" )
{
REQUIRE( translated_plane.distance() == 0.5f - 1.0f );
}
THEN( "The direction should be WORLD_BACKWARD" )
{
REQUIRE( translated_plane.direction() == constants::WORLD_FORWARD );
}
THEN( "The position should be 0.5U behind the origin" )
{
REQUIRE( translated_plane.getPosition() == constants::WORLD_FORWARD * -0.5f );
}
}
WHEN( "Rotated +90 Yaw" )
{
component.translation = constants::WORLD_CENTER;
component.rotation.yaw() += glm::radians( 90.0f );
THEN( "Distance should not change" )
{
REQUIRE( ( component.mat() * plane ).distance() == plane.distance() );
}
THEN( "Direction should be WORLD_RIGHT" )
{
REQUIRE( ( component.mat() * plane ).direction() == constants::WORLD_RIGHT );
}
}
WHEN( "Rotated +90 Yaw and translated 1U Right" )
{
component.translation += constants::WORLD_RIGHT;
component.rotation.yaw() += glm::radians( 90.0f );
const auto matrix { component.mat() };
const auto translated_plane { matrix * plane };
THEN( "new_direction should be WORLD_RIGHT" )
{
REQUIRE( matrix * plane.direction() == constants::WORLD_RIGHT );
}
REQUIRE( static_cast< glm::vec3 >( matrix * plane.getPosition() ) == constants::WORLD_RIGHT * 1.5f );
THEN( "The distance should be 0.5 + 1" )
{
REQUIRE( translated_plane.distance() == 0.5f + 1.0f );
}
THEN( "The direction should be WORLD_RIGHT" )
{
REQUIRE( translated_plane.direction() == constants::WORLD_RIGHT );
}
THEN( "The position should be 0.5U behind the origin" )
{
REQUIRE( translated_plane.getPosition() == constants::WORLD_RIGHT * 1.5f );
}
}
}
}
TEST_CASE( "Plane intersections", "[frustum][intersection]" )
{
GIVEN( "A line going from -1 to 1 (X,Y and Z)" )
{
const Line< CoordinateSpace::World > line { glm::vec3( -1 ), glm::vec3( 1 ) };
AND_GIVEN( "A plane facing toward line.start" )
{
const Plane< CoordinateSpace::World > plane { glm::normalize( line.start ), 0.0f };
THEN( "The line should intersect" )
{
REQUIRE( plane.intersects( line ) );
AND_THEN( "The line intersection should be at origin" )
{
REQUIRE( plane.intersection( line ) == glm::vec3( 0.0f ) );
}
}
THEN( "The line should intersect going the opposite way" )
{
REQUIRE( plane.intersects( line.flip() ) );
AND_THEN( "The line intersection should be at origin" )
{
REQUIRE( plane.intersection( line ) == glm::vec3( 0.0f ) );
}
}
}
}
GIVEN( "A line going from WORLD_LEFT - WORLD_FRONT * 20.0 to WORLD_LEFT + WORLD_FRONT * 20.0f" )
{
const Line< CoordinateSpace::World > line { constants::WORLD_LEFT - ( constants::WORLD_FORWARD * 20.0f ),
constants::WORLD_LEFT + ( constants::WORLD_FORWARD * 20.0f ) };
AND_GIVEN( "A plane facing toward WORLD_FORWARD at distance -2.0f" )
{
const Plane< CoordinateSpace::World > plane { constants::WORLD_FORWARD, -2.0f };
THEN( "The plane should intersect the line" )
{
REQUIRE( plane.intersects( line ) );
}
THEN( "The intersection point should be WORLD_LEFT - (constants::WORLD_FORWARD * 2.0f)" )
{
REQUIRE( plane.intersection( line ) == constants::WORLD_LEFT - ( constants::WORLD_FORWARD * 2.0f ) );
}
}
}
GIVEN( "A line going from WORLD_UP to WORLD_DOWN" )
{
const Line< fgl::engine::CoordinateSpace::World > line { constants::WORLD_UP * 5.0f - constants::WORLD_BACKWARD,
constants::WORLD_DOWN * 5.0f
- constants::WORLD_BACKWARD };
AND_GIVEN( "A plane facing UP + FORWARD" )
{
const Plane< fgl::engine::CoordinateSpace::World > plane { constants::WORLD_FORWARD + constants::WORLD_UP,
0.0f };
THEN( "The plane should intersect the line" )
{
REQUIRE( plane.intersects( line ) );
}
}
}
}