Start basic shadowmap stuff

This commit is contained in:
2025-09-27 14:44:46 -04:00
parent 9d1a011639
commit 9ff05731f6
52 changed files with 1373 additions and 855 deletions

View File

@@ -2,7 +2,7 @@
// Created by kj16609 on 7/23/24. // Created by kj16609 on 7/23/24.
// //
#include "engine/camera/Camera.hpp" #include "engine/camera/RenderCamera.hpp"
#include <cassert> #include <cassert>
@@ -13,7 +13,7 @@
namespace fgl::engine::gui namespace fgl::engine::gui
{ {
void handleCameraInput( const FrameInfo& info, Camera& camera ) void handleCameraInput( const FrameInfo& info, RenderCamera& camera )
{ {
const auto delta_time { info.delta_time }; const auto delta_time { info.delta_time };
@@ -104,7 +104,7 @@ namespace fgl::engine::gui
assert( camera_ptr ); assert( camera_ptr );
Camera& camera { *camera_ptr }; RenderCamera& camera { *camera_ptr };
std::string name {}; std::string name {};

View File

@@ -31,6 +31,8 @@ namespace fgl::engine::gui
void drawComponentsList( GameObject& game_object ); void drawComponentsList( GameObject& game_object );
void drawSelectedComponent(); void drawSelectedComponent();
void drawShadowmaps( const FrameInfo& info );
void drawCameraOutputs( FrameInfo& info ); void drawCameraOutputs( FrameInfo& info );
void drawStats( const FrameInfo& info ); void drawStats( const FrameInfo& info );

View File

@@ -2,13 +2,14 @@
#include <vulkan/vulkan.hpp> #include <vulkan/vulkan.hpp>
#include "assets/transfer/TransferManager.hpp" #include "assets/transfer/TransferManager.hpp"
#include "camera/CameraManager.hpp"
#include "camera/ShadowMap.hpp"
#include "core.hpp" #include "core.hpp"
#include "engine/debug/profiling/counters.hpp" #include "engine/debug/profiling/counters.hpp"
#include "engine/debug/timing/FlameGraph.hpp" #include "engine/debug/timing/FlameGraph.hpp"
#include "engine/flags.hpp" #include "engine/flags.hpp"
#include "engine/math/literals/size.hpp" #include "engine/math/literals/size.hpp"
#include "engine/memory/buffers/BufferHandle.hpp" #include "engine/memory/buffers/BufferHandle.hpp"
#include "memory/buffers/BufferHandle.hpp"
#include "safe_include.hpp" #include "safe_include.hpp"
namespace fgl::engine::gui namespace fgl::engine::gui
@@ -123,6 +124,38 @@ namespace fgl::engine::gui
} }
} }
void drawShadowmaps( const FrameInfo& info )
{
ImGui::Begin( "Shadowmaps" );
static std::unordered_map< int*, std::vector< Texture > > textures {};
bool move_sun { false };
move_sun = ImGui::Button( "Move sun shadowmap to camera" );
for ( const auto& weak_shadowmap : getShadowmaps() )
{
if ( weak_shadowmap.expired() ) continue;
auto shadowmap_ptr { weak_shadowmap.lock() };
ShadowMap& shadowmap { *shadowmap_ptr };
// if ( move_sun )
{
shadowmap.m_camera->moveTo( CameraManager::instance().getPrimary()->getTransform() );
}
const FrameIndex frame_index { info.in_flight_idx };
// camera.getCompositeSwapchain().m_gbuffer_target[ frame_index ]->drawImGui( target_size );
shadowmap.m_swapchain->depthTexture( frame_index )->drawImGui();
}
ImGui::End();
}
void drawStats( const FrameInfo& info ) void drawStats( const FrameInfo& info )
{ {
ImGui::Begin( "Stats" ); ImGui::Begin( "Stats" );
@@ -143,6 +176,11 @@ namespace fgl::engine::gui
debug::timing::render(); debug::timing::render();
} }
if ( ImGui::CollapsingHeader( "Shadowmaps" ) )
{
drawShadowmaps( info );
}
if ( ImGui::Button( "Reload shaders" ) ) if ( ImGui::Button( "Reload shaders" ) )
{ {
flags::triggerShaderReload(); flags::triggerShaderReload();

View File

@@ -7,7 +7,7 @@
#include "engine/FrameInfo.hpp" #include "engine/FrameInfo.hpp"
#include "engine/assets/model/Model.hpp" #include "engine/assets/model/Model.hpp"
#include "engine/assets/model/builders/SceneBuilder.hpp" #include "engine/assets/model/builders/SceneBuilder.hpp"
#include "engine/camera/Camera.hpp" #include "engine/camera/RenderCamera.hpp"
#include "engine/filesystem/scanner/FileScanner.hpp" #include "engine/filesystem/scanner/FileScanner.hpp"
#include "engine/filesystem/types.hpp" #include "engine/filesystem/types.hpp"
#include "engine/rendering/PresentSwapChain.hpp" #include "engine/rendering/PresentSwapChain.hpp"
@@ -126,7 +126,7 @@ namespace fgl::engine::gui
inline void drawConfigBar( inline void drawConfigBar(
[[maybe_unused]] const FrameInfo& info, [[maybe_unused]] const FrameInfo& info,
[[maybe_unused]] const Camera& camera, [[maybe_unused]] const RenderCamera& camera,
[[maybe_unused]] const FrameIndex frame_index, [[maybe_unused]] const FrameIndex frame_index,
std::uint_fast8_t& current ) std::uint_fast8_t& current )
{ {
@@ -167,7 +167,7 @@ namespace fgl::engine::gui
} }
} }
void drawRenderingOutputs( FrameInfo& info, const Camera& camera ) void drawRenderingOutputs( FrameInfo& info, const RenderCamera& camera )
{ {
ZoneScoped; ZoneScoped;
const auto frame_index { info.in_flight_idx }; const auto frame_index { info.in_flight_idx };

View File

@@ -7,12 +7,12 @@
namespace fgl::engine namespace fgl::engine
{ {
struct FrameInfo; struct FrameInfo;
class Camera; class RenderCamera;
} // namespace fgl::engine } // namespace fgl::engine
namespace fgl::engine::gui namespace fgl::engine::gui
{ {
void drawRenderingOutputs( FrameInfo& info, const Camera& camera ); void drawRenderingOutputs( FrameInfo& info, const RenderCamera& camera );
} // namespace fgl::engine::gui } // namespace fgl::engine::gui

View File

@@ -11,9 +11,10 @@
#include <iostream> #include <iostream>
#include "KeyboardMovementController.hpp" #include "KeyboardMovementController.hpp"
#include "camera/Camera.hpp"
#include "camera/CameraManager.hpp" #include "camera/CameraManager.hpp"
#include "camera/GBufferRenderer.hpp" #include "camera/GBufferRenderer.hpp"
#include "camera/RenderCamera.hpp"
#include "camera/ShadowMap.hpp"
#include "debug/timing/FlameGraph.hpp" #include "debug/timing/FlameGraph.hpp"
#include "engine/assets/model/builders/SceneBuilder.hpp" #include "engine/assets/model/builders/SceneBuilder.hpp"
#include "engine/assets/transfer/TransferManager.hpp" #include "engine/assets/transfer/TransferManager.hpp"
@@ -27,49 +28,20 @@ namespace fgl::engine
constexpr float MAX_DELTA_TIME { 0.5 }; constexpr float MAX_DELTA_TIME { 0.5 };
inline static EngineContext* instance { nullptr }; inline static EngineContext* instance { nullptr };
PerFrameArray< std::unique_ptr< descriptors::DescriptorSet > > createDrawCommandsDescriptors(
PerFrameArray< DeviceVector< vk::DrawIndexedIndirectCommand > >& gpu_draw_commands,
PerFrameArray< DeviceVector< InstanceRenderInfo > >& per_vertex_info )
{
PerFrameArray< std::unique_ptr< descriptors::DescriptorSet > > descriptors {};
for ( std::uint16_t i = 0; i < gpu_draw_commands.size(); ++i )
{
auto& command_buffer { gpu_draw_commands[ i ] };
auto& per_vertex_buffer { per_vertex_info[ i ] };
auto descriptor { COMMANDS_SET.create() };
descriptor->bindStorageBuffer( 0, command_buffer );
descriptor->bindStorageBuffer( 1, per_vertex_buffer );
descriptor->update();
descriptor->setName( "Command Buffer + Vertex Buffer" );
descriptors[ i ] = std::move( descriptor );
}
return descriptors;
}
EngineContext::EngineContext() : EngineContext::EngineContext() :
m_ubo_buffer_pool( 1_MiB, vk::BufferUsageFlagBits::eUniformBuffer, vk::MemoryPropertyFlagBits::eHostVisible ), m_ubo_buffer_pool( 1_MiB, vk::BufferUsageFlagBits::eUniformBuffer, vk::MemoryPropertyFlagBits::eHostVisible ),
m_draw_parameter_pool( m_delta_time( 0.0 ),
4_MiB, m_camera_manager()
vk::BufferUsageFlagBits::eIndirectBuffer | vk::BufferUsageFlagBits::eStorageBuffer,
vk::MemoryPropertyFlagBits::eDeviceLocal | vk::MemoryPropertyFlagBits::eHostVisible ),
m_gpu_draw_commands(
constructPerFrame< DeviceVector< vk::DrawIndexedIndirectCommand > >( m_draw_parameter_pool ) ),
m_per_vertex_infos( m_model_buffers.m_generated_instance_info ),
m_gpu_draw_cmds_desc( createDrawCommandsDescriptors( m_gpu_draw_commands, m_per_vertex_infos ) ),
m_delta_time( 0.0 )
{ {
ZoneScoped; ZoneScoped;
using namespace fgl::literals::size_literals; using namespace fgl::literals::size_literals;
instance = this; instance = this;
// memory::TransferManager::createInstance( device, 128_MiB ); m_camera_manager.createPrimary();
m_sun = std::make_unique< Sun >();
m_draw_parameter_pool->setDebugName( "Draw parameter pool" ); // memory::TransferManager::createInstance( device, 128_MiB );
} }
static Average< float, 60 * 15 > rolling_ms_average; static Average< float, 60 * 15 > rolling_ms_average;
@@ -116,10 +88,19 @@ namespace fgl::engine
auto sh_camera { current_camera_ptr.lock() }; auto sh_camera { current_camera_ptr.lock() };
Camera& current_camera { *sh_camera }; RenderCamera& current_camera { *sh_camera };
current_camera.pass( frame_info ); current_camera.pass( frame_info );
} }
for ( auto& shadow_map : getShadowmaps() )
{
if ( shadow_map.expired() ) continue;
auto shadowmap { shadow_map.lock() };
shadowmap->pass( frame_info );
}
} }
void EngineContext::renderFrame() void EngineContext::renderFrame()
@@ -136,9 +117,6 @@ namespace fgl::engine
// Begin by getting every single instance ready. // Begin by getting every single instance ready.
DeviceVector< PrimitiveInstanceInfo >& instances { m_model_buffers.m_primitive_instances.vec() }; DeviceVector< PrimitiveInstanceInfo >& instances { m_model_buffers.m_primitive_instances.vec() };
m_gpu_draw_commands[ in_flight_idx ].resize( instances.size() );
m_model_buffers.m_generated_instance_info[ in_flight_idx ].resize( instances.size() );
FrameInfo frame_info { in_flight_idx, FrameInfo frame_info { in_flight_idx,
present_idx, present_idx,
m_delta_time, m_delta_time,
@@ -148,8 +126,9 @@ namespace fgl::engine
m_renderer.getCurrentTracyCTX(), m_renderer.getCurrentTracyCTX(),
*m_model_buffers.m_primitives_desc, *m_model_buffers.m_primitives_desc,
*m_model_buffers.m_instances_desc, *m_model_buffers.m_instances_desc,
*m_gpu_draw_cmds_desc[ in_flight_idx ], instances,
m_gpu_draw_commands[ in_flight_idx ], // *m_gpu_draw_cmds_desc[ in_flight_idx ],
// m_gpu_draw_commands[ in_flight_idx ],
m_game_objects, m_game_objects,
this->m_renderer.getSwapChain() }; this->m_renderer.getSwapChain() };

View File

@@ -12,6 +12,7 @@
#include "engine/assets/transfer/TransferManager.hpp" #include "engine/assets/transfer/TransferManager.hpp"
#include "engine/math/literals/size.hpp" #include "engine/math/literals/size.hpp"
#include "engine/rendering/Renderer.hpp" #include "engine/rendering/Renderer.hpp"
#include "lighting/lights/Sun.hpp"
#include "scene/World.hpp" #include "scene/World.hpp"
#include "systems/composition/GuiSystem.hpp" #include "systems/composition/GuiSystem.hpp"
@@ -67,9 +68,6 @@ namespace fgl::engine
// Memory pool for shader uniforms. // Memory pool for shader uniforms.
memory::Buffer m_ubo_buffer_pool; memory::Buffer m_ubo_buffer_pool;
// Memory pool for matrix info and draw parameters
memory::Buffer m_draw_parameter_pool;
public: public:
std::vector< std::shared_ptr< GameObject > > m_game_objects {}; std::vector< std::shared_ptr< GameObject > > m_game_objects {};
@@ -78,22 +76,18 @@ namespace fgl::engine
private: private:
PerFrameArray< DeviceVector< vk::DrawIndexedIndirectCommand > > m_gpu_draw_commands;
//TODO: Outright remove this. Or the one in model buffers.
PerFrameArray< DeviceVector< InstanceRenderInfo > >& m_per_vertex_infos;
PerFrameArray< std::unique_ptr< descriptors::DescriptorSet > > m_gpu_draw_cmds_desc;
MaterialManager m_material_manager {}; MaterialManager m_material_manager {};
CameraManager m_camera_manager {};
memory::TransferManager m_transfer_manager { m_device, 512_MiB }; memory::TransferManager m_transfer_manager { m_device, 512_MiB };
std::chrono::time_point< Clock > m_last_tick { Clock::now() }; std::chrono::time_point< Clock > m_last_tick { Clock::now() };
DeltaTime m_delta_time; DeltaTime m_delta_time;
CameraManager m_camera_manager {};
// World m_world; // World m_world;
std::unique_ptr< Sun > m_sun;
public: public:
// ModelManager& models() { return m_model_manager; } // ModelManager& models() { return m_model_manager; }

View File

