From ae364934bb3cd9a5c2d3a9dcbc032bf89e369ebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sat, 10 Jul 2021 14:27:38 +0200 Subject: [PATCH] Graphics/CameraComponent: Add remaining features --- include/Nazara/Graphics/AbstractViewer.hpp | 2 + .../Graphics/Components/CameraComponent.hpp | 38 +++- .../Graphics/Components/CameraComponent.inl | 172 +++++++++++++++++- .../Graphics/Components/CameraComponent.cpp | 27 +++ src/Nazara/Graphics/ForwardFramePipeline.cpp | 8 +- 5 files changed, 233 insertions(+), 14 deletions(-) diff --git a/include/Nazara/Graphics/AbstractViewer.hpp b/include/Nazara/Graphics/AbstractViewer.hpp index 2f52bc2df..381fe9af8 100644 --- a/include/Nazara/Graphics/AbstractViewer.hpp +++ b/include/Nazara/Graphics/AbstractViewer.hpp @@ -9,6 +9,7 @@ #include #include +#include namespace Nz { @@ -24,6 +25,7 @@ namespace Nz virtual const RenderTarget& GetRenderTarget() = 0; virtual ViewerInstance& GetViewerInstance() = 0; virtual const ViewerInstance& GetViewerInstance() const = 0; + virtual const Recti& GetViewport() const = 0; }; } diff --git a/include/Nazara/Graphics/Components/CameraComponent.hpp b/include/Nazara/Graphics/Components/CameraComponent.hpp index a18c1a17e..89807a6c4 100644 --- a/include/Nazara/Graphics/Components/CameraComponent.hpp +++ b/include/Nazara/Graphics/Components/CameraComponent.hpp @@ -11,6 +11,9 @@ #include #include #include +#include +#include +#include #include #include @@ -20,26 +23,51 @@ namespace Nz { public: inline CameraComponent(const RenderTarget* renderTarget, ProjectionType projectionType = ProjectionType::Perspective); - CameraComponent(const CameraComponent&) = default; - CameraComponent(CameraComponent&&) = default; + inline CameraComponent(const CameraComponent& camera); + inline CameraComponent(CameraComponent&& camera) noexcept; ~CameraComponent() = default; + inline float GetAspectRatio() const; + inline DegreeAnglef GetFOV() const; const RenderTarget& GetRenderTarget() override; + inline const Vector2f& GetSize() const; + inline const Rectf& GetTargetRegion() const; ViewerInstance& GetViewerInstance() override; const ViewerInstance& GetViewerInstance() const override; + const Recti& GetViewport() const override; + inline float GetZFar() const; + inline float GetZNear() const; - inline void UpdateTarget(const RenderTarget* framebuffer); + inline void UpdateFOV(DegreeAnglef fov); inline void UpdateProjectionType(ProjectionType projectionType); + inline void UpdateSize(const Vector2f& size); + void UpdateTarget(const RenderTarget* framebuffer); + inline void UpdateTargetRegion(const Rectf& targetRegion); + inline void UpdateViewport(const Recti& viewport); + inline void UpdateZFar(float zFar); + inline void UpdateZNear(float zNear); - CameraComponent& operator=(const CameraComponent&) = default; - CameraComponent& operator=(CameraComponent&&) = default; + inline CameraComponent& operator=(const CameraComponent& camera); + inline CameraComponent& operator=(CameraComponent&& camera) noexcept; private: inline void UpdateProjectionMatrix(); + inline void UpdateViewport(); + inline void UpdateViewport(Vector2ui renderTargetSize); + + NazaraSlot(RenderTarget, OnRenderTargetRelease, m_onRenderTargetRelease); + NazaraSlot(RenderTarget, OnRenderTargetSizeChange, m_onRenderTargetSizeChange); const RenderTarget* m_renderTarget; + DegreeAnglef m_fov; ProjectionType m_projectionType; + Rectf m_targetRegion; + Recti m_viewport; + Vector2f m_size; ViewerInstance m_viewerInstance; + float m_aspectRatio; + float m_zFar; + float m_zNear; }; } diff --git a/include/Nazara/Graphics/Components/CameraComponent.inl b/include/Nazara/Graphics/Components/CameraComponent.inl index 1b1d0f578..55ea155b2 100644 --- a/include/Nazara/Graphics/Components/CameraComponent.inl +++ b/include/Nazara/Graphics/Components/CameraComponent.inl @@ -8,15 +8,126 @@ namespace Nz { inline CameraComponent::CameraComponent(const RenderTarget* renderTarget, ProjectionType projectionType) : + m_renderTarget(nullptr), + m_fov(70.f), m_projectionType(projectionType), - m_renderTarget(renderTarget) + m_targetRegion(0.f, 0.f, 1.f, 1.f), + m_viewport(0, 0, 0, 0), + m_size(-1.f, -1.f), + m_zFar(1000.f), + m_zNear(1.f) { + UpdateTarget(renderTarget); + } + + inline CameraComponent::CameraComponent(const CameraComponent& camera) : + m_renderTarget(nullptr), + m_fov(camera.m_fov), + m_projectionType(camera.m_projectionType), + m_targetRegion(camera.m_targetRegion), + m_viewport(camera.m_viewport), + m_size(camera.m_size), + m_aspectRatio(camera.m_aspectRatio), + m_zFar(camera.m_zFar), + m_zNear(camera.m_zNear) + { + UpdateTarget(camera.m_renderTarget); + } + + inline CameraComponent::CameraComponent(CameraComponent&& camera) noexcept : + m_renderTarget(nullptr), + m_fov(camera.m_fov), + m_projectionType(camera.m_projectionType), + m_targetRegion(camera.m_targetRegion), + m_viewport(camera.m_viewport), + m_size(camera.m_size), + m_aspectRatio(camera.m_aspectRatio), + m_zFar(camera.m_zFar), + m_zNear(camera.m_zNear) + { + UpdateTarget(camera.m_renderTarget); + } + + inline float CameraComponent::GetAspectRatio() const + { + return m_aspectRatio; + } + + inline DegreeAnglef CameraComponent::GetFOV() const + { + return m_fov; + } + + inline const Vector2f& CameraComponent::GetSize() const + { + return m_size; + } + + inline const Rectf& CameraComponent::GetTargetRegion() const + { + return m_targetRegion; + } + + inline float CameraComponent::GetZFar() const + { + return m_zFar; + } + + inline float CameraComponent::GetZNear() const + { + return m_zNear; + } + + inline void CameraComponent::UpdateFOV(DegreeAnglef fov) + { + m_fov = fov; UpdateProjectionMatrix(); } - inline void CameraComponent::UpdateTarget(const RenderTarget* renderTarget) + inline void CameraComponent::UpdateZFar(float zFar) { - m_renderTarget = renderTarget; + m_zFar = zFar; + UpdateProjectionMatrix(); + } + + inline void CameraComponent::UpdateZNear(float zNear) + { + NazaraAssert(!NumberEquals(zNear, 0.f), "zNear cannot be zero"); + + m_zNear = zNear; + UpdateProjectionMatrix(); + } + + inline CameraComponent& CameraComponent::operator=(const CameraComponent& camera) + { + m_fov = camera.m_fov; + m_projectionType = camera.m_projectionType; + m_targetRegion = camera.m_targetRegion; + m_viewport = camera.m_viewport; + m_size = camera.m_size; + m_aspectRatio = camera.m_aspectRatio; + m_zFar = camera.m_zFar; + m_zNear = camera.m_zNear; + + UpdateTarget(camera.m_renderTarget); + + return *this; + } + + inline CameraComponent& CameraComponent::operator=(CameraComponent&& camera) noexcept + { + m_fov = camera.m_fov; + m_projectionType = camera.m_projectionType; + m_targetRegion = camera.m_targetRegion; + m_viewport = camera.m_viewport; + m_size = camera.m_size; + m_aspectRatio = camera.m_aspectRatio; + m_zFar = camera.m_zFar; + m_zNear = camera.m_zNear; + + UpdateTarget(camera.m_renderTarget); + + return *this; } inline void CameraComponent::UpdateProjectionType(ProjectionType projectionType) @@ -25,18 +136,67 @@ namespace Nz UpdateProjectionMatrix(); } + inline void CameraComponent::UpdateTargetRegion(const Rectf& targetRegion) + { + m_targetRegion = targetRegion; + UpdateViewport(); + } + + inline void CameraComponent::UpdateViewport(const Recti& viewport) + { + NazaraAssert(m_renderTarget, "no render target"); + + // We compute the region necessary to make this view port with the actual size of the target + Vector2f invSize = 1.f / Vector2f(m_renderTarget->GetSize()); + + UpdateTargetRegion(Rectf(invSize.x * viewport.x, invSize.y * viewport.y, invSize.x * viewport.width, invSize.y * viewport.height)); + } + + inline void CameraComponent::UpdateSize(const Vector2f& size) + { + m_size = size; + UpdateProjectionMatrix(); + } + inline void CameraComponent::UpdateProjectionMatrix() { - //FIXME switch (m_projectionType) { case ProjectionType::Orthographic: - m_viewerInstance.UpdateProjectionMatrix(Nz::Matrix4f::Ortho(0.f, 1920.f, 0.f, 1080.f)); + if (m_size.x < 0.f || m_size.y < 0.f) + m_viewerInstance.UpdateProjectionMatrix(Matrix4f::Ortho(0.f, float(m_viewport.x), 0.f, float(m_viewport.y), m_zNear, m_zFar)); + else + m_viewerInstance.UpdateProjectionMatrix(Matrix4f::Ortho(0.f, m_size.x, 0.f, m_size.y, m_zNear, m_zFar)); break; case ProjectionType::Perspective: - m_viewerInstance.UpdateProjectionMatrix(Nz::Matrix4f::Perspective(Nz::DegreeAnglef(70.f), 16.f / 9.f, 1.f, 1000.f)); + m_viewerInstance.UpdateProjectionMatrix(Matrix4f::Perspective(m_fov, m_aspectRatio, m_zNear, m_zFar)); break; } } + + inline void CameraComponent::UpdateViewport() + { + NazaraAssert(m_renderTarget, "no rendertarget!"); + return UpdateViewport(m_renderTarget->GetSize()); + } + + inline void CameraComponent::UpdateViewport(Vector2ui renderTargetSize) + { + renderTargetSize.y = std::max(renderTargetSize.y, 1U); // Let's make sure we won't divide by zero + + // Our target region is expressed as % of the viewport dimensions, let's compute it in pixels + Rectf fViewport(m_targetRegion); + fViewport.x *= renderTargetSize.x; + fViewport.y *= renderTargetSize.y; + fViewport.width *= renderTargetSize.x; + fViewport.height *= renderTargetSize.y; + + m_aspectRatio = fViewport.width / fViewport.height; + + // Convert it back to int + m_viewport.Set(fViewport); + + UpdateProjectionMatrix(); + } } diff --git a/src/Nazara/Graphics/Components/CameraComponent.cpp b/src/Nazara/Graphics/Components/CameraComponent.cpp index 05994af16..b47892b4f 100644 --- a/src/Nazara/Graphics/Components/CameraComponent.cpp +++ b/src/Nazara/Graphics/Components/CameraComponent.cpp @@ -25,4 +25,31 @@ namespace Nz { return m_viewerInstance; } + + const Recti& CameraComponent::GetViewport() const + { + return m_viewport; + } + + void CameraComponent::UpdateTarget(const RenderTarget* renderTarget) + { + m_onRenderTargetRelease.Disconnect(); + m_onRenderTargetSizeChange.Disconnect(); + + m_renderTarget = renderTarget; + if (m_renderTarget) + { + m_onRenderTargetRelease.Connect(m_renderTarget->OnRenderTargetRelease, [this](const RenderTarget*) + { + UpdateTarget(nullptr); + }); + + m_onRenderTargetSizeChange.Connect(m_renderTarget->OnRenderTargetSizeChange, [this](const RenderTarget*, const Vector2ui& newSize) + { + UpdateViewport(newSize); + }); + + UpdateViewport(); + } + } } diff --git a/src/Nazara/Graphics/ForwardFramePipeline.cpp b/src/Nazara/Graphics/ForwardFramePipeline.cpp index 717c9f98d..c0e4b3b03 100644 --- a/src/Nazara/Graphics/ForwardFramePipeline.cpp +++ b/src/Nazara/Graphics/ForwardFramePipeline.cpp @@ -243,10 +243,12 @@ namespace Nz return FramePassExecution::Execute; }); - framePass.SetCommandCallback([this, viewer = viewer](CommandBufferBuilder& builder, const Recti& renderRect) + framePass.SetCommandCallback([this, viewer = viewer](CommandBufferBuilder& builder, const Recti& /*renderRect*/) { - builder.SetScissor(renderRect); - builder.SetViewport(renderRect); + Recti viewport = viewer->GetViewport(); + + builder.SetScissor(viewport); + builder.SetViewport(viewport); builder.BindShaderBinding(Graphics::ViewerBindingSet, viewer->GetViewerInstance().GetShaderBinding()); for (const auto& [worldInstance, renderables] : m_renderables)