diff --git a/CMakeLists.txt b/CMakeLists.txt index ac813f2..243099e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ # /CMakeLists.txt -cmake_minimum_required(VERSION 3.26.4) +cmake_minimum_required(VERSION 3.25.0) project(Game LANGUAGES CXX C) set(APP_ICON_RESOURCE_WINDOWS "${CMAKE_CURRENT_SOURCE_DIR}/appicon.rc") diff --git a/cmake_modules/common.cmake b/cmake_modules/common.cmake index 12af1d8..b71f1da 100644 --- a/cmake_modules/common.cmake +++ b/cmake_modules/common.cmake @@ -13,8 +13,16 @@ if ((${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") OR (${CMAKE_CXX_PLATFORM_ID} STREQ elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") include(clang) elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") - message() include(msvc) +else () + message(WARNING "Unknown Compiler") + #Define dummy PreCompilerSetup for unknown compilers. Later on, this will be replaced by a proper error message + function(PreCompilerSetup) + message(WARNING "Unknown Compiler! Dummy PreCompilerSetup") + endfunction() + function(PostCompilerSetup) + message(WARNING "Unknown Compiler! Dummy PostCompilerSetup") + endfunction() endif () if ((WIN32)) diff --git a/src/engine/Camera.cpp b/src/engine/Camera.cpp index e305fe6..51fd8d2 100644 --- a/src/engine/Camera.cpp +++ b/src/engine/Camera.cpp @@ -12,6 +12,7 @@ namespace fgl::engine void Camera::setOrthographicProjection( float left, float right, float top, float bottom, float near, float far ) { + ZoneScoped; projection_matrix = glm::mat4 { 1.0f }; projection_matrix[ 0 ][ 0 ] = 2.0f / ( right - left ); projection_matrix[ 1 ][ 1 ] = 2.0f / ( bottom - top ); @@ -19,10 +20,13 @@ namespace fgl::engine projection_matrix[ 3 ][ 0 ] = -( right + left ) / ( right - left ); projection_matrix[ 3 ][ 1 ] = -( bottom + top ) / ( bottom - top ); projection_matrix[ 3 ][ 2 ] = -near / ( far - near ); + + //TODO: Figure out frustum culling for orthographic projection. (If we even wanna use it) } void Camera::setPerspectiveProjection( float fovy, float aspect, float near, float far ) { + ZoneScoped; assert( glm::abs( aspect - std::numeric_limits< float >::epsilon() ) > 0 ); const float tan_half_fovy { std::tan( fovy / 2.0f ) }; projection_matrix = glm::mat4 { 0.0f }; @@ -31,50 +35,57 @@ namespace fgl::engine projection_matrix[ 2 ][ 2 ] = far / ( far - near ); projection_matrix[ 2 ][ 3 ] = 1.0f; projection_matrix[ 3 ][ 2 ] = -( far * near ) / ( far - near ); + + base_frustum = createFrustum( *this, aspect, fovy, near, far ); } void Camera::setViewDirection( glm::vec3 position, glm::vec3 direction, glm::vec3 up ) { - const glm::vec3 w { glm::normalize( direction ) }; - const glm::vec3 u { glm::normalize( glm::cross( w, up ) ) }; - const glm::vec3 v { glm::cross( w, u ) }; + ZoneScoped; + const glm::vec3 w_direction { glm::normalize( direction ) }; + const glm::vec3 u_right { glm::normalize( glm::cross( w_direction, up ) ) }; + const glm::vec3 v_up { glm::cross( w_direction, u_right ) }; + + /* + * view_matrix + * u_r = view_right + * v_u = view_up + * w_d = view_direction + * + * | u_r.x u_r.y u_r.z 0 | + * | v_u.x v_u.y v_u.z 0 | + * | w_d.x w_d.y w_d.z 0 | + * | 0 0 0 1 | + */ view_matrix = glm::mat4 { 1.0f }; - view_matrix[ 0 ][ 0 ] = u.x; - view_matrix[ 1 ][ 0 ] = u.y; - view_matrix[ 2 ][ 0 ] = u.z; - view_matrix[ 0 ][ 1 ] = v.x; - view_matrix[ 1 ][ 1 ] = v.y; - view_matrix[ 2 ][ 1 ] = v.z; - view_matrix[ 0 ][ 2 ] = w.x; - view_matrix[ 1 ][ 2 ] = w.y; - view_matrix[ 2 ][ 2 ] = w.z; - view_matrix[ 3 ][ 0 ] = -glm::dot( u, position ); - view_matrix[ 3 ][ 1 ] = -glm::dot( v, position ); - view_matrix[ 3 ][ 2 ] = -glm::dot( w, position ); + view_matrix[ 0 ][ 0 ] = u_right.x; + view_matrix[ 1 ][ 0 ] = u_right.y; + view_matrix[ 2 ][ 0 ] = u_right.z; - inverse_view_matrix = glm::mat4 { 1.0f }; - inverse_view_matrix[ 0 ][ 0 ] = u.x; - inverse_view_matrix[ 0 ][ 1 ] = u.y; - inverse_view_matrix[ 0 ][ 2 ] = u.z; - inverse_view_matrix[ 1 ][ 0 ] = v.x; - inverse_view_matrix[ 1 ][ 1 ] = v.y; - inverse_view_matrix[ 1 ][ 2 ] = v.z; - inverse_view_matrix[ 2 ][ 0 ] = w.x; - inverse_view_matrix[ 2 ][ 1 ] = w.y; - inverse_view_matrix[ 2 ][ 2 ] = w.z; - inverse_view_matrix[ 3 ][ 0 ] = position.x; - inverse_view_matrix[ 3 ][ 1 ] = position.y; - inverse_view_matrix[ 3 ][ 2 ] = position.z; + view_matrix[ 0 ][ 1 ] = v_up.x; + view_matrix[ 1 ][ 1 ] = v_up.y; + view_matrix[ 2 ][ 1 ] = v_up.z; + + view_matrix[ 0 ][ 2 ] = w_direction.x; + view_matrix[ 1 ][ 2 ] = w_direction.y; + view_matrix[ 2 ][ 2 ] = w_direction.z; + + view_matrix[ 3 ][ 0 ] = -glm::dot( u_right, position ); + view_matrix[ 3 ][ 1 ] = -glm::dot( v_up, position ); + view_matrix[ 3 ][ 2 ] = -glm::dot( w_direction, position ); + + frustum = base_frustum * view_matrix; } void Camera::setViewTarget( glm::vec3 position, glm::vec3 target, glm::vec3 up ) { - setViewDirection( position, target - position, up ); + setViewDirection( position, glm::normalize( target - position ), up ); } void Camera::setViewYXZ( glm::vec3 position, glm::vec3 rotation ) { + ZoneScoped; const float c3 { glm::cos( rotation.z ) }; const float s3 { glm::sin( rotation.z ) }; const float c2 { glm::cos( rotation.x ) }; @@ -84,33 +95,52 @@ namespace fgl::engine const glm::vec3 u { ( c1 * c3 + s1 * s2 * s3 ), ( c2 * s3 ), ( c1 * s2 * s3 - c3 * s1 ) }; const glm::vec3 v { ( c3 * s1 * s2 - c1 * s3 ), ( c2 * c3 ), ( c1 * c3 * s2 + s1 * s3 ) }; const glm::vec3 w { ( c2 * s1 ), ( -s2 ), ( c1 * c2 ) }; + view_matrix = glm::mat4 { 1.0f }; view_matrix[ 0 ][ 0 ] = u.x; view_matrix[ 1 ][ 0 ] = u.y; view_matrix[ 2 ][ 0 ] = u.z; + view_matrix[ 0 ][ 1 ] = v.x; view_matrix[ 1 ][ 1 ] = v.y; view_matrix[ 2 ][ 1 ] = v.z; + view_matrix[ 0 ][ 2 ] = w.x; view_matrix[ 1 ][ 2 ] = w.y; view_matrix[ 2 ][ 2 ] = w.z; + view_matrix[ 3 ][ 0 ] = -glm::dot( u, position ); view_matrix[ 3 ][ 1 ] = -glm::dot( v, position ); view_matrix[ 3 ][ 2 ] = -glm::dot( w, position ); - inverse_view_matrix = glm::mat4 { 1.0f }; - inverse_view_matrix[ 0 ][ 0 ] = u.x; - inverse_view_matrix[ 0 ][ 1 ] = u.y; - inverse_view_matrix[ 0 ][ 2 ] = u.z; - inverse_view_matrix[ 1 ][ 0 ] = v.x; - inverse_view_matrix[ 1 ][ 1 ] = v.y; - inverse_view_matrix[ 1 ][ 2 ] = v.z; - inverse_view_matrix[ 2 ][ 0 ] = w.x; - inverse_view_matrix[ 2 ][ 1 ] = w.y; - inverse_view_matrix[ 2 ][ 2 ] = w.z; - inverse_view_matrix[ 3 ][ 0 ] = position.x; - inverse_view_matrix[ 3 ][ 1 ] = position.y; - inverse_view_matrix[ 3 ][ 2 ] = position.z; + frustum = base_frustum * view_matrix; + } + + Frustum + createFrustum( const Camera& camera, const float aspect, const float fov_y, const float near, const float far ) + { + Plane near_plane { camera.getForward(), near }; + Plane far_plane { camera.getBackward(), far }; + + const float half_width { near * glm::tan( fov_y / 2.0f ) }; // halfHSide + const float half_height { half_width / aspect }; //halfVSide + + constexpr glm::vec3 ZERO { 0.0f, 0.0f, 0.0f }; + + const auto far_forward { camera.getForward() * far }; + + //top_dir is the direction pointing at the highest point on the far plane + const auto far_up { camera.getUp() * half_height }; + const glm::vec3 top_dir { glm::normalize( far_up + far_forward ) }; + + Plane top_plane { glm::cross( top_dir, camera.getUp() ), 0.0f }; + Plane bottom_plane { glm::cross( top_dir, camera.getDown() ), 0.0f }; + + const glm::vec3 right_dir { glm::normalize( camera.getRight() * half_width + far_forward ) }; + Plane right_plane { glm::cross( right_dir, camera.getRight() ), 0.0f }; + Plane left_plane { glm::cross( right_dir, camera.getLeft() ), 0.0f }; + + return { near_plane, far_plane, top_plane, bottom_plane, right_plane, left_plane }; } } // namespace fgl::engine \ No newline at end of file diff --git a/src/engine/Camera.hpp b/src/engine/Camera.hpp index fa50576..e38479e 100644 --- a/src/engine/Camera.hpp +++ b/src/engine/Camera.hpp @@ -8,29 +8,70 @@ #define GLM_FORCE_DEPTH_ZERO_TO_ONE #include +#include "engine/coordinates/WorldCoordinate.hpp" + namespace fgl::engine { + constexpr static auto WORLD_UP { glm::vec3 { 0.0f, 1.0f, 0.0f } }; + + class Camera; + + Frustum + createFrustum( const Camera& camera, const float aspect, const float fovy, const float near, const float far ); + class Camera { glm::mat4 projection_matrix { 1.0f }; + glm::mat4 view_matrix { 1.0f }; - glm::mat4 inverse_view_matrix { 1.0f }; + + //! Frustum of the camera in model space relative to the camera + //! @note Must be transformed by the inverse view matrix to get the frustum in world space + Frustum base_frustum {}; + Frustum frustum {}; + + friend Frustum createFrustum( + const Camera& camera, const float aspect, const float fovy, const float near, const float far ); public: + //! Returns the frustum of the camera in world space + const Frustum& getFrustumBounds() const { return frustum; } + const glm::mat4& getProjectionMatrix() const { return projection_matrix; } const glm::mat4& getViewMatrix() const { return view_matrix; } - const glm::mat4& getInverseView() const { return inverse_view_matrix; } + const glm::mat4 getProjectionViewMatrix() const { return projection_matrix * view_matrix; } void setOrthographicProjection( float left, float right, float top, float bottom, float near, float far ); void setPerspectiveProjection( float fovy, float aspect, float near, float far ); - const glm::vec3 getPosition() const { return glm::vec3( inverse_view_matrix[ 3 ] ); } + const glm::vec3 getPosition() const { return glm::vec3( -view_matrix[ 3 ] ); } - void setViewDirection( glm::vec3 pos, glm::vec3 direction, glm::vec3 up = glm::vec3 { 0.0f, -1.0f, 0.0f } ); - void setViewTarget( glm::vec3 pos, glm::vec3 target, glm::vec3 up = glm::vec3 { 0.0f, -1.0f, 0.0f } ); + const glm::vec3 getUp() const + { + return glm::normalize( glm::vec3( view_matrix[ 0 ][ 1 ], view_matrix[ 1 ][ 1 ], view_matrix[ 2 ][ 1 ] ) ); + } + + const glm::vec3 getRight() const + { + return glm::normalize( glm::vec3( view_matrix[ 0 ][ 0 ], view_matrix[ 1 ][ 0 ], view_matrix[ 2 ][ 0 ] ) ); + } + + const glm::vec3 getForward() const + { + return glm::normalize( glm::vec3( view_matrix[ 0 ][ 2 ], view_matrix[ 1 ][ 2 ], view_matrix[ 2 ][ 2 ] ) ); + } + + const glm::vec3 getLeft() const { return -getRight(); } + + const glm::vec3 getBackward() const { return -getForward(); } + + const glm::vec3 getDown() const { return -getUp(); } + + void setViewDirection( glm::vec3 pos, glm::vec3 direction, glm::vec3 up = WORLD_UP ); + void setViewTarget( glm::vec3 pos, glm::vec3 target, glm::vec3 up = WORLD_UP ); void setViewYXZ( glm::vec3 pos, glm::vec3 rotation ); }; diff --git a/src/engine/EngineContext.cpp b/src/engine/EngineContext.cpp index 67b43f3..a252d6e 100644 --- a/src/engine/EngineContext.cpp +++ b/src/engine/EngineContext.cpp @@ -27,6 +27,7 @@ #pragma GCC diagnostic ignored "-Weffc++" #pragma GCC diagnostic ignored "-Wold-style-cast" #pragma GCC diagnostic ignored "-Wconversion" +#include "engine/debug/drawers.hpp" #include "imgui/imgui.h" #include "imgui/imgui_impl_glfw.h" #include "imgui/imgui_impl_vulkan.h" @@ -104,6 +105,10 @@ namespace fgl::engine auto previous_frame_start { std::chrono::high_resolution_clock::now() }; + //camera.setOrthographicProjection( -aspect, aspect, -1, 1, -1, 1 ); + const float aspect { m_renderer.getAspectRatio() }; + camera.setPerspectiveProjection( glm::radians( 50.0f ), aspect, 0.1f, 100.f ); + while ( !m_window.shouldClose() ) { ZoneScopedN( "Poll" ); @@ -127,20 +132,25 @@ namespace fgl::engine current_time = new_time; delta_time = glm::min( delta_time, MAX_DELTA_TIME ); +#if ENABLE_IMGUI + { + ImGui_ImplVulkan_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); + } +#endif + camera_controller.moveInPlaneXZ( m_window.window(), delta_time, viewer ); camera.setViewYXZ( viewer.transform.translation, viewer.transform.rotation ); - const float aspect { m_renderer.getAspectRatio() }; - - //camera.setOrthographicProjection( -aspect, aspect, -1, 1, -1, 1 ); - camera.setPerspectiveProjection( glm::radians( 50.0f ), aspect, 0.1f, 100.f ); - if ( auto command_buffer = m_renderer.beginFrame(); command_buffer ) { ZoneScopedN( "Render" ); //Update const std::uint16_t frame_index { m_renderer.getFrameIndex() }; + const auto view_frustum { camera.getFrustumBounds() }; + FrameInfo frame_info { frame_index, delta_time, command_buffer, @@ -150,177 +160,184 @@ namespace fgl::engine m_renderer.getCurrentTracyCTX(), matrix_info_buffers[ frame_index ], draw_parameter_buffers[ frame_index ], - m_renderer.getGBufferDescriptor( frame_index ) }; + m_renderer.getGBufferDescriptor( frame_index ), + view_frustum }; #if TRACY_ENABLE auto& tracy_ctx { frame_info.tracy_ctx }; #endif CameraInfo current_camera_info { .projection = camera.getProjectionMatrix(), - .view = camera.getViewMatrix(), - .inverse_view = camera.getInverseView() }; + .view = camera.getViewMatrix() }; camera_info[ frame_index ] = current_camera_info; #if ENABLE_IMGUI { ZoneScopedN( "ImGui recording" ); - ImGui_ImplVulkan_NewFrame(); - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); + ImGui::Begin( "Titor Dev Menu" ); + + ImGui::Text( "Framerate" ); + ImGui::SameLine(); + ImGui::Text( "%.1f FPS", ImGui::GetIO().Framerate ); + + ImGui::Text( "Frame Time" ); + ImGui::SameLine(); + ImGui::Text( "%.3f ms", 1000.0f / ImGui::GetIO().Framerate ); + ImGui::Text( "Average rolling frametime: %.3f ms", rolling_ms_average.average() ); + + if ( ImGui::CollapsingHeader( "Camera" ) ) { - ImGui::Begin( "Titor Dev Menu" ); - - ImGui::Text( "Framerate" ); + ImGui::PushItemWidth( 80 ); + ImGui::DragFloat( "Pos X", &viewer.transform.translation.x, 0.1f ); ImGui::SameLine(); - ImGui::Text( "%.1f FPS", ImGui::GetIO().Framerate ); - - ImGui::Text( "Frame Time" ); + ImGui::DragFloat( "Pos Y", &viewer.transform.translation.y, 0.1f ); ImGui::SameLine(); - ImGui::Text( "%.3f ms", 1000.0f / ImGui::GetIO().Framerate ); - ImGui::Text( "Average rolling frametime: %.3f ms", rolling_ms_average.average() ); + ImGui::DragFloat( "Pos Z", &viewer.transform.translation.z, 0.1f ); + ImGui::PopItemWidth(); - if ( ImGui::CollapsingHeader( "Camera" ) ) + ImGui::Separator(); + + ImGui::PushItemWidth( 80 ); + ImGui::DragFloat( "Rot X", &viewer.transform.rotation.x, 0.1f, 0.0f, glm::two_pi< float >() ); + ImGui::SameLine(); + ImGui::DragFloat( "Rot Y", &viewer.transform.rotation.y, 0.1f, 0.0f, glm::two_pi< float >() ); + ImGui::SameLine(); + ImGui::DragFloat( "Rot Z", &viewer.transform.rotation.z, 0.1f, 0.0f, glm::two_pi< float >() ); + ImGui::PopItemWidth(); + } + + if ( ImGui::CollapsingHeader( "View Frustum" ) ) + { + const auto& frustum { camera.getFrustumBounds() }; + + auto printVec3 = []( const glm::vec3& vec ) + { ImGui::Text( "(%.2f, %.2f, %.2f)", vec.x, vec.y, vec.z ); }; + + auto printPlane = [ printVec3 ]( const Plane& plane, const std::string name ) { - ImGui::PushItemWidth( 80 ); - ImGui::DragFloat( "Pos X", &viewer.transform.translation.x, 0.1f ); - ImGui::SameLine(); - ImGui::DragFloat( "Pos Y", &viewer.transform.translation.y, 0.1f ); - ImGui::SameLine(); - ImGui::DragFloat( "Pos Z", &viewer.transform.translation.z, 0.1f ); - ImGui::PopItemWidth(); + const std::string name_str { "Plane " + name + ": " }; - ImGui::Separator(); - - ImGui::PushItemWidth( 80 ); - ImGui:: - DragFloat( "Rot X", &viewer.transform.rotation.x, 0.1f, 0.0f, glm::two_pi< float >() ); + ImGui::Text( name_str.c_str() ); + ImGui::SameLine( 120.0f ); + printVec3( plane.direction() ); ImGui::SameLine(); - ImGui:: - DragFloat( "Rot Y", &viewer.transform.rotation.y, 0.1f, 0.0f, glm::two_pi< float >() ); - ImGui::SameLine(); - ImGui:: - DragFloat( "Rot Z", &viewer.transform.rotation.z, 0.1f, 0.0f, glm::two_pi< float >() ); - ImGui::PopItemWidth(); - } + ImGui::Text( "Distance: %.6f", plane.distance() ); + }; - if ( ImGui::CollapsingHeader( "Models" ) ) + printPlane( frustum.near, "Near" ); + printPlane( frustum.far, "Far" ); + printPlane( frustum.top, "Top" ); + printPlane( frustum.bottom, "Bottom" ); + printPlane( frustum.right, "Right" ); + printPlane( frustum.left, "Left" ); + } + + if ( ImGui::CollapsingHeader( "Models" ) ) + { + for ( auto& [ id, game_object ] : game_objects ) { - for ( auto& [ id, game_object ] : game_objects ) + if ( game_object.model == nullptr ) continue; + + ImGui::PushID( std::to_string( id ).c_str() ); + + if ( ImGui::TreeNode( game_object.model->getName().c_str() ) ) { - if ( game_object.model == nullptr ) continue; - - ImGui::PushID( std::to_string( id ).c_str() ); - - if ( ImGui::TreeNode( game_object.model->getName().c_str() ) ) + ImGui::PushID( game_object.model->getName().c_str() ); { - ImGui::PushID( game_object.model->getName().c_str() ); + ImGui::PushID( "Position" ); + ImGui::PushItemWidth( 80 ); + ImGui::Text( "Position" ); + ImGui::SameLine(); + ImGui::DragFloat( "X", &game_object.transform.translation.x, 0.1f ); + ImGui::SameLine(); + ImGui::DragFloat( "Y", &game_object.transform.translation.y, 0.1f ); + ImGui::SameLine(); + ImGui::DragFloat( "Z", &game_object.transform.translation.z, 0.1f ); + ImGui::PopID(); + } + + ImGui::Separator(); + + { + ImGui::PushID( "Rotation" ); + ImGui::PushItemWidth( 80 ); + ImGui::Text( "Rotation" ); + ImGui::SameLine(); + ImGui::DragFloat( + "X", &game_object.transform.rotation.x, 0.1f, 0.0f, glm::two_pi< float >() ); + ImGui::SameLine(); + ImGui::DragFloat( + "Y", &game_object.transform.rotation.y, 0.1f, 0.0f, glm::two_pi< float >() ); + ImGui::SameLine(); + ImGui::DragFloat( + "Z", &game_object.transform.rotation.z, 0.1f, 0.0f, glm::two_pi< float >() ); + ImGui::PopID(); + } + + ImGui::Separator(); + + { + ImGui::PushID( "Scale" ); + ImGui::PushItemWidth( 80 ); + ImGui::Text( "Scale" ); + ImGui::SameLine(); + ImGui::DragFloat( "X", &game_object.transform.scale.x, 0.1f ); + ImGui::SameLine(); + ImGui::DragFloat( "Y", &game_object.transform.scale.y, 0.1f ); + ImGui::SameLine(); + ImGui::DragFloat( "Z", &game_object.transform.scale.z, 0.1f ); + ImGui::TreePop(); + ImGui::PopID(); + } + + if ( ImGui::CollapsingHeader( "Textures" ) ) + { + std::vector< TextureID > textures; + + ImGui::PushID( "Textures" ); + + for ( auto& primitive : game_object.model->m_primitives ) { - ImGui::PushID( "Position" ); - ImGui::PushItemWidth( 80 ); - ImGui::Text( "Position" ); - ImGui::SameLine(); - ImGui::DragFloat( "X", &game_object.transform.translation.x, 0.1f ); - ImGui::SameLine(); - ImGui::DragFloat( "Y", &game_object.transform.translation.y, 0.1f ); - ImGui::SameLine(); - ImGui::DragFloat( "Z", &game_object.transform.translation.z, 0.1f ); - ImGui::PopID(); - } + if ( !primitive.m_texture.has_value() ) continue; - ImGui::Separator(); + auto& texture { primitive.m_texture.value() }; - { - ImGui::PushID( "Rotation" ); - ImGui::PushItemWidth( 80 ); - ImGui::Text( "Rotation" ); - ImGui::SameLine(); - ImGui::DragFloat( - "X", - &game_object.transform.rotation.x, - 0.1f, - 0.0f, - glm::two_pi< float >() ); - ImGui::SameLine(); - ImGui::DragFloat( - "Y", - &game_object.transform.rotation.y, - 0.1f, - 0.0f, - glm::two_pi< float >() ); - ImGui::SameLine(); - ImGui::DragFloat( - "Z", - &game_object.transform.rotation.z, - 0.1f, - 0.0f, - glm::two_pi< float >() ); - ImGui::PopID(); - } + const auto& extent { texture.getExtent() }; - ImGui::Separator(); + auto& image_view { texture.getImageView() }; + auto& sampler { image_view.getSampler() }; - { - ImGui::PushID( "Scale" ); - ImGui::PushItemWidth( 80 ); - ImGui::Text( "Scale" ); - ImGui::SameLine(); - ImGui::DragFloat( "X", &game_object.transform.scale.x, 0.1f ); - ImGui::SameLine(); - ImGui::DragFloat( "Y", &game_object.transform.scale.y, 0.1f ); - ImGui::SameLine(); - ImGui::DragFloat( "Z", &game_object.transform.scale.z, 0.1f ); - ImGui::TreePop(); - ImGui::PopID(); - } + if ( !sampler.has_value() ) continue; - if ( ImGui::CollapsingHeader( "Textures" ) ) - { - std::vector< TextureID > textures; + ImVec2 size; + size.x = extent.width; + size.y = extent.height; - ImGui::PushID( "Textures" ); - - for ( auto& primitive : game_object.model->m_primitives ) + if ( std::find( textures.begin(), textures.end(), texture.getID() ) + == textures.end() ) { - if ( !primitive.m_texture.has_value() ) continue; + textures.emplace_back( texture.getID() ); - auto& texture { primitive.m_texture.value() }; - - const auto& extent { texture.getExtent() }; - - auto& image_view { texture.getImageView() }; - auto& sampler { image_view.getSampler() }; - - if ( !sampler.has_value() ) continue; - - ImVec2 size; - size.x = extent.width; - size.y = extent.height; - - if ( std::find( textures.begin(), textures.end(), texture.getID() ) - == textures.end() ) - { - textures.emplace_back( texture.getID() ); - - ImGui::Image( - static_cast< ImTextureID >( primitive.m_texture - ->getImGuiDescriptorSet() ), - size ); - } + ImGui::Image( + static_cast< ImTextureID >( primitive.m_texture + ->getImGuiDescriptorSet() ), + size ); } - - ImGui::PopID(); } ImGui::PopID(); } + ImGui::PopID(); } + ImGui::PopID(); } + } - //TODO: Add in a collapsable header to view all buffers, And their suballocations - /* + //TODO: Add in a collapsable header to view all buffers, And their suballocations + /* if ( ImGui::CollapsingHeader( "Buffer allocations" ) ) { for ( const auto& buffer : Buffer::getActiveBufferHandles() ) @@ -329,14 +346,7 @@ namespace fgl::engine ImGui::Text( "Size: %zu", buffer.lock()->size() ); } }*/ - - ImGui::End(); - } - - //Render - ImGui::Render(); } - ImDrawData* data { ImGui::GetDrawData() }; #endif m_renderer.beginSwapchainRendererPass( command_buffer ); @@ -348,6 +358,13 @@ namespace fgl::engine #if TRACY_ENABLE TracyVkZone( tracy_ctx, command_buffer, "ImGui Rendering" ); #endif + + debug::world::drawPointText( { 0.0f, 0.0f, 0.0f }, camera, { 1.0f, 0.0f, 0.0f } ); + + ImGui::End(); + ImGui::Render(); + + ImDrawData* data { ImGui::GetDrawData() }; ImGui_ImplVulkan_RenderDrawData( data, command_buffer ); } #endif @@ -359,6 +376,9 @@ namespace fgl::engine #endif m_renderer.endFrame(); + + std::this_thread::sleep_until( new_time + std::chrono::milliseconds( 16 ) ); + FrameMark; } } @@ -398,9 +418,9 @@ namespace fgl::engine m_entity_renderer.getVertexBuffer(), m_entity_renderer.getIndexBuffer() ) }; - for ( int x = 0; x < 4; ++x ) + for ( int x = 0; x < 1; ++x ) { - for ( int y = 0; y < 4; ++y ) + for ( int y = 0; y < 1; ++y ) { auto sponza = GameObject::createGameObject(); sponza.model = model; diff --git a/src/engine/EngineContext.hpp b/src/engine/EngineContext.hpp index de6a462..745082f 100644 --- a/src/engine/EngineContext.hpp +++ b/src/engine/EngineContext.hpp @@ -9,10 +9,10 @@ #include "Device.hpp" #include "GameObject.hpp" -#include "Model.hpp" #include "Renderer.hpp" #include "Window.hpp" #include "engine/descriptors/DescriptorPool.hpp" +#include "engine/model/Model.hpp" #include "engine/systems/EntityRendererSystem.hpp" namespace fgl::engine diff --git a/src/engine/FrameInfo.hpp b/src/engine/FrameInfo.hpp index d7c5a03..41b345d 100644 --- a/src/engine/FrameInfo.hpp +++ b/src/engine/FrameInfo.hpp @@ -32,7 +32,6 @@ namespace fgl::engine { glm::mat4 projection { 1.0f }; glm::mat4 view { 1.0f }; - glm::mat4 inverse_view { 1.0f }; glm::vec4 ambient_light_color { 1.0f, 1.0f, 1.0f, 0.02f }; }; @@ -79,6 +78,8 @@ namespace fgl::engine Buffer& draw_parameter_buffer; DescriptorSet& gbuffer_descriptor_set; + + const Frustum& camera_frustum; }; } // namespace fgl::engine diff --git a/src/engine/coordinates/WorldCoordinate.cpp b/src/engine/coordinates/WorldCoordinate.cpp new file mode 100644 index 0000000..a66605a --- /dev/null +++ b/src/engine/coordinates/WorldCoordinate.cpp @@ -0,0 +1,49 @@ +// +// Created by kj16609 on 1/27/24. +// + +#include "WorldCoordinate.hpp" + +namespace fgl::engine +{ + + double Plane::distanceFrom( const Coordinate& coord ) const + { + return -( glm::dot( coord.position, m_direction ) - m_distance ); + } + + bool Plane::isForward( const Coordinate& coord ) const + { + return distanceFrom( coord ) > 0.0; + } + + bool Plane::isBehind( const Coordinate& coord ) const + { + return !isForward( coord ); + } + + Plane Plane::operator*( glm::mat4 matrix ) const + { + assert( m_distance != std::numeric_limits< float >::max() ); + assert( m_direction != DEFAULT_COORDINATE_VEC3 ); + + Plane result = *this; + const glm::vec3 new_direction { matrix * glm::vec4( m_direction, 1.0f ) }; + + const auto new_distance { glm::dot( new_direction, m_direction ) + m_distance }; + result.m_direction = glm::normalize( new_direction ); + result.m_distance = new_distance; + + return result; + } + + bool Frustum::pointInside( const Coordinate& coord ) const + { + // clang-format off + return + near.isForward( coord ) && far.isForward( coord ) + && top.isForward( coord ) && bottom.isForward( coord ) + && right.isForward( coord ) && left.isForward( coord ); + // clang-format on + } +} // namespace fgl::engine diff --git a/src/engine/coordinates/WorldCoordinate.hpp b/src/engine/coordinates/WorldCoordinate.hpp new file mode 100644 index 0000000..62a9662 --- /dev/null +++ b/src/engine/coordinates/WorldCoordinate.hpp @@ -0,0 +1,129 @@ +// +// Created by kj16609 on 1/26/24. +// + +#pragma once + +#include +#include + +namespace fgl::engine +{ + constexpr static auto DEFAULT_COORDINATE_VEC3 { glm::vec3( std::numeric_limits< float >::max() ) }; + + struct Coordinate + { + glm::vec3 position { DEFAULT_COORDINATE_VEC3 }; + + Coordinate() = default; + + Coordinate( glm::vec3 position ) : position( position ) {} + + Coordinate( const Coordinate& other ) = default; + + Coordinate( Coordinate&& other ) : position( std::move( other.position ) ) + { + other.position = DEFAULT_COORDINATE_VEC3; + } + }; + + class Plane + { + float m_distance { std::numeric_limits< float >::max() }; + glm::vec3 m_direction { DEFAULT_COORDINATE_VEC3 }; + + public: + + bool valid() const + { + return m_distance != std::numeric_limits< float >::max() && m_direction != DEFAULT_COORDINATE_VEC3; + } + + Plane( const glm::vec3 vector, const float distance ) : m_distance( distance ), m_direction( vector ) {} + + Plane( const glm::vec3 normal, const glm::vec3 point ) : + Plane( glm::normalize( normal ), glm::dot( glm::normalize( normal ), point ) ) + {} + + Plane() = default; + + Plane operator*( glm::mat4 matrix ) const; + + //! Returns the closest point on the plane to the 0,0,0 origin + glm::vec3 getPosition() const + { + assert( m_distance != std::numeric_limits< float >::max() ); + assert( m_direction != DEFAULT_COORDINATE_VEC3 ); + return m_direction * m_distance; + } + + bool isForward( const Coordinate& coord ) const; + bool isBehind( const Coordinate& coord ) const; + + //! Returns the distance from a point to the plane. Negative if behind, positive if in front + double distanceFrom( const Coordinate& coord ) const; + + glm::vec3 direction() const { return m_direction; } + + float distance() const { return m_distance; } + }; + + struct Frustum + { + Plane near; + Plane far; + + Plane top; + Plane bottom; + + Plane right; + Plane left; + + friend class Camera; + + public: + + Frustum() = default; + + Frustum( + const Plane near_plane, + const Plane far_plane, + const Plane top_plane, + const Plane bottom_plane, + const Plane right_plane, + const Plane left_plane ) : + near( near_plane ), + far( far_plane ), + top( top_plane ), + bottom( bottom_plane ), + right( right_plane ), + left( left_plane ) + { + assert( near.valid() ); + assert( far.valid() ); + assert( top.valid() ); + assert( bottom.valid() ); + assert( right.valid() ); + assert( left.valid() ); + + assert( right_plane.direction() != left_plane.direction() ); + assert( top_plane.direction() != bottom_plane.direction() ); + assert( near_plane.direction() != far_plane.direction() ); + } + + Frustum operator*( glm::mat4 matrix ) const + { + Frustum result = *this; + result.near = near * matrix; + result.far = far * matrix; + result.top = top * matrix; + result.bottom = bottom * matrix; + result.right = right * matrix; + result.left = left * matrix; + + return result; + } + + bool pointInside( const Coordinate& coord ) const; + }; +} // namespace fgl::engine \ No newline at end of file diff --git a/src/engine/model/BoundingBox.cpp b/src/engine/model/BoundingBox.cpp new file mode 100644 index 0000000..ec665e8 --- /dev/null +++ b/src/engine/model/BoundingBox.cpp @@ -0,0 +1,232 @@ +// +// Created by kj16609 on 1/27/24. +// + +#include "BoundingBox.hpp" + +#include + +#include "engine/coordinates/WorldCoordinate.hpp" + +namespace fgl::engine +{ + + bool engine::BoundingBox::isInFrustum( const Frustum& frustum ) const + { + ZoneScoped; + const auto points { this->points() }; + for ( const auto& point : points ) + { + if ( frustum.pointInside( point ) ) return true; + } + + return false; + } + + consteval std::array< std::uint32_t, BoundingBox::indicies_count > BoundingBox::triangleIndicies() + { + /** + * Order (Top) + * 1 =========== 0 + * || || + * || || + * 2 =========== 3 + * + * Order (Bottom) + * 5 =========== 4 + * || || + * || || + * 6 =========== 7 + * + * Order (Side - 1) + * 2 =========== 3 + * || || + * || || + * 6 =========== 7 + * + * Order (Side - 2) + * 1 =========== 0 + * || || + * || || + * 5 =========== 4 + * + * Order (Side - 3) + * 3 =========== 0 + * || || + * || || + * 7 =========== 4 + * + * Order (Side - 4) + * 2 =========== 1 + * || || + * || || + * 6 =========== 5 + */ + + // clang-format off + std::array< std::uint32_t, indicies_count > data { + //Top tris + 0, 1, 2, + 1, 2, 3, + //Bottom tris + 4, 5, 6, + 5, 6, 7, + //Side 1 + 2, 3, 6, + 3, 6, 7, + //Side 2 + 1, 0, 5, + 0, 5, 4, + //Side 3 + 3, 0, 7, + 0, 7, 4, + //Side 4 + 2, 1, 6, + 1, 6, 5 + }; + // clang-format on + + return data; + } + + std::vector< glm::vec3 > BoundingBox::points() const + { + assert( middle != DEFAULT_COORDINATE_VEC3 ); + assert( scale != glm::vec3( 0.0f ) ); + std::vector< glm::vec3 > points; + + // xp == x positive (Highest x point) + // xn == x negative (Lowest x point) + + const glm::vec3 xp_yp_zp { middle + scale }; + const glm::vec3 xn_yn_zn { middle - scale }; + + const auto xn { xn_yn_zn.x }; + const auto yn { xn_yn_zn.y }; + const auto zn { xn_yn_zn.z }; + + const auto xp { xp_yp_zp.x }; + const auto yp { xp_yp_zp.y }; + const auto zp { xp_yp_zp.z }; + + //Top + const glm::vec3 xn_yp_zp { xn, yp, zp }; // (- + +) + const glm::vec3 xn_yp_zn { xn, yp, zn }; // (- + -) + const glm::vec3 xp_yp_zn { xp, yp, zn }; // (+ + -) + + /* + * Top-Down view (X,Y,Z) + * (-,+,+) =========== (+,+,+) + * || || + * || || + * (-,+,-) =========== (+,+,-) + * + * Order (Top) + * 1 =========== 0 + * || || + * || || + * 2 =========== 3 + * + * Order (Bottom) + * 5 =========== 4 + * || || + * || || + * 6 =========== 7 + */ + + points.resize( 8 ); + points[ 0 ] = xp_yp_zp; + points[ 1 ] = xn_yp_zp; + points[ 2 ] = xn_yp_zn; + points[ 3 ] = xp_yp_zn; + + //Bottom + const glm::vec3 xn_yn_zp { xn, yn, zp }; // (- - +) + const glm::vec3 xp_yn_zn { xp, yn, zn }; // (+ - -) + const glm::vec3 xp_yn_zp { xp, yn, zp }; // (+ - +) + + /* + * Bottom-Top view (X,Y,Z) + * (-,-,+) =========== (+,-,+) + * || || + * || || + * (-,-,-) =========== (+,-,-) + */ + + points[ 4 ] = xp_yn_zp; + points[ 5 ] = xn_yn_zp; + points[ 6 ] = xn_yn_zn; + points[ 7 ] = xp_yn_zn; + + return points; + } + + BoundingBox BoundingBox::combine( const BoundingBox& other ) const + { + ZoneScoped; + if ( middle == DEFAULT_COORDINATE_VEC3 ) + return other; + else + { + const auto& other_points { other.points() }; + std::vector< glm::vec3 > points { this->points() }; + points.insert( points.end(), other_points.begin(), other_points.end() ); + + //TODO: There might be a way to do this without needing to do yet another point calculation. + return generateBoundingFromPoints( points ); + } + } + + BoundingBox BoundingBox::operator*( const glm::mat4 matrix ) const + { + ZoneScoped; + const glm::vec3 new_middle { matrix * glm::vec4( middle, 1.0f ) }; + const glm::vec3 new_scale { matrix * glm::vec4( scale, 0.0f ) }; + return { new_middle, new_scale }; + } + + std::vector< std::pair< glm::vec3, glm::vec3 > > BoundingBox::lines() const + { + const auto points { this->points() }; + std::vector< std::pair< glm::vec3, glm::vec3 > > lines; + for ( std::uint32_t i = 0; i < points.size() - 1; ++i ) + { + lines.emplace_back( points[ i ], points[ i + 1 ] ); + } + + return lines; + } + + BoundingBox generateBoundingFromPoints( std::vector< glm::vec3 >& points ) + { + ZoneScoped; + assert( points.size() > 0 ); + + // neg (min) + glm::vec3 top_left_front { points[ 0 ] }; + // pos (max) + glm::vec3 bottom_right_back { points[ 0 ] }; + + for ( const auto& pos : points ) + { + top_left_front.x = std::min( pos.x, top_left_front.x ); + top_left_front.y = std::min( pos.y, top_left_front.y ); + top_left_front.z = std::min( pos.z, top_left_front.z ); + + bottom_right_back.x = std::max( pos.x, bottom_right_back.x ); + bottom_right_back.y = std::max( pos.y, bottom_right_back.y ); + bottom_right_back.z = std::max( pos.z, bottom_right_back.z ); + } + + //Calculate midpoint + const glm::vec3 midpoint { ( top_left_front + bottom_right_back ) / glm::vec3( 2.0f ) }; + const glm::vec3 scale { bottom_right_back - midpoint }; + + std::cout << "Generated bounding box from " << points.size() << "points. Output:\n\tMidpoint:" << midpoint.x + << " " << midpoint.y << " " << midpoint.z << "\n\tScale:" << scale.x << " " << scale.y << " " + << scale.z << std::endl; + + return { midpoint, scale }; + } + +} // namespace fgl::engine diff --git a/src/engine/model/BoundingBox.hpp b/src/engine/model/BoundingBox.hpp new file mode 100644 index 0000000..88389a6 --- /dev/null +++ b/src/engine/model/BoundingBox.hpp @@ -0,0 +1,46 @@ +// +// Created by kj16609 on 1/27/24. +// + +#pragma once + +#include + +#include +#include + +#include "engine/coordinates/WorldCoordinate.hpp" + +namespace fgl::engine +{ + class Frustum; + + struct BoundingBox + { + glm::vec3 middle { DEFAULT_COORDINATE_VEC3 }; + glm::vec3 scale { 0.0f }; + + //! Returns the top left (-x, -y, -z) coordinate + inline glm::vec3 topLeftFront() const { return middle - scale; } + + //! Returns the bottom right (x, y, z) coordinate + inline glm::vec3 bottomRightBack() const { return middle + scale; } + + // 6 sides, 2 triangles each, 3 verts per triangle + constexpr static std::uint32_t indicies_count { 6 * 2 * 3 }; + + consteval static std::array< std::uint32_t, indicies_count > triangleIndicies(); + + std::vector< glm::vec3 > points() const; + std::vector< std::pair< glm::vec3, glm::vec3 > > lines() const; + + bool isInFrustum( const Frustum& frustum ) const; + + BoundingBox combine( const BoundingBox& other ) const; + + BoundingBox operator*( glm::mat4 matrix ) const; + }; + + BoundingBox generateBoundingFromPoints( std::vector< glm::vec3 >& points ); + +} // namespace fgl::engine diff --git a/src/engine/Model.cpp b/src/engine/model/Model.cpp similarity index 90% rename from src/engine/Model.cpp rename to src/engine/model/Model.cpp index 20d94a6..ae5cba8 100644 --- a/src/engine/Model.cpp +++ b/src/engine/model/Model.cpp @@ -28,7 +28,7 @@ #include "objectloaders/tiny_obj_loader.h" #pragma GCC diagnostic pop -#include "utils.hpp" +#include "engine/utils.hpp" namespace std { @@ -69,6 +69,19 @@ namespace fgl::engine return draw_parameters; } + BoundingBox Model::buildBoundingBox( const std::vector< Primitive >& primitives ) + { + //TODO: + BoundingBox box; + + for ( const auto& primitive : primitives ) + { + box = box.combine( primitive.m_bounding_box ); + } + + return box; + } + std::vector< vk::DrawIndexedIndirectCommand > Model::getDrawCommand( const std::uint32_t index ) const { std::vector< vk::DrawIndexedIndirectCommand > draw_commands; @@ -84,20 +97,25 @@ namespace fgl::engine return draw_commands; } - Model::Model( Device& device, Builder& builder ) : + Model::Model( Device& device, ModelBuilder& builder, const BoundingBox bounding_box ) : m_device( device ), - m_draw_parameters( buildParameters( builder.m_primitives ) ) + m_draw_parameters( buildParameters( builder.m_primitives ) ), + m_bounding_box( bounding_box ) { + assert( bounding_box.middle != DEFAULT_COORDINATE_VEC3 ); m_primitives = std::move( builder.m_primitives ); } std::unique_ptr< Model > Model:: createModel( Device& device, const std::filesystem::path& path, Buffer& vertex_buffer, Buffer& index_buffer ) { - Builder builder { vertex_buffer, index_buffer }; + ModelBuilder builder { vertex_buffer, index_buffer }; builder.loadModel( path ); - return std::make_unique< Model >( device, builder ); + //Calculate bounding box + BoundingBox bounding_box { buildBoundingBox( builder.m_primitives ) }; + + return std::make_unique< Model >( device, builder, bounding_box ); } void Model::syncBuffers( vk::CommandBuffer& cmd_buffer ) @@ -141,7 +159,7 @@ namespace fgl::engine return attribute_descriptions; } - void Model::Builder::loadModel( const std::filesystem::path& filepath ) + void ModelBuilder::loadModel( const std::filesystem::path& filepath ) { if ( filepath.extension() == ".obj" ) { @@ -220,7 +238,7 @@ namespace fgl::engine } }; - void Model::Builder::loadGltf( const std::filesystem::path& filepath ) + void ModelBuilder::loadGltf( const std::filesystem::path& filepath ) { std::cout << "Loading gltf model " << filepath << std::endl; @@ -244,6 +262,8 @@ namespace fgl::engine for ( const tinygltf::Mesh& mesh : model.meshes ) { + std::vector< glm::vec3 > model_positions; + for ( const tinygltf::Primitive& primitive : mesh.primitives ) { //TODO: Implement modes @@ -279,6 +299,9 @@ namespace fgl::engine //Load positions auto& position_accessor { model.accessors.at( primitive.attributes.at( "POSITION" ) ) }; std::vector< glm::vec3 > position_data { extractData< glm::vec3 >( model, position_accessor ) }; + model_positions.insert( model_positions.end(), position_data.begin(), position_data.end() ); + + BoundingBox bounding_box { generateBoundingFromPoints( position_data ) }; std::vector< glm::vec3 > normals; @@ -399,7 +422,9 @@ namespace fgl::engine Device::getInstance().endSingleTimeCommands( cmd ); tex.dropStaging(); - Primitive prim { std::move( vertex_buffer ), std::move( index_buffer ), std::move( tex ) }; + Primitive prim { + std::move( vertex_buffer ), std::move( index_buffer ), bounding_box, std::move( tex ) + }; m_primitives.emplace_back( std::move( prim ) ); @@ -409,7 +434,7 @@ namespace fgl::engine else std::cout << "No material" << std::endl; - Primitive prim { std::move( vertex_buffer ), std::move( index_buffer ) }; + Primitive prim { std::move( vertex_buffer ), std::move( index_buffer ), bounding_box }; m_primitives.emplace_back( std::move( prim ) ); } @@ -433,7 +458,7 @@ namespace fgl::engine std::cout << "Meshes: " << model.meshes.size() << std::endl; } - void Model::Builder::loadObj( const std::filesystem::path& filepath ) + void ModelBuilder::loadObj( const std::filesystem::path& filepath ) { m_primitives.clear(); @@ -507,9 +532,18 @@ namespace fgl::engine } } + std::vector< glm::vec3 > vert_pos; + for ( const auto& vert : verts ) + { + vert_pos.emplace_back( vert.m_position ); + } + + BoundingBox bounding_box { generateBoundingFromPoints( vert_pos ) }; + m_primitives.emplace_back( VertexBufferSuballocation( m_vertex_buffer, std::move( verts ) ), - IndexBufferSuballocation( m_index_buffer, std::move( indicies ) ) ); + IndexBufferSuballocation( m_index_buffer, std::move( indicies ) ), + bounding_box ); std::cout << unique_verts.size() << " unique verts" << std::endl; } diff --git a/src/engine/Model.hpp b/src/engine/model/Model.hpp similarity index 61% rename from src/engine/Model.hpp rename to src/engine/model/Model.hpp index 127d886..08c585a 100644 --- a/src/engine/Model.hpp +++ b/src/engine/model/Model.hpp @@ -14,13 +14,14 @@ #include #include -#include "Device.hpp" +#include "BoundingBox.hpp" +#include "engine/Device.hpp" #include "engine/buffers/Buffer.hpp" #include "engine/buffers/BufferSuballocation.hpp" #include "engine/buffers/vector/DeviceVector.hpp" #include "engine/buffers/vector/HostVector.hpp" #include "engine/texture/Texture.hpp" -#include "utils.hpp" +#include "engine/utils.hpp" namespace fgl::engine { @@ -62,18 +63,27 @@ namespace fgl::engine { VertexBufferSuballocation m_vertex_buffer; IndexBufferSuballocation m_index_buffer; + BoundingBox m_bounding_box; std::optional< Texture > m_texture { std::nullopt }; - Primitive( VertexBufferSuballocation&& vertex_buffer, IndexBufferSuballocation&& index_buffer ) : + Primitive( + VertexBufferSuballocation&& vertex_buffer, + IndexBufferSuballocation&& index_buffer, + BoundingBox& bounding_box ) : m_vertex_buffer( std::move( vertex_buffer ) ), - m_index_buffer( std::move( index_buffer ) ) + m_index_buffer( std::move( index_buffer ) ), + m_bounding_box( bounding_box ) {} Primitive( - VertexBufferSuballocation&& vertex_buffer, IndexBufferSuballocation&& index_buffer, Texture&& texture ) : + VertexBufferSuballocation&& vertex_buffer, + IndexBufferSuballocation&& index_buffer, + BoundingBox& bounding_box, + Texture&& texture ) : m_vertex_buffer( std::move( vertex_buffer ) ), m_index_buffer( std::move( index_buffer ) ), + m_bounding_box( bounding_box ), m_texture( std::move( texture ) ) {} @@ -82,39 +92,49 @@ namespace fgl::engine Primitive( Primitive&& other ) = default; }; + struct ModelBuilder + { + Buffer& m_vertex_buffer; + Buffer& m_index_buffer; + + std::vector< ::fgl::engine::Primitive > m_primitives {}; + + ModelBuilder() = delete; + + ModelBuilder( Buffer& parent_vertex_buffer, Buffer& parent_index_buffer ) : + m_vertex_buffer( parent_vertex_buffer ), + m_index_buffer( parent_index_buffer ) + {} + + void loadModel( const std::filesystem::path& filepath ); + void loadObj( const std::filesystem::path& filepath ); + void loadGltf( const std::filesystem::path& filepath ); + }; + class Model { Device& m_device; - std::vector< vk::DrawIndexedIndirectCommand > buildParameters( const std::vector< Primitive >& primitives ); + static std::vector< vk::DrawIndexedIndirectCommand > buildParameters( const std::vector< Primitive >& + primitives ); + static BoundingBox buildBoundingBox( const std::vector< Primitive >& primitives ); std::vector< vk::DrawIndexedIndirectCommand > m_draw_parameters; std::string m_name { "Unnamed model" }; + //! Bounding box of the model + BoundingBox m_bounding_box; + public: + //! Returns the bounding box in model space + const BoundingBox& getBoundingBox() const { return m_bounding_box; } + + BoundingBox getBoundingBox( const glm::mat4 matrix ) const { return m_bounding_box * matrix; } + std::vector< ::fgl::engine::Primitive > m_primitives {}; - struct Builder - { - Buffer& m_vertex_buffer; - Buffer& m_index_buffer; - - std::vector< ::fgl::engine::Primitive > m_primitives {}; - - Builder() = delete; - - Builder( Buffer& parent_vertex_buffer, Buffer& parent_index_buffer ) : - m_vertex_buffer( parent_vertex_buffer ), - m_index_buffer( parent_index_buffer ) - {} - - void loadModel( const std::filesystem::path& filepath ); - void loadObj( const std::filesystem::path& filepath ); - void loadGltf( const std::filesystem::path& filepath ); - }; - std::vector< vk::DrawIndexedIndirectCommand > getDrawCommand( const std::uint32_t index ) const; static std::unique_ptr< Model > createModel( @@ -124,7 +144,7 @@ namespace fgl::engine const std::string& getName() const { return m_name; } - Model( Device& device, Builder& builder ); + Model( Device& device, ModelBuilder& builder, const BoundingBox bounding_box ); ~Model() = default; diff --git a/src/engine/pipeline/Pipeline.cpp b/src/engine/pipeline/Pipeline.cpp index f8d6c56..8720078 100644 --- a/src/engine/pipeline/Pipeline.cpp +++ b/src/engine/pipeline/Pipeline.cpp @@ -7,7 +7,7 @@ #include #include -#include "engine/Model.hpp" +#include "engine/model/Model.hpp" namespace fgl::engine { diff --git a/src/engine/pipeline/PipelineConfigInfo.cpp b/src/engine/pipeline/PipelineConfigInfo.cpp index ca3f494..ead4972 100644 --- a/src/engine/pipeline/PipelineConfigInfo.cpp +++ b/src/engine/pipeline/PipelineConfigInfo.cpp @@ -4,7 +4,7 @@ #include "PipelineConfigInfo.hpp" -#include "engine/Model.hpp" +#include "engine/model/Model.hpp" namespace fgl::engine { diff --git a/src/engine/systems/EntityRendererSystem.cpp b/src/engine/systems/EntityRendererSystem.cpp index fbc1d2d..4899bb7 100644 --- a/src/engine/systems/EntityRendererSystem.cpp +++ b/src/engine/systems/EntityRendererSystem.cpp @@ -8,6 +8,9 @@ #define GLM_FORCE_DEPTH_ZERO_TO_ON #include #include +#include +#include +#include #include #include @@ -18,6 +21,7 @@ #include #include +#include "engine/debug/drawers.hpp" #include "engine/literals/size.hpp" namespace fgl::engine @@ -94,6 +98,12 @@ namespace fgl::engine TracyVkZone( info.tracy_ctx, command_buffer, "Render game object" ); if ( obj.model == nullptr ) continue; + const BoundingBox model_bounding_box { obj.model->getBoundingBox( obj.transform.mat4() ) }; + + debug::world::drawBoundingBox( model_bounding_box, info.camera ); + + if ( !model_bounding_box.isInFrustum( info.camera_frustum ) ) continue; + for ( const auto& primitive : obj.model->m_primitives ) { ZoneScopedN( "Queue Primitive" ); @@ -157,6 +167,13 @@ namespace fgl::engine } } + if ( draw_pairs.empty() ) + { + std::cout << "Nothing to draw!" << std::endl; + command_buffer.nextSubpass( vk::SubpassContents::eInline ); + return; + } + std::vector< vk::DrawIndexedIndirectCommand > draw_commands; std::vector< ModelMatrixInfo > model_matrices; @@ -172,8 +189,6 @@ namespace fgl::engine } TracyCZoneEnd( filter_zone_TRACY ); - assert( draw_commands.size() > 0 && "No draw commands to render" ); - TracyCZoneN( draw_zone_TRACY, "Submit draw data", true ); auto& draw_parameter_buffer { m_draw_parameter_buffers[ info.frame_idx ] }; diff --git a/src/engine/systems/EntityRendererSystem.hpp b/src/engine/systems/EntityRendererSystem.hpp index cad1f77..4f1aa5d 100644 --- a/src/engine/systems/EntityRendererSystem.hpp +++ b/src/engine/systems/EntityRendererSystem.hpp @@ -11,8 +11,8 @@ #include "engine/Device.hpp" #include "engine/FrameInfo.hpp" #include "engine/GameObject.hpp" -#include "engine/Model.hpp" #include "engine/SwapChain.hpp" +#include "engine/model/Model.hpp" #include "engine/pipeline/PipelineT.hpp" namespace fgl::engine