@@ -4,20 +4,21 @@
#include "FrameInfo.hpp" #include "FrameInfo.hpp"
#include "camera/Camera.hpp"
#include "camera/GBufferSwapchain.hpp" #include "camera/GBufferSwapchain.hpp"
#include "camera/RenderCamera.hpp"
namespace fgl::engine namespace fgl::engine
{ {
descriptors::DescriptorSet& FrameInfo::getGBufferDescriptor() const // descriptors::DescriptorSet& FrameInfo::getGBufferDescriptor() const
{ // {
return camera->getSwapchain().getGBufferDescriptor( in_flight_idx ); // return camera->getSwapchain().getGBufferDescriptor( in_flight_idx );
} // }
descriptors::DescriptorSet& FrameInfo::getCameraDescriptor() const descriptors::DescriptorSet& FrameInfo::getCameraDescriptor() const
{ {
return camera->getDescriptor( in_flight_idx ); FGL_ASSERT( camera != nullptr, "Camera not set" );
return *camera->m_camera_info_descriptors[ in_flight_idx ];
} }
void FrameInfo::bindCamera( [[maybe_unused]] Pipeline& pipeline ) void FrameInfo::bindCamera( [[maybe_unused]] Pipeline& pipeline )

View File

@@ -21,6 +21,7 @@
namespace fgl::engine namespace fgl::engine
{ {
class CameraViewpoint;
struct PrimitiveRenderInfo; struct PrimitiveRenderInfo;
struct PrimitiveInstanceInfo; struct PrimitiveInstanceInfo;
class Pipeline; class Pipeline;
@@ -31,7 +32,7 @@ namespace fgl::engine
} }
class PresentSwapChain; class PresentSwapChain;
class Camera; class RenderCamera;
struct PointLight struct PointLight
{ {
@@ -81,9 +82,9 @@ namespace fgl::engine
CommandBuffers& command_buffer; CommandBuffers& command_buffer;
Camera* camera { nullptr }; CameraViewpoint* camera { nullptr };
std::vector< std::weak_ptr< Camera > >& m_camera_list; std::vector< std::weak_ptr< RenderCamera > >& m_camera_list;
// descriptors::DescriptorSet& global_descriptor_set; // descriptors::DescriptorSet& global_descriptor_set;
// OctTreeNode& game_objects; // OctTreeNode& game_objects;
@@ -91,16 +92,17 @@ namespace fgl::engine
descriptors::DescriptorSet& m_primitives_desc; descriptors::DescriptorSet& m_primitives_desc;
descriptors::DescriptorSet& m_instances_desc; descriptors::DescriptorSet& m_instances_desc;
descriptors::DescriptorSet& m_command_buffer_desc; DeviceVector< PrimitiveInstanceInfo >& instances;
// descriptors::DescriptorSet& m_command_buffer_desc;
// out for rendering process // out for rendering process
//! Populated commands buffer by the culling pass //! Populated commands buffer by the culling pass
DeviceVector< vk::DrawIndexedIndirectCommand >& m_commands; // DeviceVector< vk::DrawIndexedIndirectCommand >& m_commands;
std::vector< std::shared_ptr< GameObject > >& m_game_objects; std::vector< std::shared_ptr< GameObject > >& m_game_objects;
// descriptors::DescriptorSet& gui_input_descriptor; // descriptors::DescriptorSet& gui_input_descriptor;
[[nodiscard]] descriptors::DescriptorSet& getGBufferDescriptor() const; // [[nodiscard]] descriptors::DescriptorSet& getGBufferDescriptor() const;
[[nodiscard]] descriptors::DescriptorSet& getCameraDescriptor() const; [[nodiscard]] descriptors::DescriptorSet& getCameraDescriptor() const;
PresentSwapChain& swap_chain; PresentSwapChain& swap_chain;

View File

@@ -38,7 +38,6 @@ namespace fgl::engine
1_GiB, 1_GiB,
vk::BufferUsageFlagBits::eIndexBuffer | vk::BufferUsageFlagBits::eTransferDst, vk::BufferUsageFlagBits::eIndexBuffer | vk::BufferUsageFlagBits::eTransferDst,
vk::MemoryPropertyFlagBits::eDeviceLocal ), vk::MemoryPropertyFlagBits::eDeviceLocal ),
m_generated_instance_info( constructPerFrame< DeviceVector< InstanceRenderInfo > >( m_vertex_buffer ) ),
m_primitive_info( m_long_buffer ), m_primitive_info( m_long_buffer ),
m_primitive_instances( m_short_buffer ), m_primitive_instances( m_short_buffer ),
m_model_instances( m_short_buffer ) m_model_instances( m_short_buffer )

View File

@@ -104,9 +104,6 @@ namespace fgl::engine
memory::Buffer m_vertex_buffer; memory::Buffer m_vertex_buffer;
memory::Buffer m_index_buffer; memory::Buffer m_index_buffer;
//! Generated by the compute shader, This vector contains the instance info for each primitive.
PerFrameArray< DeviceVector< InstanceRenderInfo > > m_generated_instance_info;
//! contains the core primitive info, like vertex and index offsets and counts //! contains the core primitive info, like vertex and index offsets and counts
IndexedVector< PrimitiveRenderInfo > m_primitive_info; IndexedVector< PrimitiveRenderInfo > m_primitive_info;
//! contains a list of all rendered primitives //! contains a list of all rendered primitives

View File

@@ -14,7 +14,7 @@
#include "assets/model/ModelVertex.hpp" #include "assets/model/ModelVertex.hpp"
#include "engine/assets/stores.hpp" #include "engine/assets/stores.hpp"
#include "engine/camera/Camera.hpp" #include "engine/camera/RenderCamera.hpp"
#include "engine/debug/logging/logging.hpp" #include "engine/debug/logging/logging.hpp"
#include "engine/descriptors/DescriptorSet.hpp" #include "engine/descriptors/DescriptorSet.hpp"
#include "engine/gameobjects/GameObject.hpp" #include "engine/gameobjects/GameObject.hpp"

View File

@@ -4,6 +4,8 @@
#pragma once #pragma once
#include <glm/mat4x4.hpp>
namespace fgl::engine namespace fgl::engine
{ {

View File

@@ -4,8 +4,8 @@
#include "CameraManager.hpp" #include "CameraManager.hpp"
#include "Camera.hpp"
#include "GBufferRenderer.hpp" #include "GBufferRenderer.hpp"
#include "RenderCamera.hpp"
#include "engine/debug/DEBUG_NAMES.hpp" #include "engine/debug/DEBUG_NAMES.hpp"
#include "engine/math/literals/size.hpp" #include "engine/math/literals/size.hpp"
@@ -14,35 +14,64 @@ namespace fgl::engine
using namespace fgl::literals::size_literals; using namespace fgl::literals::size_literals;
std::vector< std::weak_ptr< Camera > >& CameraManager::getCameras() inline static CameraManager* camera_manager_instance { nullptr };
{
return cameras;
}
std::shared_ptr< Camera >& CameraManager::getPrimary()
{
return m_primary_camera;
}
CameraManager::CameraManager() : CameraManager::CameraManager() :
m_renderer( std::make_shared< GBufferRenderer >() ), m_renderer( std::make_shared< GBufferRenderer >() ),
m_data_buffer( 4_KiB, vk::BufferUsageFlagBits::eUniformBuffer, vk::MemoryPropertyFlagBits::eHostVisible ) m_data_buffer( 4_KiB, vk::BufferUsageFlagBits::eUniformBuffer, vk::MemoryPropertyFlagBits::eHostVisible )
{ {
m_primary_camera = createCamera( { 1920, 1080 } ); FGL_ASSERT( camera_manager_instance == nullptr, "CameraManager already initialized" );
m_primary_camera->setName( CAMERA_EDITOR_NAME ); camera_manager_instance = this;
}
std::shared_ptr< Camera > CameraManager::createCamera( const vk::Extent2D extent ) m_data_buffer->setDebugName( "Camera data buffer" );
{
std::shared_ptr< Camera > camera { new Camera( extent, m_data_buffer, m_renderer ) };
this->cameras.emplace_back( camera );
return camera;
} }
CameraManager::~CameraManager() CameraManager::~CameraManager()
{ {
m_primary_camera.reset(); m_primary_camera.reset();
camera_manager_instance = nullptr;
}
std::vector< std::weak_ptr< RenderCamera > >& CameraManager::getCameras()
{
return cameras;
}
std::shared_ptr< RenderCamera >& CameraManager::getPrimary()
{
return m_primary_camera;
}
void CameraManager::createPrimary()
{
m_primary_camera = createCamera( { 1920, 1080 } );
m_primary_camera->setName( CAMERA_EDITOR_NAME );
}
CameraManager& CameraManager::instance()
{
FGL_ASSERT( camera_manager_instance, "CameraManager not initialized" );
return *camera_manager_instance;
}
std::shared_ptr< RenderCamera > CameraManager::createCamera( const vk::Extent2D extent )
{
auto& instance = CameraManager::instance();
std::shared_ptr< RenderCamera > camera {
new RenderCamera( extent, instance.m_data_buffer, instance.m_renderer )
};
instance.cameras.emplace_back( camera );
return camera;
}
std::shared_ptr< CameraViewpoint > CameraManager::createViewpoint( const vk::Extent2D extent )
{
auto& instance = CameraManager::instance();
std::shared_ptr< CameraViewpoint > camera_viewpoint { new CameraViewpoint( instance.m_data_buffer, extent ) };
return camera_viewpoint;
} }
} // namespace fgl::engine } // namespace fgl::engine

View File

@@ -5,7 +5,7 @@
#pragma once #pragma once
#include <vector> #include <vector>
#include "Camera.hpp" #include "RenderCamera.hpp"
#include "engine/memory/buffers/BufferHandle.hpp" #include "engine/memory/buffers/BufferHandle.hpp"
namespace fgl::engine namespace fgl::engine
@@ -20,20 +20,23 @@ namespace fgl::engine
std::shared_ptr< GBufferRenderer > m_renderer; std::shared_ptr< GBufferRenderer > m_renderer;
memory::Buffer m_data_buffer; memory::Buffer m_data_buffer;
std::shared_ptr< Camera > m_primary_camera { nullptr }; std::shared_ptr< RenderCamera > m_primary_camera { nullptr };
std::vector< std::weak_ptr< Camera > > cameras {}; std::vector< std::weak_ptr< RenderCamera > > cameras {};
public: public:
CameraManager(); CameraManager();
~CameraManager(); ~CameraManager();
std::vector< std::weak_ptr< Camera > >& getCameras(); std::vector< std::weak_ptr< RenderCamera > >& getCameras();
std::shared_ptr< Camera >& getPrimary(); std::shared_ptr< RenderCamera >& getPrimary();
void createPrimary();
std::shared_ptr< Camera > createCamera( vk::Extent2D extent ); static CameraManager& instance();
static std::shared_ptr< RenderCamera > createCamera( vk::Extent2D extent );
static std::shared_ptr< CameraViewpoint > createViewpoint( vk::Extent2D extent );
}; };
} // namespace fgl::engine } // namespace fgl::engine

View File

@@ -0,0 +1,240 @@
//
// Created by kj16609 on 9/23/25.
//
#include "CameraViewpoint.hpp"
#include "CameraInfo.hpp"
#include "RenderCamera.hpp"
#include "assets/model/Model.hpp"
namespace fgl::engine
{
void CameraViewpoint::updateMatrix()
{
const auto& [ pos, scale, rotation ] = m_transform;
const auto rotation_matrix { rotation.forcedQuat().mat() };
const glm::vec3 forward { rotation_matrix * glm::vec4( constants::WORLD_FORWARD, 0.0f ) };
const glm::vec3 camera_up { rotation_matrix * glm::vec4( -constants::WORLD_Z, 0.0f ) };
const WorldCoordinate center_pos { pos + forward };
m_view_matrix = Matrix< MatrixType::WorldToCamera >( glm::lookAt( pos.vec(), center_pos.vec(), camera_up ) );
m_inverse_view_matrix = glm::inverse( m_view_matrix );
updateFrustum();
}
void CameraViewpoint::updateFrustum()
{
m_last_frustum_pos = getPosition();
const Matrix< MatrixType::ModelToWorld > translation_matrix { frustumTranslationMatrix() };
m_frustum = translation_matrix * m_base_frustum;
}
constexpr descriptors::Descriptor camera_descriptor { 0,
vk::DescriptorType::eUniformBuffer,
vk::ShaderStageFlagBits::eAllGraphics };
inline static descriptors::DescriptorSetLayout camera_descriptor_set { 1, camera_descriptor };
memory::BufferSuballocation& CameraViewpoint::frameInfo( const FrameIndex i )
{
return m_camera_frame_info[ i ];
}
std::vector< std::unique_ptr< descriptors::DescriptorSet > > CameraViewpoint::createCameraDescriptors()
{
std::vector< std::unique_ptr< descriptors::DescriptorSet > > sets {};
sets.reserve( constants::MAX_FRAMES_IN_FLIGHT );
for ( std::uint8_t i = 0; i < constants::MAX_FRAMES_IN_FLIGHT; ++i )
{
auto set { camera_descriptor_set.create() };
set->bindUniformBuffer( 0, m_camera_frame_info[ i ] );
set->update();
set->setName( std::format( "Viewpoint {} descriptor set {}", m_viewpoint_idx, i ) );
sets.emplace_back( std::move( set ) );
}
return sets;
}
using namespace fgl::literals::size_literals;
PerFrameArray< std::unique_ptr< descriptors::DescriptorSet > > createDrawCommandsDescriptors(
PerFrameArray< DeviceVector< vk::DrawIndexedIndirectCommand > >& gpu_draw_commands,
PerFrameArray< DeviceVector< InstanceRenderInfo > >& per_vertex_info )
{
PerFrameArray< std::unique_ptr< descriptors::DescriptorSet > > descriptors {};
for ( std::uint16_t i = 0; i < gpu_draw_commands.size(); ++i )
{
auto& command_buffer { gpu_draw_commands[ i ] };
auto& per_vertex_buffer { per_vertex_info[ i ] };
auto descriptor { COMMANDS_SET.create() };
descriptor->bindStorageBuffer( 0, command_buffer );
descriptor->bindStorageBuffer( 1, per_vertex_buffer );
descriptor->update();
descriptor->setName( "Command Buffer + Vertex Buffer" );
descriptors[ i ] = std::move( descriptor );
}
return descriptors;
}
CameraViewpoint::CameraViewpoint( memory::Buffer& buffer, const vk::Extent2D extent ) :
m_extent( extent ),
m_camera_frame_info( buffer ),
m_draw_parameter_pool(
4_MiB,
vk::BufferUsageFlagBits::eIndirectBuffer | vk::BufferUsageFlagBits::eStorageBuffer,
vk::MemoryPropertyFlagBits::eDeviceLocal | vk::MemoryPropertyFlagBits::eHostVisible ),
m_gpu_draw_commands(
constructPerFrame< DeviceVector< vk::DrawIndexedIndirectCommand > >( m_draw_parameter_pool ) ),
m_generated_instance_info(
constructPerFrame< DeviceVector< InstanceRenderInfo > >( getModelBuffers().m_vertex_buffer ) ),
m_gpu_draw_cmds_desc( createDrawCommandsDescriptors( m_gpu_draw_commands, m_generated_instance_info ) ),
m_camera_info_descriptors( createCameraDescriptors() )
{
setFOV( m_fov_y );
}
Coordinate< CoordinateSpace::World > CameraViewpoint::getPosition() const
{
//Should maybe store the inverse view matrix
return WorldCoordinate( m_inverse_view_matrix[ 3 ] );
}
Matrix< MatrixType::WorldToScreen > CameraViewpoint::getProjectionViewMatrix() const
{
assert( m_projection_matrix != constants::MAT4_IDENTITY );
return m_projection_matrix * m_view_matrix;
}
glm::mat4 CameraViewpoint::getInverseViewMatrix() const
{
return glm::inverse( m_view_matrix );
}
FGL_FLATTEN_HOT void CameraViewpoint::
setView( const WorldCoordinate pos, const QuatRotation& rotation, const ViewMode mode )
{
switch ( mode )
{
case ViewMode::TaitBryan:
{
m_transform.translation = pos;
m_transform.rotation = rotation;
updateMatrix();
break;
}
case ViewMode::Euler:
[[fallthrough]];
{
//TODO: Implement
//view_matrix = glm::lookAt(position, position + );
}
default:
throw std::runtime_error( "Unimplemented view mode" );
}
updateFrustum();
}
void CameraViewpoint::setOrthographicProjection(
const float left, const float right, const float top, const float bottom, const float near, const float far )
{
m_projection_matrix = Matrix< MatrixType::CameraToScreen >( glm::ortho( left, right, bottom, top, near, far ) );
}
FGL_FLATTEN_HOT void CameraViewpoint::
setPerspectiveProjection( const float fovy, const float aspect, const float near, const float far )
{
m_projection_matrix = Matrix< MatrixType::CameraToScreen >( glm::perspective( fovy, aspect, near, far ) );
m_base_frustum = createFrustum( aspect, fovy, near, far );
}
void CameraViewpoint::setViewport( const vk::raii::CommandBuffer& command_buffer )
{
vk::Viewport viewport {};
viewport.x = 0.0f;
viewport.y = 0.0f;
const auto& [ width, height ] = m_extent;
viewport.width = static_cast< float >( width );
viewport.height = static_cast< float >( height );
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
const std::vector< vk::Viewport > viewports { viewport };
command_buffer.setViewport( 0, viewports );
}
void CameraViewpoint::setScissor( const vk::raii::CommandBuffer& command_buffer )
{
const vk::Rect2D scissor { { 0, 0 }, m_extent };
const std::vector< vk::Rect2D > scissors { scissor };
command_buffer.setScissor( 0, scissors );
}
void CameraViewpoint::setFOV( const float fov_y )
{
m_fov_y = fov_y;
setPerspectiveProjection( m_fov_y, aspectRatio(), constants::NEAR_PLANE, constants::FAR_PLANE );
}
float CameraViewpoint::aspectRatio() const
{
return static_cast< float >( m_extent.width ) / static_cast< float >( m_extent.height );
}
void CameraViewpoint::moveTo( const WorldTransform pos )
{
this->m_transform = pos;
}
void CameraViewpoint::updateInfo( const FrameIndex frame_index )
{
ZoneScoped;
updateMatrix();
CameraInfo current_camera_info { .projection = getProjectionMatrix(),
.view = getViewMatrix(),
.inverse_view = getInverseViewMatrix() };
m_camera_frame_info[ frame_index ] = current_camera_info;
}
void CameraViewpoint::setExtent( const vk::Extent2D extent )
{
m_extent = extent;
}
vk::Rect2D CameraViewpoint::scissor() const
{
return { { 0, 0 }, m_extent };
}
vk::Viewport CameraViewpoint::viewport() const
{
return { 0, 0, this->m_extent.width, this->m_extent.height, 0.0f, 1.0f };
}
descriptors::DescriptorSetLayout& CameraViewpoint::getDescriptorLayout()
{
return camera_descriptor_set;
}
} // namespace fgl::engine

