Files
FGL-Engine/src/engine/camera/CameraViewpoint.cpp
2025-12-15 19:56:18 -05:00

242 lines
7.2 KiB
C++

//
// Created by kj16609 on 9/23/25.
//
#include "CameraViewpoint.hpp"
#include "CameraInfo.hpp"
#include "RenderCamera.hpp"
#include "assets/model/Model.hpp"
#include "math/literals/size.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, static_cast< float >( this->m_extent.width ), static_cast< float >( this->m_extent.height ),
0.0f, 1.0f };
}
descriptors::DescriptorSetLayout& CameraViewpoint::getDescriptorLayout()
{
return camera_descriptor_set;
}
} // namespace fgl::engine