Gets frustum culling via line intersection mostly working
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "Device.hpp"
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
|
||||
#include "KeyboardMovementController.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
|
||||
#include "engine/primitives/Vector.hpp"
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <unordered_map>
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace fgl::engine
|
||||
{
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 } );
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <glm/mat4x4.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 )
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include "engine/FrameInfo.hpp"
|
||||
|
||||
namespace fgl::engine
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
namespace fgl::engine
|
||||
{
|
||||
class ImageView;
|
||||
|
||||
15
src/engine/universe_constants.hpp
Normal file
15
src/engine/universe_constants.hpp
Normal 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
|
||||
@@ -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
208
tests/src/PlaneTests.cpp
Normal 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 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user