View File

@@ -1,82 +1,37 @@
// //
// Created by kj16609 on 11/28/23. // Created by kj16609 on 9/23/25.
// //
#pragma once #pragma once
#include <vulkan/vulkan.hpp>
#pragma GCC diagnostic push #include "CameraInfo.hpp"
#pragma GCC diagnostic ignored "-Weffc++" #include "memory/buffers/HostSingleT.hpp"
#pragma GCC diagnostic ignored "-Wduplicated-branches" #include "memory/buffers/UniqueFrameSuballocation.hpp"
#define GLM_ENABLE_EXPERIMENTAL #include "primitives/Frustum.hpp"
#include <glm/glm.hpp> #include "primitives/Transform.hpp"
#include <glm/gtx/string_cast.hpp> #include "primitives/matricies/Matrix.hpp"
#pragma GCC diagnostic pop #include "rendering/PresentSwapChain.hpp"
#include "../primitives/rotation/QuatRotation.hpp"
#include "CompositeSwapchain.hpp"
#include "GBufferSwapchain.hpp"
#include "debug/Track.hpp"
#include "engine/descriptors/DescriptorSet.hpp"
#include "engine/memory/buffers/HostSingleT.hpp"
#include "engine/memory/buffers/UniqueFrameSuballocation.hpp"
#include "engine/primitives/Frustum.hpp"
#include "engine/primitives/Transform.hpp"
#include "engine/rendering/types.hpp"
namespace vk::raii
{
class CommandBuffer;
class RenderPass;
} // namespace vk::raii
namespace fgl::engine namespace fgl::engine
{ {
struct InstanceRenderInfo;
namespace descriptors namespace descriptors
{ {
class DescriptorSetLayout; class DescriptorSetLayout;
} class DescriptorSet;
class Image; } // namespace descriptors
struct FrameInfo;
class GBufferRenderer;
struct CameraInfo; class CameraViewpoint
class Camera;
FrustumBase createFrustum( float aspect, float fovy, float near, float far );
using CameraIDX = std::uint8_t;
class Camera
{ {
inline static CameraIDX m_camera_counter { 0 }; protected:
debug::Track< "CPU", "Camera" > m_camera {};
vk::Extent2D m_target_extent;
std::unique_ptr< CompositeSwapchain > m_composite_swapchain;
std::unique_ptr< GBufferSwapchain > m_gbuffer_swapchain;
//TODO: Move to deffered deleter
std::queue< std::unique_ptr< CompositeSwapchain > > m_old_composite_swapchain {};
std::queue< std::unique_ptr< GBufferSwapchain > > m_old_gbuffer_swapchain {};
std::shared_ptr< GBufferRenderer > m_camera_renderer;
//! True if the camera is active and to be rendered
bool m_active { true };
//! If true, The camera's swapchain is to be destroyed in order to preserve memory.
//! This is here to allow us to set a camera cold when it's not likely to be used soon
bool m_cold { false };
// Const is acceptable, Since this value should never change. EVER
const CameraIDX m_camera_idx { m_camera_counter++ };
vk::Extent2D m_extent;
Matrix< MatrixType::CameraToScreen > m_projection_matrix { 1.0f }; Matrix< MatrixType::CameraToScreen > m_projection_matrix { 1.0f };
Matrix< MatrixType::WorldToCamera > m_view_matrix { 1.0f }; Matrix< MatrixType::WorldToCamera > m_view_matrix { 1.0f };
glm::mat4 m_inverse_view_matrix { 1.0f }; glm::mat4 m_inverse_view_matrix { 1.0f };
bool m_ortho { false };
//! Frustum of the camera in model space relative to the camera //! 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 //! @note Must be transformed by the inverse view matrix to get the frustum in world space
@@ -86,58 +41,62 @@ namespace fgl::engine
WorldTransform m_transform {}; WorldTransform m_transform {};
float m_fov_y { glm::radians( 90.0f ) }; float& x { m_transform.translation.x };
float& y { m_transform.translation.y };
float& z { m_transform.translation.z };
PerFrameSuballocation< HostSingleT< CameraInfo > > m_camera_frame_info; PerFrameSuballocation< HostSingleT< CameraInfo > > m_camera_frame_info;
std::uint32_t m_viewpoint_idx { 0 };
memory::Buffer m_draw_parameter_pool;
public:
PerFrameArray< DeviceVector< vk::DrawIndexedIndirectCommand > > m_gpu_draw_commands;
PerFrameArray< DeviceVector< InstanceRenderInfo > > m_generated_instance_info;
PerFrameArray< std::unique_ptr< descriptors::DescriptorSet > > m_gpu_draw_cmds_desc;
memory::BufferSuballocation& frameInfo( FrameIndex i );
// Camera info is expected at binding 0 // Camera info is expected at binding 0
std::vector< std::unique_ptr< descriptors::DescriptorSet > > createCameraDescriptors(); std::vector< std::unique_ptr< descriptors::DescriptorSet > > createCameraDescriptors();
std::vector< std::unique_ptr< descriptors::DescriptorSet > > m_camera_info_descriptors; std::vector< std::unique_ptr< descriptors::DescriptorSet > > m_camera_info_descriptors;
std::string m_name { "Unnamed Camera" }; private:
[[nodiscard]] Matrix< MatrixType::ModelToWorld > frustumTranslationMatrix() const; enum ViewMode
{
void updateFrustum(); Euler,
TaitBryan
#ifdef EXPOSE_CAMERA_TESTS };
//Constructor for tests
Camera( vk::Extent2D test_extent ) : m_target_extent( test_extent ) {}
#endif
Camera( vk::Extent2D extent, memory::Buffer& buffer, const std::shared_ptr< GBufferRenderer >& renderer );
friend class CameraManager;
public: public:
float& x { m_transform.translation.x }; float m_fov_y { glm::radians( 90.0f ) };
float& y { m_transform.translation.y };
float& z { m_transform.translation.z };
FGL_DELETE_ALL_RO5( Camera ); FGL_DELETE_ALL_RO5( CameraViewpoint );
~Camera(); explicit CameraViewpoint( memory::Buffer& buffer, vk::Extent2D extent = { 1920, 1080 } );
[[nodiscard]] CameraIDX getIDX() const; [[nodiscard]] Coordinate< CoordinateSpace::World > getPosition() const;
[[nodiscard]] const std::string& getName() const; WorldTransform& getTransform() { return m_transform; }
void setExtent( vk::Extent2D extent );
[[nodiscard]] QuatRotation getRotation() const { return m_transform.rotation.forcedQuat(); } [[nodiscard]] QuatRotation getRotation() const { return m_transform.rotation.forcedQuat(); }
[[nodiscard]] const WorldTransform& getTransform() const { return m_transform; } [[nodiscard]] const WorldTransform& getTransform() const { return m_transform; }
WorldTransform& getTransform() { return m_transform; }
WorldCoordinate getFrustumPosition() const;
[[nodiscard]] const FrustumBase& getBaseFrustum() const { return m_base_frustum; } [[nodiscard]] const FrustumBase& getBaseFrustum() const { return m_base_frustum; }
//! Returns the frustum of the camera in world space //! Returns the frustum of the camera in world space
[[nodiscard]] const Frustum& getFrustumBounds() const { return m_frustum; } [[nodiscard]] const Frustum& getFrustumBounds() const { return m_frustum; }
[[nodiscard]] WorldCoordinate getFrustumPosition() const;
void updateMatrix();
void updateFrustum();
[[nodiscard]] const Matrix< MatrixType::CameraToScreen >& getProjectionMatrix() const [[nodiscard]] const Matrix< MatrixType::CameraToScreen >& getProjectionMatrix() const
{ {
return m_projection_matrix; return m_projection_matrix;
@@ -148,20 +107,13 @@ namespace fgl::engine
[[nodiscard]] Matrix< MatrixType::WorldToScreen > getProjectionViewMatrix() const; [[nodiscard]] Matrix< MatrixType::WorldToScreen > getProjectionViewMatrix() const;
[[nodiscard]] glm::mat4 getInverseViewMatrix() const; [[nodiscard]] glm::mat4 getInverseViewMatrix() const;
[[nodiscard]] Matrix< MatrixType::ModelToWorld > frustumTranslationMatrix() const;
enum ViewMode
{
Euler,
TaitBryan
};
void setView( WorldCoordinate pos, const QuatRotation& rotation, ViewMode mode = TaitBryan ); void setView( WorldCoordinate pos, const QuatRotation& rotation, ViewMode mode = TaitBryan );
void setOrthographicProjection( float left, float right, float top, float bottom, float near, float far ); void setOrthographicProjection( float left, float right, float top, float bottom, float near, float far );
void setPerspectiveProjection( float fovy, float aspect, float near, float far ); void setPerspectiveProjection( float fovy, float aspect, float near, float far );
[[nodiscard]] Coordinate< CoordinateSpace::World > getPosition() const; FGL_FORCE_INLINE NormalVector getLeft() const { return -getRight(); }
FGL_FORCE_INLINE NormalVector getUp() const { return -getDown(); }
FGL_FORCE_INLINE NormalVector getRight() const FGL_FORCE_INLINE NormalVector getRight() const
{ {
@@ -173,45 +125,30 @@ namespace fgl::engine
return -NormalVector( glm::vec3( m_inverse_view_matrix[ 2 ] ) ); return -NormalVector( glm::vec3( m_inverse_view_matrix[ 2 ] ) );
} }
FGL_FORCE_INLINE NormalVector getLeft() const { return -getRight(); }
FGL_FORCE_INLINE NormalVector getBackward() const { return -getForward(); } FGL_FORCE_INLINE NormalVector getBackward() const { return -getForward(); }
FGL_FORCE_INLINE NormalVector getUp() const { return -getDown(); }
FGL_FORCE_INLINE NormalVector getDown() const FGL_FORCE_INLINE NormalVector getDown() const
{ {
return NormalVector( glm::vec3( m_inverse_view_matrix[ 1 ] ) ); return NormalVector( glm::vec3( m_inverse_view_matrix[ 1 ] ) );
} }
//! Updates the required info for rendering
void updateInfo( FrameIndex frame_index );
descriptors::DescriptorSet& getDescriptor( FrameIndex index );
void setFOV( float fov_y );
//! Performs the render pass for this camera
void pass( FrameInfo& frame_info );
[[nodiscard]] GBufferSwapchain& getSwapchain() const;
[[nodiscard]] CompositeSwapchain& getCompositeSwapchain() const;
void setViewport( const vk::raii::CommandBuffer& command_buffer ); void setViewport( const vk::raii::CommandBuffer& command_buffer );
void setScissor( const vk::raii::CommandBuffer& command_buffer ); void setScissor( const vk::raii::CommandBuffer& command_buffer );
void setFOV( float fov_y );
[[nodiscard]] float aspectRatio() const;
void remakeSwapchain( vk::Extent2D extent ); void moveTo( const WorldTransform pos );
void setName( std::string_view str ); //! Updates the required info for rendering
void updateInfo( FrameIndex frame_index );
float aspectRatio() const; void setExtent( vk::Extent2D extent );
void copyOutput( const vk::raii::CommandBuffer& command_buffer, FrameIndex frame_index, Image& target ); vk::Rect2D scissor() const;
void updateMatrix(); vk::Viewport viewport() const;
static descriptors::DescriptorSetLayout& getDescriptorLayout(); static descriptors::DescriptorSetLayout& getDescriptorLayout();
#ifdef EXPOSE_CAMERA_TESTS
Camera CREATE_TESTING_CAMERA() { return { { 1920, 1080 } }; }
#endif
}; };
} // namespace fgl::engine
} // namespace fgl::engine

View File

@@ -3,9 +3,10 @@
// //
#include "GBufferCompositor.hpp" #include "GBufferCompositor.hpp"
#include "Camera.hpp"
#include "CompositeSwapchain.hpp" #include "CompositeSwapchain.hpp"
#include "GBufferSwapchain.hpp" #include "GBufferSwapchain.hpp"
#include "RenderCamera.hpp"
#include "ShadowMap.hpp"
#include "engine/rendering/pipelines/v2/AttachmentBuilder.hpp" #include "engine/rendering/pipelines/v2/AttachmentBuilder.hpp"
namespace fgl::engine namespace fgl::engine
@@ -56,7 +57,8 @@ namespace fgl::engine
PipelineBuilder builder { 0 }; PipelineBuilder builder { 0 };
builder.addDescriptorSet( gbuffer_set ); builder.addDescriptorSet( gbuffer_set );
builder.addDescriptorSet( Camera::getDescriptorLayout() ); builder.addDescriptorSet( RenderCamera::getDescriptorLayout() );
builder.addDescriptorSet( ShadowMap::getDescriptorLayout() );
builder.addColorAttachment().setFormat( pickColorFormat() ).finish(); builder.addColorAttachment().setFormat( pickColorFormat() ).finish();
@@ -73,7 +75,8 @@ namespace fgl::engine
m_pipeline->setDebugName( "Composition pipeline" ); m_pipeline->setDebugName( "Composition pipeline" );
} }
void GBufferCompositor::composite( CommandBuffer& command_buffer, Camera& camera, const FrameIndex frame_index ) void GBufferCompositor::
composite( CommandBuffer& command_buffer, RenderCamera& camera, const FrameIndex frame_index )
{ {
auto& gbuffer_swapchain { camera.getSwapchain() }; auto& gbuffer_swapchain { camera.getSwapchain() };
auto& composite_swapchain { camera.getCompositeSwapchain() }; auto& composite_swapchain { camera.getCompositeSwapchain() };

View File

@@ -5,7 +5,7 @@
#include <vulkan/vulkan_raii.hpp> #include <vulkan/vulkan_raii.hpp>
#include "Camera.hpp" #include "RenderCamera.hpp"
#include "engine/rendering/pipelines/v2/Pipeline.hpp" #include "engine/rendering/pipelines/v2/Pipeline.hpp"
#include "engine/rendering/types.hpp" #include "engine/rendering/types.hpp"
#include "engine/systems/composition/Control.hpp" #include "engine/systems/composition/Control.hpp"
@@ -48,7 +48,7 @@ namespace fgl::engine
GBufferCompositor( CompositeFlags flags = CompositeFlagBits_Standard ); GBufferCompositor( CompositeFlags flags = CompositeFlagBits_Standard );
void composite( CommandBuffer& command_buffer, Camera& camera, FrameIndex frame_index ); void composite( CommandBuffer& command_buffer, RenderCamera& camera, FrameIndex frame_index );
inline void switchMode( const CompositeFlags flags ) { m_flags = flags; } inline void switchMode( const CompositeFlags flags ) { m_flags = flags; }
}; };

View File

@@ -73,7 +73,8 @@ namespace fgl::engine
camera_swapchain.transitionImages( command_buffer, GBufferSwapchain::FINAL, frame_info.in_flight_idx ); camera_swapchain.transitionImages( command_buffer, GBufferSwapchain::FINAL, frame_info.in_flight_idx );
m_compositor.composite( command_buffer, *frame_info.camera, frame_info.in_flight_idx ); m_compositor
.composite( command_buffer, *static_cast< RenderCamera* >( frame_info.camera ), frame_info.in_flight_idx );
} }
} // namespace fgl::engine } // namespace fgl::engine

View File

@@ -2,13 +2,12 @@
// Created by kj16609 on 11/28/23. // Created by kj16609 on 11/28/23.
// //
#include "Camera.hpp" #include "RenderCamera.hpp"
#define GLM_ENABLE_EXPERIMENTAL #define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/string_cast.hpp> #include <glm/gtx/string_cast.hpp>
#include <tracy/Tracy.hpp> #include <tracy/Tracy.hpp>
#include "CameraInfo.hpp"
#include "GBufferRenderer.hpp" #include "GBufferRenderer.hpp"
#include "GBufferSwapchain.hpp" #include "GBufferSwapchain.hpp"
#include "engine/debug/timing/FlameGraph.hpp" #include "engine/debug/timing/FlameGraph.hpp"
@@ -16,61 +15,67 @@
namespace fgl::engine namespace fgl::engine
{ {
Matrix< MatrixType::WorldToScreen > Camera::getProjectionViewMatrix() const FrustumBase createFrustum( const float aspect, const float fov_y, const float near, const float far )
{ {
assert( m_projection_matrix != constants::MAT4_IDENTITY ); const Plane< CoordinateSpace::Model > near_plane { ModelCoordinate( constants::WORLD_FORWARD * near ),
return m_projection_matrix * m_view_matrix; NormalVector( constants::WORLD_FORWARD ) };
const Plane< CoordinateSpace::Model > far_plane { ModelCoordinate( constants::WORLD_FORWARD * far ),
NormalVector( -constants::WORLD_FORWARD ) };
const float half_height { far * glm::tan( fov_y / 2.0f ) };
const float half_width { half_height * aspect };
const ModelCoordinate far_forward { constants::WORLD_FORWARD * far };
const ModelCoordinate right_half { constants::WORLD_RIGHT * half_width };
const Vector right_forward { ( far_forward + right_half ).vec() };
const Vector left_forward { ( far_forward - right_half ).vec() };
const Plane< CoordinateSpace::Model > right_plane {
ModelCoordinate( constants::WORLD_CENTER ),
NormalVector( glm::cross( right_forward.vec(), constants::WORLD_Z_NEG ) )
};
const Plane< CoordinateSpace::Model > left_plane {
ModelCoordinate( constants::WORLD_CENTER ),
NormalVector( glm::cross( left_forward.vec(), constants::WORLD_Z ) )
};
const ModelCoordinate top_half { constants::WORLD_Z * half_height };
const Vector top_forward { ( far_forward + top_half ).vec() };
const Vector bottom_forward { ( far_forward - top_half ).vec() };
const Plane< CoordinateSpace::Model > top_plane {
ModelCoordinate( constants::WORLD_CENTER ),
NormalVector( glm::cross( top_forward.vec(), constants::WORLD_RIGHT ) )
};
const Plane< CoordinateSpace::Model > bottom_plane {
ModelCoordinate( constants::WORLD_CENTER ),
NormalVector( glm::cross( bottom_forward.vec(), -constants::WORLD_RIGHT ) )
};
return { near_plane,
far_plane,
top_plane,
bottom_plane,
right_plane,
left_plane,
Coordinate< CoordinateSpace::Model >( constants::WORLD_CENTER ) };
} }
glm::mat4 Camera::getInverseViewMatrix() const const std::string& RenderCamera::getName() const
{ {
return glm::inverse( m_view_matrix ); return m_name;
} }
void Camera::setOrthographicProjection( float left, float right, float top, float bottom, float near, float far ) descriptors::DescriptorSet& RenderCamera::getDescriptor( const FrameIndex index )
{
m_projection_matrix = Matrix< MatrixType::CameraToScreen >( glm::ortho( left, right, bottom, top, near, far ) );
//TODO: Figure out frustum culling for orthographic projection. (If we even wanna use it)
}
FGL_FLATTEN_HOT void Camera::
setPerspectiveProjection( const float fovy, const float aspect, const float near, const float far )
{
m_projection_matrix = Matrix< MatrixType::CameraToScreen >( glm::perspective( fovy, aspect, near, far ) );
m_base_frustum = createFrustum( aspect, fovy, near, far );
}
Coordinate< CoordinateSpace::World > Camera::getPosition() const
{
//Should maybe store the inverse view matrix
return WorldCoordinate( m_inverse_view_matrix[ 3 ] );
}
void Camera::updateInfo( const FrameIndex frame_index )
{
ZoneScoped;
CameraInfo current_camera_info { .projection = getProjectionMatrix(),
.view = getViewMatrix(),
.inverse_view = getInverseViewMatrix() };
m_camera_frame_info[ frame_index ] = current_camera_info;
}
descriptors::DescriptorSet& Camera::getDescriptor( const FrameIndex index )
{ {
assert( index < m_camera_info_descriptors.size() ); assert( index < m_camera_info_descriptors.size() );
return *m_camera_info_descriptors[ index ]; return *m_camera_info_descriptors[ index ];
} }
void Camera::setFOV( const float fov_y ) void RenderCamera::pass( FrameInfo& frame_info )
{
m_fov_y = fov_y;
setPerspectiveProjection( m_fov_y, aspectRatio(), constants::NEAR_PLANE, constants::FAR_PLANE );
}
void Camera::pass( FrameInfo& frame_info )
{ {
ZoneScopedN( "Camera::pass" ); ZoneScopedN( "Camera::pass" );
auto timer = debug::timing::push( "Camera" ); auto timer = debug::timing::push( "Camera" );
@@ -98,45 +103,20 @@ namespace fgl::engine
frame_info.camera = nullptr; frame_info.camera = nullptr;
} }
GBufferSwapchain& Camera::getSwapchain() const GBufferSwapchain& RenderCamera::getSwapchain() const
{ {
return *m_gbuffer_swapchain; return *m_gbuffer_swapchain;
} }
CompositeSwapchain& Camera::getCompositeSwapchain() const CompositeSwapchain& RenderCamera::getCompositeSwapchain() const
{ {
return *m_composite_swapchain; return *m_composite_swapchain;
} }
void Camera::setViewport( const vk::raii::CommandBuffer& command_buffer ) void RenderCamera::remakeSwapchain( vk::Extent2D extent )
{ {
vk::Viewport viewport {}; setExtent( extent );
viewport.x = 0.0f; this->setPerspectiveProjection( m_fov_y, this->aspectRatio(), constants::NEAR_PLANE, constants::FAR_PLANE );
viewport.y = 0.0f;
const auto& [ width, height ] = m_gbuffer_swapchain->getExtent();
viewport.width = static_cast< float >( width );
viewport.height = static_cast< float >( height );
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
const std::vector< vk::Viewport > viewports { viewport };
command_buffer.setViewport( 0, viewports );
}
void Camera::setScissor( const vk::raii::CommandBuffer& command_buffer )
{
const vk::Rect2D scissor { { 0, 0 }, m_gbuffer_swapchain->getExtent() };
const std::vector< vk::Rect2D > scissors { scissor };
command_buffer.setScissor( 0, scissors );
}
void Camera::remakeSwapchain( vk::Extent2D extent )
{
this->setPerspectiveProjection( m_fov_y, aspectRatio(), constants::NEAR_PLANE, constants::FAR_PLANE );
log::debug( "Camera swapchain recreated" ); log::debug( "Camera swapchain recreated" );
@@ -148,20 +128,22 @@ namespace fgl::engine
m_composite_swapchain = std::make_unique< CompositeSwapchain >( extent ); m_composite_swapchain = std::make_unique< CompositeSwapchain >( extent );
m_gbuffer_swapchain = std::make_unique< GBufferSwapchain >( extent ); m_gbuffer_swapchain = std::make_unique< GBufferSwapchain >( extent );
CameraViewpoint::setExtent( extent );
} }
void Camera::setName( const std::string_view str ) void RenderCamera::setName( const std::string_view str )
{ {
m_name = str; m_name = str;
} }
float Camera::aspectRatio() const float RenderCamera::aspectRatio() const
{ {
return m_gbuffer_swapchain->getAspectRatio(); return m_gbuffer_swapchain->getAspectRatio();
} }
void Camera:: void RenderCamera::
copyOutput( const vk::raii::CommandBuffer& command_buffer, const FrameIndex frame_index, Image& target ) copyOutput( const vk::raii::CommandBuffer& command_buffer, const FrameIndex frame_index, Image& target ) const
{ {
assert( m_gbuffer_swapchain->getExtent() == target.getExtent() ); assert( m_gbuffer_swapchain->getExtent() == target.getExtent() );
@@ -271,175 +253,39 @@ namespace fgl::engine
{ barrier_to_source } ); { barrier_to_source } );
} }
void Camera::updateMatrix() WorldCoordinate CameraViewpoint::getFrustumPosition() const
{ {
const auto& [ pos, scale, rotation ] = m_transform; return m_last_frustum_pos;
const auto rotation_matrix { rotation.forcedQuat().mat() };
const glm::vec3 forward { rotation_matrix * glm::vec4( constants::WORLD_FORWARD, 0.0f ) };
const glm::vec3 camera_up { rotation_matrix * glm::vec4( -constants::WORLD_Z, 0.0f ) };
const WorldCoordinate center_pos { pos + forward };
m_view_matrix = Matrix< MatrixType::WorldToCamera >( glm::lookAt( pos.vec(), center_pos.vec(), camera_up ) );
m_inverse_view_matrix = glm::inverse( m_view_matrix );
updateFrustum();
} }
FGL_FLATTEN_HOT void Camera::setView( const WorldCoordinate pos, const QuatRotation& rotation, const ViewMode mode ) Matrix< MatrixType::ModelToWorld > CameraViewpoint::frustumTranslationMatrix() const
{ {
switch ( mode ) return m_transform.mat();
{
case ViewMode::TaitBryan:
{
m_transform.translation = pos;
m_transform.rotation = rotation;
updateMatrix();
break;
}
case ViewMode::Euler:
[[fallthrough]];
{
//TODO: Implement
//view_matrix = glm::lookAt(position, position + );
}
default:
throw std::runtime_error( "Unimplemented view mode" );
}
updateFrustum();
} }
void Camera::updateFrustum() RenderCamera::RenderCamera(
{
m_last_frustum_pos = getPosition();
const Matrix< MatrixType::ModelToWorld > translation_matrix { frustumTranslationMatrix() };
m_frustum = translation_matrix * m_base_frustum;
}
const std::string& Camera::getName() const
{
return m_name;
}
constexpr descriptors::Descriptor camera_descriptor { 0,
vk::DescriptorType::eUniformBuffer,
vk::ShaderStageFlagBits::eAllGraphics };
inline static descriptors::DescriptorSetLayout camera_descriptor_set { 1, camera_descriptor };
descriptors::DescriptorSetLayout& Camera::getDescriptorLayout()
{
return camera_descriptor_set;
}
Camera::Camera(
const vk::Extent2D extent, memory::Buffer& buffer, const std::shared_ptr< GBufferRenderer >& renderer ) : const vk::Extent2D extent, memory::Buffer& buffer, const std::shared_ptr< GBufferRenderer >& renderer ) :
CameraViewpoint( buffer, extent ),
m_target_extent( extent ), m_target_extent( extent ),
m_composite_swapchain( std::make_unique< CompositeSwapchain >( m_target_extent ) ), m_composite_swapchain( std::make_unique< CompositeSwapchain >( m_target_extent ) ),
m_gbuffer_swapchain( std::make_unique< GBufferSwapchain >( m_target_extent ) ), m_gbuffer_swapchain( std::make_unique< GBufferSwapchain >( m_target_extent ) ),
m_camera_renderer( renderer ), m_camera_renderer( renderer )
m_camera_frame_info( buffer ),
m_camera_info_descriptors( createCameraDescriptors() )
{ {
FGL_ASSERT( renderer, "Camera renderer is null" ); FGL_ASSERT( renderer, "Camera renderer is null" );
this->setPerspectiveProjection( m_fov_y, aspectRatio(), constants::NEAR_PLANE, constants::FAR_PLANE ); this->setPerspectiveProjection( m_fov_y, aspectRatio(), constants::NEAR_PLANE, constants::FAR_PLANE );
this->setView( WorldCoordinate( constants::CENTER ), QuatRotation( 0.0f, 0.0f, 0.0f ) ); this->setView( WorldCoordinate( constants::CENTER ), QuatRotation( 0.0f, 0.0f, 0.0f ) );
} }
std::vector< std::unique_ptr< descriptors::DescriptorSet > > Camera::createCameraDescriptors() RenderCamera::~RenderCamera() = default;
{
std::vector< std::unique_ptr< descriptors::DescriptorSet > > sets {};
sets.reserve( constants::MAX_FRAMES_IN_FLIGHT );
for ( std::uint8_t i = 0; i < constants::MAX_FRAMES_IN_FLIGHT; ++i ) CameraIDX RenderCamera::getIDX() const
{
auto set { camera_descriptor_set.create() };
set->bindUniformBuffer( 0, m_camera_frame_info[ i ] );
set->update();
set->setName( std::format( "Camera {} descriptor set {}", m_camera_idx, i ) );
sets.emplace_back( std::move( set ) );
}
return sets;
}
void Camera::setExtent( const vk::Extent2D extent )
{
m_target_extent = extent;
}
FrustumBase createFrustum( const float aspect, const float fov_y, const float near, const float far )
{
const Plane< CoordinateSpace::Model > near_plane { ModelCoordinate( constants::WORLD_FORWARD * near ),
NormalVector( constants::WORLD_FORWARD ) };
const Plane< CoordinateSpace::Model > far_plane { ModelCoordinate( constants::WORLD_FORWARD * far ),
NormalVector( -constants::WORLD_FORWARD ) };
const float half_height { far * glm::tan( fov_y / 2.0f ) };
const float half_width { half_height * aspect };
const ModelCoordinate far_forward { constants::WORLD_FORWARD * far };
const ModelCoordinate right_half { constants::WORLD_RIGHT * half_width };
const Vector right_forward { ( far_forward + right_half ).vec() };
const Vector left_forward { ( far_forward - right_half ).vec() };
const Plane< CoordinateSpace::Model > right_plane {
ModelCoordinate( constants::WORLD_CENTER ),
NormalVector( glm::cross( right_forward.vec(), constants::WORLD_Z_NEG ) )
};
const Plane< CoordinateSpace::Model > left_plane {
ModelCoordinate( constants::WORLD_CENTER ),
NormalVector( glm::cross( left_forward.vec(), constants::WORLD_Z ) )
};
const ModelCoordinate top_half { constants::WORLD_Z * half_height };
const Vector top_forward { ( far_forward + top_half ).vec() };
const Vector bottom_forward { ( far_forward - top_half ).vec() };
const Plane< CoordinateSpace::Model > top_plane {
ModelCoordinate( constants::WORLD_CENTER ),
NormalVector( glm::cross( top_forward.vec(), constants::WORLD_RIGHT ) )
};
const Plane< CoordinateSpace::Model > bottom_plane {
ModelCoordinate( constants::WORLD_CENTER ),
NormalVector( glm::cross( bottom_forward.vec(), -constants::WORLD_RIGHT ) )
};
return { near_plane,
far_plane,
top_plane,
bottom_plane,
right_plane,
left_plane,
Coordinate< CoordinateSpace::Model >( constants::WORLD_CENTER ) };
}
Matrix< MatrixType::ModelToWorld > Camera::frustumTranslationMatrix() const
{
return m_transform.mat();
}
WorldCoordinate Camera::getFrustumPosition() const
{
return m_last_frustum_pos;
}
Camera::~Camera()
{}
CameraIDX Camera::getIDX() const
{ {
return m_camera_idx; return m_camera_idx;
} }
void RenderCamera::setExtent( const vk::Extent2D extent )
{
m_target_extent = extent;
}
} // namespace fgl::engine } // namespace fgl::engine

View File

@@ -0,0 +1,110 @@
//
// Created by kj16609 on 11/28/23.
//
#pragma once
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wduplicated-branches"
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
#include <glm/gtx/string_cast.hpp>
#pragma GCC diagnostic pop
#include "CameraViewpoint.hpp"
#include "CompositeSwapchain.hpp"
#include "GBufferSwapchain.hpp"
#include "debug/Track.hpp"
#include "engine/descriptors/DescriptorSet.hpp"
#include "engine/memory/buffers/HostSingleT.hpp"
#include "engine/memory/buffers/UniqueFrameSuballocation.hpp"
#include "engine/primitives/Frustum.hpp"
#include "engine/rendering/types.hpp"
namespace vk::raii
{
class CommandBuffer;
class RenderPass;
} // namespace vk::raii
namespace fgl::engine
{
namespace descriptors
{
class DescriptorSetLayout;
}
class Image;
struct FrameInfo;
class GBufferRenderer;
struct CameraInfo;
class RenderCamera;
FrustumBase createFrustum( float aspect, float fovy, float near, float far );
using CameraIDX = std::uint8_t;
class RenderCamera final : public CameraViewpoint
{
inline static CameraIDX m_camera_counter { 0 };
debug::Track< "CPU", "Camera" > m_camera {};
vk::Extent2D m_target_extent;
std::unique_ptr< CompositeSwapchain > m_composite_swapchain;
std::unique_ptr< GBufferSwapchain > m_gbuffer_swapchain;
//TODO: Move to deffered deleter
std::queue< std::unique_ptr< CompositeSwapchain > > m_old_composite_swapchain {};
std::queue< std::unique_ptr< GBufferSwapchain > > m_old_gbuffer_swapchain {};
std::shared_ptr< GBufferRenderer > m_camera_renderer;
//! True if the camera is active and to be rendered
bool m_active { true };
//! If true, The camera's swapchain is to be destroyed to preserve memory.
//! This is here to allow us to set a camera cold when it's not likely to be used soon
bool m_cold { false };
// Const is acceptable, Since this value should never change. EVER
const CameraIDX m_camera_idx { m_camera_counter++ };
std::string m_name { "Unnamed Camera" };
RenderCamera( vk::Extent2D extent, memory::Buffer& buffer, const std::shared_ptr< GBufferRenderer >& renderer );
friend class CameraManager;
public:
FGL_DELETE_ALL_RO5( RenderCamera );
~RenderCamera();
[[nodiscard]] CameraIDX getIDX() const;
[[nodiscard]] const std::string& getName() const;
descriptors::DescriptorSet& getDescriptor( FrameIndex index );
void setExtent( vk::Extent2D extent );
//! Performs the render pass for this camera
void pass( FrameInfo& frame_info );
[[nodiscard]] GBufferSwapchain& getSwapchain() const;
[[nodiscard]] CompositeSwapchain& getCompositeSwapchain() const;
void remakeSwapchain( vk::Extent2D extent );
void setName( std::string_view str );
[[nodiscard]] float aspectRatio() const;
void copyOutput( const vk::raii::CommandBuffer& command_buffer, FrameIndex frame_index, Image& target ) const;
};
} // namespace fgl::engine

View File

@@ -0,0 +1,167 @@
//
// Created by kj16609 on 9/23/25.
//
#include "ShadowMap.hpp"
#include "CameraManager.hpp"
#include "assets/model/Model.hpp"
#include "assets/model/ModelVertex.hpp"
#include "debug/timing/FlameGraph.hpp"
#include "rendering/pipelines/v2/Pipeline.hpp"
#include "rendering/pipelines/v2/PipelineBuilder.hpp"
namespace fgl::engine
{
std::shared_ptr< Swapchain > createDepthSwapchain( const vk::Extent2D extent )
{
std::vector< SwapchainImageInfo > swapchain_images {
{ .m_format = { .m_canidates = { vk::Format::eD32Sfloat,
vk::Format::eD32SfloatS8Uint,
vk::Format::eD24UnormS8Uint },
.m_usage =
vk::ImageUsageFlagBits::eDepthStencilAttachment | vk::ImageUsageFlagBits::eSampled,
.m_features = vk::FormatFeatureFlagBits::eDepthStencilAttachment },
.m_inital_layout = vk::ImageLayout::eUndefined,
.m_final_layout = vk::ImageLayout::eDepthReadOnlyOptimal,
.m_extent = extent,
.m_name = "Shadowmap Depth" }
};
return std::make_shared< Swapchain >( std::move( swapchain_images ) );
}
constexpr descriptors::Descriptor camera_descriptor { 0,
vk::DescriptorType::eUniformBuffer,
vk::ShaderStageFlagBits::eAllGraphics };
// 2d sampler
constexpr descriptors::Descriptor shadowmap_descriptor { 1,
vk::DescriptorType::eSampledImage,
vk::ShaderStageFlagBits::eFragment };
inline static descriptors::DescriptorSetLayout shadowmap_descriptor_set { 2,
camera_descriptor,
shadowmap_descriptor };
PerFrameArray< std::unique_ptr< descriptors::DescriptorSet > > ShadowMap::createShadowmapDescriptors() const
{
PerFrameArray< std::unique_ptr< descriptors::DescriptorSet > > data {};
for ( std::size_t i = 0; i < data.size(); ++i )
{
auto set { shadowmap_descriptor_set.create() };
set->bindImage(
shadowmap_descriptor.m_index,
*this->m_swapchain->depthView( i ),
vk::ImageLayout::eDepthReadOnlyOptimal );
set->bindUniformBuffer( camera_descriptor.m_index, this->m_camera->frameInfo( i ) );
set->update();
data[ i ] = std::move( set );
}
return data;
}
ShadowMap::ShadowMap( const UniversalRotation& direction, const vk::Extent2D extent ) :
m_swapchain( createDepthSwapchain( extent ) ),
m_direction( direction ),
m_camera( CameraManager::createViewpoint( extent ) ),
m_extent( extent ),
m_shadowmap_descriptor( createShadowmapDescriptors() )
{
PipelineBuilder builder { 0 };
builder.addDepthAttachment();
builder.addDescriptorSet( CameraViewpoint::getDescriptorLayout() );
builder.setVertexShader( Shader::loadVertex( "shaders/shadowmap.slang" ) );
builder.setFragmentShader( Shader::loadFragment( "shaders/shadowmap.slang" ) );
builder.setAttributeDescriptions( ModelVertex::getAttributeDescriptions() );
builder.setBindingDescriptions( ModelVertex::getBindingDescriptions() );
m_shadow_pipeline = builder.create();
m_shadow_pipeline->setDebugName( "Shadow pipeline" );
}
void ShadowMap::pass( FrameInfo info )
{
ZoneScopedN( "ShadowMap::pass" );
auto timer = debug::timing::push( "ShadowMap" );
info.camera = m_camera.get();
info.camera->updateInfo( info.in_flight_idx );
m_culling_system.pass( info );
auto& command_buffer { info.command_buffer.render_cb };
vk::RenderingInfo rendering_info {};
vk::RenderingAttachmentInfo depth_info {};
depth_info.setClearValue( vk::ClearDepthStencilValue( 1.0f, 0 ) );
depth_info.setLoadOp( vk::AttachmentLoadOp::eClear );
depth_info.setStoreOp( vk::AttachmentStoreOp::eStore );
depth_info.imageLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal;
depth_info.imageView = m_swapchain->depthView( info.in_flight_idx )->getVkView();
rendering_info.colorAttachmentCount = 0;
rendering_info.pColorAttachments = nullptr;
rendering_info.setRenderArea( { { 0, 0 }, this->m_extent } );
rendering_info.layerCount = 1;
rendering_info.setPDepthAttachment( &depth_info );
command_buffer->beginRendering( rendering_info );
command_buffer->setViewport( 0, { info.camera->viewport() } );
command_buffer->setScissor( 0, { info.camera->scissor() } );
m_shadow_pipeline->bind( command_buffer );
m_shadow_pipeline->bindDescriptor( command_buffer, info.getCameraDescriptor() );
auto& model_buffers { getModelBuffers() };
const std::vector< vk::Buffer > vert_buffers {
model_buffers.m_vertex_buffer->getVkBuffer(),
info.camera->m_generated_instance_info[ info.in_flight_idx ].getVkBuffer(),
};
command_buffer->bindVertexBuffers(
0, vert_buffers, { 0, info.camera->m_generated_instance_info[ info.in_flight_idx ].getOffset() } );
command_buffer->bindIndexBuffer( model_buffers.m_index_buffer->getVkBuffer(), 0, vk::IndexType::eUint32 );
const auto& commands { info.camera->m_gpu_draw_commands[ info.in_flight_idx ] };
command_buffer
->drawIndexedIndirect( commands.getVkBuffer(), commands.getOffset(), commands.size(), commands.stride() );
command_buffer->endRendering();
}
static std::vector< std::weak_ptr< ShadowMap > > shadowmaps {};
descriptors::DescriptorSetLayout& ShadowMap::getDescriptorLayout()
{
return shadowmap_descriptor_set;
}
std::shared_ptr< ShadowMap > createShadowmap( UniversalRotation direction )
{
constexpr int size { 1024 };
auto ptr { std::make_shared< ShadowMap >( direction, vk::Extent2D { size, size } ) };
shadowmaps.emplace_back( ptr );
return ptr;
}
std::vector< std::weak_ptr< ShadowMap > > getShadowmaps()
{
return shadowmaps;
}
} // namespace fgl::engine

View File

@@ -0,0 +1,55 @@
//
// Created by kj16609 on 9/23/25.
//
#pragma once
#include <vulkan/vulkan.hpp>
#include <memory>
#include "RenderCamera.hpp"
#include "Swapchain.hpp"
#include "primitives/rotation/UniversalRotation.hpp"
#include "systems/prerender/CullingSystem.hpp"
namespace fgl::engine
{
namespace gui
{
void drawShadowmaps( const FrameInfo& info );
}
struct CameraInfo;
class ShadowMap
{
std::shared_ptr< Swapchain > m_swapchain;
UniversalRotation m_direction;
std::shared_ptr< CameraViewpoint > m_camera;
std::unique_ptr< Pipeline > m_shadow_pipeline;
CullingSystem m_culling_system;
vk::Extent2D m_extent;
PerFrameArray< std::unique_ptr< descriptors::DescriptorSet > > createShadowmapDescriptors() const;
PerFrameArray< std::unique_ptr< descriptors::DescriptorSet > > m_shadowmap_descriptor;
public:
ShadowMap() = delete;
ShadowMap( const UniversalRotation& direction, vk::Extent2D extent );
void pass( FrameInfo info );
friend void gui::drawShadowmaps( const FrameInfo& info );
static descriptors::DescriptorSetLayout& getDescriptorLayout();
};
std::shared_ptr< ShadowMap > createShadowmap( UniversalRotation direction );
std::vector< std::weak_ptr< ShadowMap > > getShadowmaps();
} // namespace fgl::engine

View File

@@ -0,0 +1,80 @@
//
// Created by kj16609 on 9/23/25.
//
#include "Swapchain.hpp"
#include "assets/image/Image.hpp"
#include "assets/image/ImageView.hpp"
#include "assets/texture/Texture.hpp"
#include "constants.hpp"
#include "rendering/devices/Device.hpp"
#include "slang.h"
namespace fgl::engine
{
vk::Format SwapchainImageInfo::pickBestFormat() const
{
return Device::getInstance()
.findSupportedFormat( m_format.m_canidates, vk::ImageTiling::eOptimal, m_format.m_features );
}
SwapchainImageSet::SwapchainImageSet( const SwapchainImageInfo& info )
{
for ( int i = 0; i < constants::MAX_FRAMES_IN_FLIGHT; ++i )
{
auto image_itter { m_image.emplace_back(
std::make_shared< Image >(
info.m_extent,
info.pickBestFormat(),
info.m_format.m_usage,
info.m_inital_layout,
info.m_final_layout ) ) };
auto view_itter { m_view.emplace_back( image_itter->getView() ) };
image_itter->setName( std::format( "Swapchain image {}:{}", info.m_name, i ) );
}
}
std::shared_ptr< Texture > SwapchainImageSet::getTexture( const FrameIndex frame_index ) const
{
if ( m_texture.empty() ) m_texture.resize( constants::MAX_FRAMES_IN_FLIGHT );
if ( !m_texture[ frame_index ] )
{
Sampler default_sampler {};
m_texture[ frame_index ] =
std::make_shared< Texture >( m_image[ frame_index ], std::move( default_sampler ) );
}
return m_texture[ frame_index ];
}
std::shared_ptr< ImageView > Swapchain::depthView( const FrameIndex frame_index ) const
{
const SwapchainImageSet& set { m_depth.value() };
return set.m_view[ frame_index ];
}
std::shared_ptr< Image > Swapchain::depthImage( const FrameIndex frame_index ) const
{
return m_depth.value().m_image[ frame_index ];
}
std::shared_ptr< Texture > Swapchain::depthTexture( const FrameIndex frame_index ) const
{
return m_depth.value().getTexture( frame_index );
}
Swapchain::Swapchain( const std::vector< SwapchainImageInfo >& in )
{
for ( const SwapchainImageInfo& info : in )
{
if ( info.m_format.m_usage & vk::ImageUsageFlagBits::eDepthStencilAttachment )
m_depth.emplace( info );
else
m_swapchain_images.emplace_back( info );
}
}
} // namespace fgl::engine

View File

@@ -0,0 +1,69 @@
//
// Created by kj16609 on 9/23/25.
//
#pragma once
#include <vulkan/vulkan.hpp>
#include <memory>
#include <unordered_map>
#include <vector>
#include "FGL_DEFINES.hpp"
#include "assets/texture/Texture.hpp"
#include "rendering/types.hpp"
namespace fgl::engine
{
class Image;
class ImageView;
struct SwapchainImageInfo
{
struct
{
std::vector< vk::Format > m_canidates;
vk::ImageUsageFlags m_usage;
vk::FormatFeatureFlags m_features;
} m_format;
vk::ImageLayout m_inital_layout;
vk::ImageLayout m_final_layout;
vk::Extent2D m_extent;
std::string m_name;
[[nodiscard]] vk::Format pickBestFormat() const;
};
class SwapchainImageSet
{
std::vector< std::shared_ptr< Image > > m_image {};
std::vector< std::shared_ptr< ImageView > > m_view {};
mutable std::vector< std::shared_ptr< Texture > > m_texture {};
friend class Swapchain;
public:
SwapchainImageSet() = delete;
[[nodiscard]] SwapchainImageSet( const SwapchainImageInfo& info );
std::shared_ptr< Texture > getTexture( FrameIndex frame_index ) const;
};
class Swapchain
{
std::vector< SwapchainImageSet > m_swapchain_images {};
std::optional< SwapchainImageSet > m_depth {};
public:
[[nodiscard]] std::shared_ptr< ImageView > depthView( FrameIndex frame_index ) const;
[[nodiscard]] std::shared_ptr< Image > depthImage( FrameIndex frame_index ) const;
std::shared_ptr< Texture > depthTexture( FrameIndex frame_index ) const;
FGL_DELETE_ALL_RO5( Swapchain );
[[nodiscard]] explicit Swapchain( const std::vector< SwapchainImageInfo >& in );
};
} // namespace fgl::engine

View File

@@ -55,4 +55,6 @@ namespace fgl::engine::constants
constexpr glm::vec3 DEFAULT_SCALE { 1.0f }; constexpr glm::vec3 DEFAULT_SCALE { 1.0f };
constexpr glm::vec3 SUN_DIR { 0.0f, 0.0f, 1.0f };
} // namespace fgl::engine::constants } // namespace fgl::engine::constants

View File

@@ -9,7 +9,15 @@
namespace fgl::engine::descriptors namespace fgl::engine::descriptors
{ {
vk::raii::DescriptorPool createPool( std::uint32_t set_count ) static const std::unordered_map< vk::DescriptorType, float > DESCRIPTOR_ALLOCATION_RATIOS {
{ vk::DescriptorType::eUniformBuffer, 1.0f },
{ vk::DescriptorType::eCombinedImageSampler, 2.0f },
{ vk::DescriptorType::eStorageBuffer, 1.0f },
{ vk::DescriptorType::eInputAttachment, 0.5f },
{ vk::DescriptorType::eSampledImage, 2.0f }
};
vk::raii::DescriptorPool createPool( const std::uint32_t set_count )
{ {
std::vector< vk::DescriptorPoolSize > pool_sizes {}; std::vector< vk::DescriptorPoolSize > pool_sizes {};
for ( auto& [ type, ratio ] : DESCRIPTOR_ALLOCATION_RATIOS ) for ( auto& [ type, ratio ] : DESCRIPTOR_ALLOCATION_RATIOS )

View File

@@ -17,9 +17,6 @@ namespace fgl::engine
namespace fgl::engine::descriptors namespace fgl::engine::descriptors
{ {
static const std::unordered_map< vk::DescriptorType, float > DESCRIPTOR_ALLOCATION_RATIOS {
{ vk::DescriptorType::eUniformBuffer, 2.0f }, { vk::DescriptorType::eCombinedImageSampler, 2.0f }
};
class DescriptorPool class DescriptorPool
{ {

View File

@@ -10,16 +10,16 @@
namespace fgl::engine namespace fgl::engine
{ {
class Camera; class RenderCamera;
COMPONENT_CLASS( CameraComponent, CameraComponentID ) COMPONENT_CLASS( CameraComponent, CameraComponentID )
{ {
std::shared_ptr< Camera > m_camera; std::shared_ptr< RenderCamera > m_camera;
public: public:
CameraComponent() = delete; CameraComponent() = delete;
CameraComponent( std::shared_ptr< Camera > & camera ); CameraComponent( std::shared_ptr< RenderCamera > & camera );
~CameraComponent(); ~CameraComponent();
}; };

View File

@@ -0,0 +1,12 @@
//
// Created by kj16609 on 9/23/25.
//
#include "Sun.hpp"
#include "camera/ShadowMap.hpp"
namespace fgl::engine
{
Sun::Sun() : m_shadowmap( createShadowmap( UniversalRotation::pointAt( constants::SUN_DIR ) ) )
{}
} // namespace fgl::engine

View File

@@ -0,0 +1,19 @@
//
// Created by kj16609 on 9/23/25.
//
#pragma once
#include <memory>
namespace fgl::engine
{
class ShadowMap;
struct Sun
{
std::shared_ptr< ShadowMap > m_shadowmap;
public:
Sun();
};
} // namespace fgl::engine

View File

@@ -1,59 +0,0 @@
//
// Created by kj16609 on 2/17/25.
//
#include "ShadowMap.hpp"
#include "assets/image/Image.hpp"
#include "assets/texture/Texture.hpp"
namespace fgl::engine::shadows
{
std::shared_ptr< Image > getDepthImage( const vk::Extent2D extent )
{
constexpr auto format { vk::Format::eR16Unorm };
constexpr vk::ImageUsageFlags usage_flags { vk::ImageUsageFlagBits::eSampled
| vk::ImageUsageFlagBits::eDepthStencilAttachment };
constexpr auto inital_layout { vk::ImageLayout::eUndefined };
constexpr auto final_layout { vk::ImageLayout::eDepthReadOnlyOptimal };
return std::make_shared< Image >( extent, format, usage_flags, inital_layout, final_layout );
}
PerFrameArray< std::shared_ptr< Image > > createDepthImages( vk::Extent2D extent )
{
PerFrameArray< std::shared_ptr< Image > > array {};
for ( std::size_t i = 0; i < array.size(); ++i ) array[ i ] = getDepthImage( extent );
return array;
}
PerFrameArray< std::shared_ptr< Texture > > ShadowMap::createDepthTargets()
{
PerFrameArray< std::shared_ptr< Texture > > array {};
Sampler default_sampler {};
for ( std::size_t i = 0; i < array.size(); ++i )
array[ i ] = std::make_shared< Texture >( m_image[ i ], std::move( default_sampler ) );
return array;
}
void ShadowMap::renderForCamera( const Camera& camera )
{
// model -> world -> camera (identity) -> screen (shadow)
// since the camera in this case is the shadow map we just need to convert the screen space to world space. So we can just use an identity matrix
const Matrix< MatrixType::WorldToCamera > camera_matrix { m_transform.mat() };
const Matrix< MatrixType::CameraToScreen > identity { 1.0f };
const Matrix< MatrixType::WorldToScreen > matrix { camera_matrix * identity };
}
ShadowMap::ShadowMap( const vk::Extent2D extent ) :
m_image( createDepthImages( extent ) ),
m_target( createDepthTargets() )
{}
} // namespace fgl::engine::shadows

View File

@@ -1,47 +0,0 @@
//
// Created by kj16609 on 2/17/25.
//
#pragma once
#include <vulkan/vulkan_raii.hpp>
#include <memory>
#include "primitives/Transform.hpp"
#include "primitives/matricies/Matrix.hpp"
#include "primitives/matricies/MatrixEvolvedTypes.hpp"
#include "rendering/PresentSwapChain.hpp"
namespace fgl::engine
{
class Image;
class Texture;
} // namespace fgl::engine
namespace fgl::engine::shadows
{
class ShadowMap
{
PerFrameArray< std::shared_ptr< Image > > m_image;
PerFrameArray< std::shared_ptr< Texture > > m_target;
Matrix< MatrixType::WorldToScreen > m_matrix { 1.0f };
Transform< CoordinateSpace::World > m_transform {};
PerFrameArray< std::shared_ptr< Texture > > createDepthTargets();
public:
void renderForCamera( const Camera& camera );
ShadowMap( vk::Extent2D extent );
~ShadowMap();
};
} // namespace fgl::engine::shadows
namespace fgl::engine
{
using namespace shadows;
}

View File

@@ -15,7 +15,7 @@
namespace fgl::engine namespace fgl::engine
{ {
class Camera; class RenderCamera;
//! Frustum constructed in model space (To be translated to a World space frustum later) //! Frustum constructed in model space (To be translated to a World space frustum later)
struct FrustumBase struct FrustumBase
@@ -60,7 +60,7 @@ namespace fgl::engine
WorldCoordinate m_position {}; WorldCoordinate m_position {};
friend class Camera; friend class RenderCamera;
public: public:

View File

@@ -6,6 +6,11 @@
namespace fgl::engine namespace fgl::engine
{ {
UniversalRotation UniversalRotation::pointAt( const glm::vec3 vec )
{
return UniversalRotation( QuatRotation( glm::normalize( vec ) ) );
}
void UniversalRotation::addX( const float value ) void UniversalRotation::addX( const float value )
{ {
if ( isQuat() ) [[likely]] if ( isQuat() ) [[likely]]

View File

@@ -75,6 +75,8 @@ namespace fgl::engine
return q_rotation; return q_rotation;
} }
static UniversalRotation pointAt( const glm::vec3 vec );
// Universal modification // Universal modification
void addX( float value ); void addX( float value );
void addY( float value ); void addY( float value );

View File

@@ -14,6 +14,8 @@ inline const static std::vector< const char* > DEVICE_EXTENSIONS = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_KHR_SWAPCHAIN_EXTENSION_NAME,
VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME, // Used for descriptor indexing VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME, // Used for descriptor indexing
VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME,
// VK_EXT_MESH_SHADER_EXTENSION_NAME, // MAGICAL SHIT // VK_EXT_MESH_SHADER_EXTENSION_NAME, // MAGICAL SHIT
VK_KHR_DYNAMIC_RENDERING_LOCAL_READ_EXTENSION_NAME // Required until vulkan 1.4 VK_KHR_DYNAMIC_RENDERING_LOCAL_READ_EXTENSION_NAME // Required until vulkan 1.4
}; };

View File

@@ -168,45 +168,6 @@ namespace fgl::engine
friend class RenderPassBuilder; friend class RenderPassBuilder;
}; };
template < std::size_t index, vk::ImageLayout layout >
struct InputAttachment
{
static constexpr bool is_input { true };
static constexpr vk::ImageLayout m_layout { layout };
static constexpr std::size_t m_index { index };
};
template < std::size_t index, vk::ImageLayout layout >
struct UsedAttachment
{
static constexpr vk::ImageLayout m_layout { layout };
static constexpr std::size_t m_index { index };
static constexpr bool is_input { false };
};
template < typename T >
concept is_input_attachment = requires( T a ) {
{ a.is_input } -> std::same_as< const bool& >;
{ a.m_layout } -> std::same_as< const vk::ImageLayout& >;
} && T::is_input;
template < typename T >
concept is_used_attachment = requires( T a ) {
{ a.is_input } -> std::same_as< const bool& >;
{ a.m_layout } -> std::same_as< const vk::ImageLayout& >;
} && !T::is_input;
template < typename T > concept is_wrapped_attachment = is_input_attachment< T > || is_used_attachment< T >;
template < typename T >
requires is_wrapped_attachment< T >
using UnwrappedAttachment = std::conditional_t< is_wrapped_attachment< T >, typename T::Attachment, T >;
//! Checks if the wrapped attachment is a depth attachment
template < typename T >
concept is_wrapped_depth_attachment = is_wrapped_attachment< T > && is_attachment< UnwrappedAttachment< T > >
&& ( T::m_layout == vk::ImageLayout::eDepthStencilAttachmentOptimal );
//Helper functions //Helper functions
template < is_attachment Attachment, is_attachment... Attachments > template < is_attachment Attachment, is_attachment... Attachments >
consteval std::uint32_t maxIndex() consteval std::uint32_t maxIndex()
@@ -221,18 +182,6 @@ namespace fgl::engine
} }
} }
template < is_attachment... Attachments >
static std::vector< vk::ImageView > getViewsForFrame( const FrameIndex frame_idx, Attachments... attachments )
{
std::vector< vk::ImageView > view {};
view.resize( sizeof...( Attachments ) );
static_assert( maxIndex< Attachments... >() + 1 == sizeof...( Attachments ) );
( ( view[ attachments.m_index ] = *attachments.getView( frame_idx ) ), ... );
return view;
}
template < is_attachment... Attachments > template < is_attachment... Attachments >
static std::vector< vk::ClearValue > gatherClearValues( Attachments... attachments ) static std::vector< vk::ClearValue > gatherClearValues( Attachments... attachments )
{ {

View File

@@ -13,6 +13,189 @@
namespace fgl::engine namespace fgl::engine
{ {
vk::raii::PipelineLayout PipelineBuilder::createLayout()
{
vk::PipelineLayoutCreateInfo info {};
if ( m_state->push_constant.size > 0 ) info.setPushConstantRanges( m_state->push_constant );
std::vector< vk::DescriptorSetLayout > set_layouts {};
set_layouts.reserve( m_state->descriptor_set_layouts.size() );
SetID max_set_idx { 0 };
for ( const auto& [ set_idx, _ ] : m_state->descriptor_set_layouts )
{
max_set_idx = std::max( max_set_idx, set_idx );
}
// Any sets not used, Should be set to VK_NULL_HANDLE
set_layouts.resize( max_set_idx + 1 );
for ( std::size_t i = 0; i < set_layouts.size(); ++i )
{
auto itter { m_state->descriptor_set_layouts.find( static_cast< SetID >( i ) ) };
if ( itter == m_state->descriptor_set_layouts.end() )
{
// Could not find it. Empty
set_layouts[ i ] = m_empty_set_layout.layout();
}
else
{
set_layouts[ i ] = itter->second;
}
}
for ( const auto& [ set_idx, layout ] : m_state->descriptor_set_layouts )
{
set_layouts[ set_idx ] = layout;
}
info.setSetLayouts( set_layouts );
return Device::getInstance()->createPipelineLayout( info );
}
void PipelineBuilder::
addDescriptorSet( const SetID idx, const vk::raii::DescriptorSetLayout& descriptor_set_layout ) const
{
FGL_ASSERT( !m_state->descriptor_set_layouts.contains( idx ), "Descriptor already set! Conflicting SetIDs" );
m_state->descriptor_set_layouts.insert( std::make_pair( idx, *descriptor_set_layout ) );
}
void PipelineBuilder::addDescriptorSet( descriptors::DescriptorSetLayout& descriptor )
{
addDescriptorSet( descriptor.m_set_idx, descriptor.layout() );
}
void PipelineBuilder::addDynamicState( vk::DynamicState dynamic_state )
{
m_state->m_dynamic_state.emplace_back( dynamic_state );
}
void PipelineBuilder::setPushConstant( const vk::ShaderStageFlags flags, std::uint32_t size )
{
m_state->push_constant.offset = 0;
m_state->push_constant.size = size;
m_state->push_constant.stageFlags = flags;
}
void PipelineBuilder::setBindPoint( vk::PipelineBindPoint bind_point )
{
m_state->bind_point = bind_point;
}
PipelineBuilder::BuilderState::Formats::Formats()
{}
[[nodiscard]] vk::PipelineColorBlendAttachmentState& PipelineBuilder::BuilderState::addColorAttachment()
{
color_blend_attachment.emplace_back();
color_blend_info.setAttachments( color_blend_attachment );
return color_blend_attachment.back();
}
PipelineBuilder::BuilderState::BuilderState( std::uint32_t subpass ) : m_subpass_stage( subpass )
{
setDefault();
}
void PipelineBuilder::BuilderState::setDefault()
{
viewport_info.viewportCount = 1;
viewport_info.pViewports = nullptr;
viewport_info.scissorCount = 1;
viewport_info.pScissors = nullptr;
assembly_info.topology = vk::PrimitiveTopology::eTriangleList;
assembly_info.primitiveRestartEnable = VK_FALSE;
rasterization_info.depthClampEnable = VK_FALSE;
rasterization_info.rasterizerDiscardEnable = VK_FALSE;
rasterization_info.polygonMode = vk::PolygonMode::eFill;
rasterization_info.cullMode = vk::CullModeFlagBits::eBack;
rasterization_info.frontFace = vk::FrontFace::eClockwise;
rasterization_info.depthBiasEnable = VK_FALSE;
rasterization_info.depthBiasConstantFactor = 0.0f;
rasterization_info.depthBiasClamp = 0.0f;
rasterization_info.depthBiasSlopeFactor = 0.0f;
rasterization_info.lineWidth = 1.0f;
multisample_info.rasterizationSamples = vk::SampleCountFlagBits::e1;
multisample_info.sampleShadingEnable = VK_FALSE;
multisample_info.minSampleShading = 1.0f;
multisample_info.pSampleMask = nullptr;
multisample_info.alphaToCoverageEnable = VK_FALSE;
multisample_info.alphaToOneEnable = VK_FALSE;
color_blend_info.logicOpEnable = VK_FALSE;
color_blend_info.logicOp = vk::LogicOp::eCopy;
color_blend_info.attachmentCount = 0;
color_blend_info.pAttachments = nullptr;
color_blend_info.blendConstants[ 0 ] = 0.0f;
color_blend_info.blendConstants[ 1 ] = 0.0f;
color_blend_info.blendConstants[ 2 ] = 0.0f;
color_blend_info.blendConstants[ 3 ] = 0.0f;
depth_stencil_info.depthTestEnable = VK_TRUE;
depth_stencil_info.depthWriteEnable = VK_TRUE;
depth_stencil_info.depthCompareOp = vk::CompareOp::eLess;
depth_stencil_info.depthBoundsTestEnable = VK_FALSE;
depth_stencil_info.stencilTestEnable = VK_FALSE;
//depth_stencil_info.front = {};
//depth_stencil_info.back = {};
depth_stencil_info.minDepthBounds = 0.0f;
depth_stencil_info.maxDepthBounds = 1.0f;
dynamic_state_enables = { vk::DynamicState::eViewport, vk::DynamicState::eScissor };
dynamic_state_info.setDynamicStates( dynamic_state_enables );
//info.dynamic_state_info.flags = 0;
}
void PipelineBuilder::setTopology( const vk::PrimitiveTopology primitive_topology )
{
m_state->assembly_info.topology = primitive_topology;
}
void PipelineBuilder::disableVertexInput()
{
m_state->vertex_input_descriptions.bindings = {};
m_state->vertex_input_descriptions.attributes = {};
}
void PipelineBuilder::disableCulling()
{
m_state->rasterization_info.cullMode = vk::CullModeFlagBits::eNone;
}
void PipelineBuilder::addDepthAttachment()
{
m_state->formats.depth = pickDepthFormat();
}
AttachmentBuilder PipelineBuilder::addAttachment()
{
return { *this };
}
AttachmentBuilder PipelineBuilder::addColorAttachment()
{
AttachmentBuilder builder { addAttachment() };
return builder;
}
void PipelineBuilder::setBindingDescriptions( const std::vector< vk::VertexInputBindingDescription >& descriptions )
{
m_state->vertex_input_descriptions.bindings = descriptions;
}
void PipelineBuilder::
setAttributeDescriptions( const std::vector< vk::VertexInputAttributeDescription >& descriptions ) const
{
m_state->vertex_input_descriptions.attributes = descriptions;
}
PipelineBuilder::PipelineBuilder( std::uint32_t subpass ) : m_state( std::make_unique< BuilderState >( subpass ) ) PipelineBuilder::PipelineBuilder( std::uint32_t subpass ) : m_state( std::make_unique< BuilderState >( subpass ) )
{ {
addDynamicState( vk::DynamicState::eViewport ); addDynamicState( vk::DynamicState::eViewport );
@@ -87,6 +270,12 @@ namespace fgl::engine
return pipeline; return pipeline;
} }
vk::raii::Pipeline PipelineBuilder::createDynamicPipeline( BuilderState& state, vk::raii::PipelineLayout& layout )
{
if ( state.shaders.compute ) return createComputePipeline( state, layout );
return createGraphicsPipeline( state, layout );
}
vk::raii::Pipeline PipelineBuilder::createComputePipeline( BuilderState& state, vk::raii::PipelineLayout& layout ) vk::raii::Pipeline PipelineBuilder::createComputePipeline( BuilderState& state, vk::raii::PipelineLayout& layout )
{ {
vk::StructureChain< vk::ComputePipelineCreateInfo > chain {}; vk::StructureChain< vk::ComputePipelineCreateInfo > chain {};
@@ -106,12 +295,6 @@ namespace fgl::engine
return Device::getInstance()->createComputePipeline( VK_NULL_HANDLE, info ); return Device::getInstance()->createComputePipeline( VK_NULL_HANDLE, info );
} }
vk::raii::Pipeline PipelineBuilder::createDynamicPipeline( BuilderState& state, vk::raii::PipelineLayout& layout )
{
if ( state.shaders.compute ) return createComputePipeline( state, layout );
return createGraphicsPipeline( state, layout );
}
vk::raii::Pipeline PipelineBuilder::createGraphicsPipeline( BuilderState& state, vk::raii::PipelineLayout& layout ) vk::raii::Pipeline PipelineBuilder::createGraphicsPipeline( BuilderState& state, vk::raii::PipelineLayout& layout )
{ {
vk::StructureChain< vk::GraphicsPipelineCreateInfo, vk::PipelineRenderingCreateInfo > chain {}; vk::StructureChain< vk::GraphicsPipelineCreateInfo, vk::PipelineRenderingCreateInfo > chain {};
@@ -174,189 +357,6 @@ namespace fgl::engine
return pipeline; return pipeline;
} }
vk::raii::PipelineLayout PipelineBuilder::createLayout()
{
vk::PipelineLayoutCreateInfo info {};
if ( m_state->push_constant.size > 0 ) info.setPushConstantRanges( m_state->push_constant );
std::vector< vk::DescriptorSetLayout > set_layouts {};
set_layouts.reserve( m_state->descriptor_set_layouts.size() );
SetID max_set_idx { 0 };
for ( const auto& [ set_idx, _ ] : m_state->descriptor_set_layouts )
{
max_set_idx = std::max( max_set_idx, set_idx );
}
// Any sets not used, Should be set to VK_NULL_HANDLE
set_layouts.resize( max_set_idx + 1 );
for ( std::size_t i = 0; i < set_layouts.size(); ++i )
{
auto itter { m_state->descriptor_set_layouts.find( static_cast< SetID >( i ) ) };
if ( itter == m_state->descriptor_set_layouts.end() )
{
// Could not find it. Empty
set_layouts[ i ] = m_empty_set_layout.layout();
}
else
{
set_layouts[ i ] = itter->second;
}
}
for ( const auto& [ set_idx, layout ] : m_state->descriptor_set_layouts )
{
set_layouts[ set_idx ] = layout;
}
info.setSetLayouts( set_layouts );
return Device::getInstance()->createPipelineLayout( info );
}
void PipelineBuilder::
addDescriptorSet( const SetID idx, const vk::raii::DescriptorSetLayout& descriptor_set_layout ) const
{
FGL_ASSERT( !m_state->descriptor_set_layouts.contains( idx ), "Descriptor already set!" );
m_state->descriptor_set_layouts.insert( std::make_pair( idx, *descriptor_set_layout ) );
}
void PipelineBuilder::addDescriptorSet( descriptors::DescriptorSetLayout& descriptor )
{
addDescriptorSet( descriptor.m_set_idx, descriptor.layout() );
}
void PipelineBuilder::addDynamicState( vk::DynamicState dynamic_state )
{
m_state->m_dynamic_state.emplace_back( dynamic_state );
}
void PipelineBuilder::setPushConstant( const vk::ShaderStageFlags flags, std::uint32_t size )
{
m_state->push_constant.offset = 0;
m_state->push_constant.size = size;
m_state->push_constant.stageFlags = flags;
}
void PipelineBuilder::setBindPoint( vk::PipelineBindPoint bind_point )
{
m_state->bind_point = bind_point;
}
PipelineBuilder::BuilderState::Formats::Formats()
{}
[[nodiscard]] vk::PipelineColorBlendAttachmentState& PipelineBuilder::BuilderState::addColorAttachment()
{
color_blend_attachment.emplace_back();
color_blend_info.setAttachments( color_blend_attachment );
return color_blend_attachment.back();
}
void PipelineBuilder::BuilderState::setDefault()
{
viewport_info.viewportCount = 1;
viewport_info.pViewports = nullptr;
viewport_info.scissorCount = 1;
viewport_info.pScissors = nullptr;
assembly_info.topology = vk::PrimitiveTopology::eTriangleList;
assembly_info.primitiveRestartEnable = VK_FALSE;
rasterization_info.depthClampEnable = VK_FALSE;
rasterization_info.rasterizerDiscardEnable = VK_FALSE;
rasterization_info.polygonMode = vk::PolygonMode::eFill;
rasterization_info.cullMode = vk::CullModeFlagBits::eBack;
rasterization_info.frontFace = vk::FrontFace::eClockwise;
rasterization_info.depthBiasEnable = VK_FALSE;
rasterization_info.depthBiasConstantFactor = 0.0f;
rasterization_info.depthBiasClamp = 0.0f;
rasterization_info.depthBiasSlopeFactor = 0.0f;
rasterization_info.lineWidth = 1.0f;
multisample_info.rasterizationSamples = vk::SampleCountFlagBits::e1;
multisample_info.sampleShadingEnable = VK_FALSE;
multisample_info.minSampleShading = 1.0f;
multisample_info.pSampleMask = nullptr;
multisample_info.alphaToCoverageEnable = VK_FALSE;
multisample_info.alphaToOneEnable = VK_FALSE;
color_blend_info.logicOpEnable = VK_FALSE;
color_blend_info.logicOp = vk::LogicOp::eCopy;
color_blend_info.attachmentCount = 0;
color_blend_info.pAttachments = nullptr;
color_blend_info.blendConstants[ 0 ] = 0.0f;
color_blend_info.blendConstants[ 1 ] = 0.0f;
color_blend_info.blendConstants[ 2 ] = 0.0f;
color_blend_info.blendConstants[ 3 ] = 0.0f;
depth_stencil_info.depthTestEnable = VK_TRUE;
depth_stencil_info.depthWriteEnable = VK_TRUE;
depth_stencil_info.depthCompareOp = vk::CompareOp::eLess;
depth_stencil_info.depthBoundsTestEnable = VK_FALSE;
depth_stencil_info.stencilTestEnable = VK_FALSE;
//depth_stencil_info.front = {};
//depth_stencil_info.back = {};
depth_stencil_info.minDepthBounds = 0.0f;
depth_stencil_info.maxDepthBounds = 1.0f;
dynamic_state_enables = { vk::DynamicState::eViewport, vk::DynamicState::eScissor };
dynamic_state_info.setDynamicStates( dynamic_state_enables );
//info.dynamic_state_info.flags = 0;
}
PipelineBuilder::BuilderState::BuilderState( std::uint32_t subpass ) : m_subpass_stage( subpass )
{
setDefault();
}
void PipelineBuilder::setTopology( const vk::PrimitiveTopology primitive_topology )
{
m_state->assembly_info.topology = primitive_topology;
}
void PipelineBuilder::disableVertexInput()
{
m_state->vertex_input_descriptions.bindings = {};
m_state->vertex_input_descriptions.attributes = {};
}
void PipelineBuilder::disableCulling()
{
m_state->rasterization_info.cullMode = vk::CullModeFlagBits::eNone;
}
void PipelineBuilder::addDepthAttachment()
{
m_state->formats.depth = pickDepthFormat();
}
AttachmentBuilder PipelineBuilder::addAttachment()
{
return { *this };
}
AttachmentBuilder PipelineBuilder::addColorAttachment()
{
AttachmentBuilder builder { addAttachment() };
return builder;
}
void PipelineBuilder::setBindingDescriptions( const std::vector< vk::VertexInputBindingDescription >& descriptions )
{
m_state->vertex_input_descriptions.bindings = descriptions;
}
void PipelineBuilder::
setAttributeDescriptions( const std::vector< vk::VertexInputAttributeDescription >& descriptions ) const
{
m_state->vertex_input_descriptions.attributes = descriptions;
}
vk::raii::Pipeline PipelineBuilder::createFromState( BuilderState& state, vk::raii::PipelineLayout& layout ) vk::raii::Pipeline PipelineBuilder::createFromState( BuilderState& state, vk::raii::PipelineLayout& layout )
{ {
return createDynamicPipeline( state, layout ); return createDynamicPipeline( state, layout );

View File

@@ -2,7 +2,7 @@
// Created by kj16609 on 2/28/25. // Created by kj16609 on 2/28/25.
// //
#pragma once #pragma once
#include "camera/Camera.hpp" #include "camera/RenderCamera.hpp"
namespace fgl::engine namespace fgl::engine
{ {

View File

@@ -8,7 +8,7 @@
#include "assets/model/Model.hpp" #include "assets/model/Model.hpp"
#include "engine/FrameInfo.hpp" #include "engine/FrameInfo.hpp"
#include "engine/camera/Camera.hpp" #include "engine/camera/RenderCamera.hpp"
namespace fgl::engine namespace fgl::engine
{ {
@@ -44,7 +44,7 @@ namespace fgl::engine
CullingSystem::~CullingSystem() CullingSystem::~CullingSystem()
{} {}
void CullingSystem::pass( FrameInfo& info ) void CullingSystem::pass( const FrameInfo& info )
{ {
ZoneScopedN( "Culling pass" ); ZoneScopedN( "Culling pass" );
@@ -61,10 +61,13 @@ namespace fgl::engine
m_cull_compute->bindDescriptor( command_buffer, info.m_primitives_desc ); // primitive set m_cull_compute->bindDescriptor( command_buffer, info.m_primitives_desc ); // primitive set
m_cull_compute->bindDescriptor( command_buffer, info.m_instances_desc ); // instances m_cull_compute->bindDescriptor( command_buffer, info.m_instances_desc ); // instances
m_cull_compute->bindDescriptor( command_buffer, info.m_command_buffer_desc ); // commands output m_cull_compute->bindDescriptor(
command_buffer, *info.camera->m_gpu_draw_cmds_desc[ info.in_flight_idx ] ); // commands output
auto& commands { info.camera->m_gpu_draw_commands[ info.in_flight_idx ] };
commands.resize( info.instances.size() );
CullPushConstants push_constants {}; CullPushConstants push_constants {};
push_constants.draw_count = info.m_commands.size(); push_constants.draw_count = commands.size();
command_buffer->pushConstants< command_buffer->pushConstants<
CullPushConstants >( m_cull_compute->layout(), vk::ShaderStageFlagBits::eCompute, 0, { push_constants } ); CullPushConstants >( m_cull_compute->layout(), vk::ShaderStageFlagBits::eCompute, 0, { push_constants } );
@@ -76,7 +79,7 @@ namespace fgl::engine
command_buffer->dispatch( group_count, 1, 1 ); command_buffer->dispatch( group_count, 1, 1 );
// Add a memory barrier to ensure synchronization between the compute and subsequent stages // Add a memory barrier to ensure synchronization between the compute and later stages
vk::MemoryBarrier memory_barrier { vk::MemoryBarrier memory_barrier {
vk::AccessFlagBits::eShaderWrite, vk::AccessFlagBits::eShaderWrite,
vk::AccessFlagBits::eVertexAttributeRead | vk::AccessFlagBits::eIndirectCommandRead, vk::AccessFlagBits::eVertexAttributeRead | vk::AccessFlagBits::eIndirectCommandRead,

View File

@@ -38,7 +38,7 @@ namespace fgl::engine
~CullingSystem(); ~CullingSystem();
void pass( FrameInfo& info ); void pass( const FrameInfo& info );
}; };
static_assert( is_system< CullingSystem > ); static_assert( is_system< CullingSystem > );

View File

@@ -10,7 +10,7 @@
#include "EngineContext.hpp" #include "EngineContext.hpp"
#include "assets/model/ModelVertex.hpp" #include "assets/model/ModelVertex.hpp"
#include "engine/assets/material/Material.hpp" #include "engine/assets/material/Material.hpp"
#include "engine/camera/Camera.hpp" #include "engine/camera/RenderCamera.hpp"
#include "engine/debug/timing/FlameGraph.hpp" #include "engine/debug/timing/FlameGraph.hpp"
#include "engine/rendering/pipelines/v2/Pipeline.hpp" #include "engine/rendering/pipelines/v2/Pipeline.hpp"
#include "engine/rendering/pipelines/v2/PipelineBuilder.hpp" #include "engine/rendering/pipelines/v2/PipelineBuilder.hpp"
@@ -29,7 +29,7 @@ namespace fgl::engine
addGBufferAttachments( builder ); addGBufferAttachments( builder );
builder.addDescriptorSet( Camera::getDescriptorLayout() ); builder.addDescriptorSet( RenderCamera::getDescriptorLayout() );
builder.addDescriptorSet( Texture::getDescriptorLayout() ); builder.addDescriptorSet( Texture::getDescriptorLayout() );
builder.addDescriptorSet( Material::getDescriptorLayout() ); builder.addDescriptorSet( Material::getDescriptorLayout() );
@@ -92,18 +92,17 @@ namespace fgl::engine
const std::vector< vk::Buffer > vert_buffers { const std::vector< vk::Buffer > vert_buffers {
model_buffers.m_vertex_buffer->getVkBuffer(), model_buffers.m_vertex_buffer->getVkBuffer(),
model_buffers.m_generated_instance_info[ info.in_flight_idx ].getVkBuffer() info.camera->m_generated_instance_info[ info.in_flight_idx ].getVkBuffer(),
}; };
command_buffer->bindVertexBuffers( command_buffer->bindVertexBuffers(
0, vert_buffers, { 0, model_buffers.m_generated_instance_info[ info.in_flight_idx ].getOffset() } ); 0, vert_buffers, { 0, info.camera->m_generated_instance_info[ info.in_flight_idx ].getOffset() } );
command_buffer->bindIndexBuffer( model_buffers.m_index_buffer->getVkBuffer(), 0, vk::IndexType::eUint32 ); command_buffer->bindIndexBuffer( model_buffers.m_index_buffer->getVkBuffer(), 0, vk::IndexType::eUint32 );
command_buffer->drawIndexedIndirect( const auto& commands { info.camera->m_gpu_draw_commands[ info.in_flight_idx ] };
info.m_commands.getVkBuffer(),
info.m_commands.getOffset(), command_buffer
info.m_commands.size(), ->drawIndexedIndirect( commands.getVkBuffer(), commands.getOffset(), commands.size(), commands.stride() );
info.m_commands.stride() );
}; };
} // namespace fgl::engine } // namespace fgl::engine

View File

@@ -6,7 +6,7 @@
#include "engine/FrameInfo.hpp" #include "engine/FrameInfo.hpp"
#include "engine/assets/model/SimpleVertex.hpp" #include "engine/assets/model/SimpleVertex.hpp"
#include "engine/camera/Camera.hpp" #include "engine/camera/RenderCamera.hpp"
#include "engine/debug/drawers.hpp" #include "engine/debug/drawers.hpp"
#include "engine/primitives/points/Coordinate.hpp" #include "engine/primitives/points/Coordinate.hpp"
#include "engine/rendering/pipelines/v2/Pipeline.hpp" #include "engine/rendering/pipelines/v2/Pipeline.hpp"
@@ -27,7 +27,7 @@ namespace fgl::engine
{ {
PipelineBuilder builder { 0 }; PipelineBuilder builder { 0 };
builder.addDescriptorSet( Camera::getDescriptorLayout() ); builder.addDescriptorSet( RenderCamera::getDescriptorLayout() );
addGBufferAttachments( builder ); addGBufferAttachments( builder );

View File

@@ -1,6 +1,7 @@
#version 450 #version 450
import objects.camera; import objects.camera;
import objects.gbuffer;
struct Vertex { struct Vertex {
vec4 position : SV_Position; vec4 position : SV_Position;
@@ -24,13 +25,6 @@ struct CompositeFragment {
vec4 color; vec4 color;
}; };
struct GBufferInput {
SubpassInput<vec4> color : COLOR;
SubpassInput<vec4> position : POSITION;
SubpassInput<vec4> normal : NORMAL;
SubpassInput<vec4> metallic : METALLIC;
SubpassInput<vec4> emissive : EMISSIVE;
};
// SubpassInput< vec4 > test : TEST; // SubpassInput< vec4 > test : TEST;
@@ -46,6 +40,12 @@ ParameterBlock<GBufferInput> gbuffer : GBUFFER;
[[vk::binding(0,1)]] [[vk::binding(0,1)]]
ParameterBlock< CameraData > camera : CAMERA; ParameterBlock< CameraData > camera : CAMERA;
[[vk::binding(0,2)]]
ParameterBlock< CameraData > sun_camera;
[[vk::binding(1,2)]]
Sampler2D shadow_sampler;
//TODO: constant flags //TODO: constant flags
// Direction the sun is facing // Direction the sun is facing

View File

@@ -75,7 +75,7 @@ void computeMain( uint3 dispatch_id : SV_DispatchThreadID)
out_instances[ instance_index ].material_id = instance.material_id; out_instances[ instance_index ].material_id = instance.material_id;
const ModelInstanceInfo model_instance = model_instances[ instance.model_index ]; const ModelInstanceInfo model_instance = model_instances[ instance.model_index ];
out_instances[ instance_index ].model_matrix = model_instance.model_matrix; out_instances[ instance_index ].model_matrix = {model_instance.model_matrix};
// out_instances[ instance_index ].normal_matrix = model_instance.normal_matrix; // out_instances[ instance_index ].normal_matrix = model_instance.normal_matrix;
} }
else else

View File

@@ -14,6 +14,13 @@ public struct CameraData
return vec3( inverse_view[ 0 ][ 3 ], inverse_view[ 1 ][ 3 ], inverse_view[ 2 ][ 3 ] ); return vec3( inverse_view[ 0 ][ 3 ], inverse_view[ 1 ][ 3 ], inverse_view[ 2 ][ 3 ] );
} }
public vec4 toCameraSpace(const vec4 world_coordinate)
{
return mul(mat(), world_coordinate);
}
public mat4x4 mat() public mat4x4 mat()
{ {
return mul( projection, view ); return mul( projection, view );

View File

@@ -11,6 +11,41 @@ public struct PrimitiveRenderInfo {
public uint32_t index_count; public uint32_t index_count;
}; };
public struct ModelMatrix
{
mat4x4 matrix;
public mat3 toNormalMatrix()
{
return transpose( inverse( mat3( matrix ) ) );
}
public vec3 normalizeNormal( vec3 normal )
{
return normalize( mul( toNormalMatrix(), normal ) );
}
public vec4 toWorldSpace( vec4 position )
{
return mul(matrix, position);
}
public __init( mat4x4 matrix_in )
{
matrix = matrix_in;
}
public mat4x4 mat()
{
return matrix;
}
};
ModelMatrix operator=(mat4x4 matrix)
{
return {matrix};
}
// Each primitive has one instance // Each primitive has one instance
public struct PrimitiveInstanceInfo public struct PrimitiveInstanceInfo
{ {
@@ -22,7 +57,7 @@ public struct PrimitiveInstanceInfo
// One object exists for each render instance // One object exists for each render instance
public struct InstanceRenderInfo public struct InstanceRenderInfo
{ {
public mat4x4 model_matrix; public ModelMatrix model_matrix;
// public mat4x4 normal_matrix; // public mat4x4 normal_matrix;
public uint32_t material_id; public uint32_t material_id;
}; };

View File

@@ -11,3 +11,10 @@ public struct GBufferFragment
public vec3 emissive : EMISSIVE; public vec3 emissive : EMISSIVE;
}; };
public struct GBufferInput {
public SubpassInput<vec4> color : COLOR;
public SubpassInput<vec4> position : POSITION;
public SubpassInput<vec4> normal : NORMAL;
public SubpassInput<vec4> metallic : METALLIC;
public SubpassInput<vec4> emissive : EMISSIVE;
};

View File

@@ -1,15 +1,36 @@
#version 450
import model.vertex; import model.vertex;
import objects.camera;
struct CoarseVertex { struct CoarseVertex {
float4 position : SV_Position; float4 position : SV_Position;
} };
struct Fragment
{
};
[ [ vk::binding( 0, 1 ) ] ]
ConstantBuffer< CameraData > camera : CAMERA;
[shader("vertex")] [shader("vertex")]
CoarseVertex vertexMain( ModelVertex in_vertex ) CoarseVertex vertexMain(ModelVertex in_vertex)
{ {
CoarseVertex out_vertex;
vec4 world_pos = in_vertex.instance.model_matrix.toWorldSpace( vec4(in_vertex.simple.position, 1.0) );
out_vertex.position = camera.toCameraSpace( world_pos );
return out_vertex;
} }
[shader("fragment")]
Fragment fragmentMain(CoarseVertex vertex)
{
Fragment fragment;
return fragment;
}

View File

@@ -23,18 +23,20 @@ CoarseVertex vertexMain( ModelVertex in_vertex )
{ {
CoarseVertex out_vertex; CoarseVertex out_vertex;
vec4 world_pos = mul(in_vertex.instance.model_matrix, vec4(in_vertex.simple.position, 1.0)); // vec4 world_pos = mul(in_vertex.instance.model_matrix, vec4(in_vertex.simple.position, 1.0));
vec4 world_pos = in_vertex.instance.model_matrix.toWorldSpace( vec4(in_vertex.simple.position, 1.0) );
const float4 transformed_pos = mul( camera.mat(), world_pos );
out_vertex.position = transformed_pos;
out_vertex.world_pos = world_pos.xyz; out_vertex.world_pos = world_pos.xyz;
mat3 normal_matrix = transpose( inverse( mat3( in_vertex.instance.model_matrix ) ) ); out_vertex.position = camera.toCameraSpace( world_pos) ;
out_vertex.normal = normalize( mul(normal_matrix, in_vertex.normal) ); // mat3 normal_matrix = transpose( inverse( mat3( in_vertex.instance.model_matrix ) ) );
mat3 normal_matrix = in_vertex.instance.model_matrix.toNormalMatrix();
// out_vertex.normal = normalize( mul(normal_matrix, in_vertex.normal) );
out_vertex.normal = in_vertex.instance.model_matrix.normalizeNormal( in_vertex.normal );
out_vertex.tex_coord = in_vertex.uv; out_vertex.tex_coord = in_vertex.uv;
out_vertex.material_id = in_vertex.instance.material_id; out_vertex.material_id = in_vertex.instance.material_id;
out_vertex.matrix = in_vertex.instance.model_matrix; out_vertex.matrix = in_vertex.instance.model_matrix.mat();
out_vertex.tangent = in_vertex.tangent; out_vertex.tangent = in_vertex.tangent;
return out_vertex; return out_vertex;