Graphics: Add RenderSystem and frame pipeline
This commit is contained in:
parent
428a706fbe
commit
4ac5fe7cba
|
|
@ -3,6 +3,7 @@
|
|||
#include <Nazara/Platform.hpp>
|
||||
#include <Nazara/Graphics.hpp>
|
||||
#include <Nazara/Graphics/Components.hpp>
|
||||
#include <Nazara/Graphics/Systems.hpp>
|
||||
#include <Nazara/Math/PidController.hpp>
|
||||
#include <Nazara/Physics3D.hpp>
|
||||
#include <Nazara/Physics3D/Components.hpp>
|
||||
|
|
@ -49,6 +50,8 @@ int main()
|
|||
return __LINE__;
|
||||
}
|
||||
|
||||
Nz::RenderWindowImpl* windowImpl = window.GetImpl();
|
||||
|
||||
std::shared_ptr<Nz::Mesh> spaceshipMesh = Nz::Mesh::LoadFromFile(resourceDir / "Spaceship/spaceship.obj", meshParams);
|
||||
if (!spaceshipMesh)
|
||||
{
|
||||
|
|
@ -89,10 +92,6 @@ int main()
|
|||
|
||||
Nz::Vector2ui windowSize = window.GetSize();
|
||||
|
||||
Nz::ViewerInstance viewerInstance;
|
||||
viewerInstance.UpdateTargetSize(Nz::Vector2f(window.GetSize()));
|
||||
viewerInstance.UpdateProjViewMatrices(Nz::Matrix4f::Perspective(Nz::DegreeAnglef(70.f), float(windowSize.x) / windowSize.y, 0.1f, 1000.f), Nz::Matrix4f::Translate(Nz::Vector3f::Backward() * 1));
|
||||
|
||||
Nz::VertexMapper vertexMapper(*spaceshipMesh->GetSubMesh(0), Nz::BufferAccess::ReadOnly);
|
||||
Nz::SparsePtr<Nz::Vector3f> vertices = vertexMapper.GetComponentPtr<Nz::Vector3f>(Nz::VertexComponent::Position);
|
||||
|
||||
|
|
@ -100,8 +99,13 @@ int main()
|
|||
entt::registry registry;
|
||||
|
||||
Nz::Physics3DSystem physSytem(registry);
|
||||
Nz::RenderSystem renderSystem(registry);
|
||||
|
||||
|
||||
entt::entity viewer = registry.create();
|
||||
registry.emplace<Nz::NodeComponent>(viewer);
|
||||
registry.emplace<Nz::CameraComponent>(viewer, windowImpl);
|
||||
|
||||
auto shipCollider = std::make_shared<Nz::ConvexCollider3D>(vertices, vertexMapper.GetVertexCount(), 0.01f);
|
||||
|
||||
std::shared_ptr<Nz::Material> colliderMat = std::make_shared<Nz::Material>(Nz::BasicMaterial::GetSettings());
|
||||
|
|
@ -122,41 +126,41 @@ int main()
|
|||
}
|
||||
|
||||
entt::entity playerEntity = registry.create();
|
||||
Nz::Node headingNode;
|
||||
{
|
||||
auto& entityNode = registry.emplace<Nz::NodeComponent>(playerEntity);
|
||||
entityNode.SetPosition(Nz::Vector3f(12.5f, 0.f, 25.f));
|
||||
|
||||
entt::entity headingEntity = registry.create();
|
||||
{
|
||||
auto& entityGfx = registry.emplace<Nz::GraphicsComponent>(playerEntity);
|
||||
entityGfx.AttachRenderable(model);
|
||||
|
||||
auto& entityNode = registry.emplace<Nz::NodeComponent>(playerEntity);
|
||||
entityNode.SetPosition(Nz::Vector3f(12.5f, 0.f, 25.f));
|
||||
|
||||
auto& entityPhys = registry.emplace<Nz::RigidBody3DComponent>(playerEntity, physSytem.CreateRigidBody(shipCollider));
|
||||
entityPhys.SetMass(50.f);
|
||||
entityPhys.SetAngularDamping(Nz::Vector3f::Zero());
|
||||
|
||||
headingNode.SetParent(entityNode);
|
||||
auto& headingNode = registry.emplace<Nz::NodeComponent>(headingEntity);
|
||||
headingNode.SetInheritRotation(false);
|
||||
headingNode.SetRotation(entityNode.GetRotation());
|
||||
headingNode.SetParent(registry, playerEntity);
|
||||
}
|
||||
|
||||
|
||||
Nz::Node cameraNode;
|
||||
cameraNode.SetParent(headingNode);
|
||||
cameraNode.SetPosition(Nz::Vector3f::Backward() * 2.5f + Nz::Vector3f::Up() * 1.f);
|
||||
registry.get<Nz::NodeComponent>(viewer).SetParent(registry, headingEntity);
|
||||
registry.get<Nz::NodeComponent>(viewer).SetPosition(Nz::Vector3f::Backward() * 2.5f + Nz::Vector3f::Up() * 1.f);
|
||||
|
||||
for (std::size_t x = 0; x < 1; ++x)
|
||||
for (std::size_t x = 0; x < 5; ++x)
|
||||
{
|
||||
for (std::size_t y = 0; y < 1; ++y)
|
||||
for (std::size_t y = 0; y < 5; ++y)
|
||||
{
|
||||
for (std::size_t z = 0; z < 10; ++z)
|
||||
for (std::size_t z = 0; z < 5; ++z)
|
||||
{
|
||||
entt::entity entity = registry.create();
|
||||
auto& entityNode = registry.emplace<Nz::NodeComponent>(entity);
|
||||
entityNode.SetPosition(Nz::Vector3f(x * 2.f, y * 1.5f, z * 2.f));
|
||||
|
||||
auto& entityGfx = registry.emplace<Nz::GraphicsComponent>(entity);
|
||||
entityGfx.AttachRenderable(model);
|
||||
|
||||
auto& entityNode = registry.emplace<Nz::NodeComponent>(entity);
|
||||
entityNode.SetPosition(Nz::Vector3f(x * 2.f, y * 1.5f, z * 2.f));
|
||||
|
||||
auto& entityPhys = registry.emplace<Nz::RigidBody3DComponent>(entity, physSytem.CreateRigidBody(shipCollider));
|
||||
entityPhys.SetMass(1.f);
|
||||
entityPhys.SetAngularDamping(Nz::Vector3f::Zero());
|
||||
|
|
@ -165,46 +169,6 @@ int main()
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
Nz::RenderWindowImpl* windowImpl = window.GetImpl();
|
||||
std::shared_ptr<Nz::CommandPool> commandPool = windowImpl->CreateCommandPool(Nz::QueueType::Graphics);
|
||||
|
||||
Nz::CommandBufferPtr drawCommandBuffer;
|
||||
auto RebuildCommandBuffer = [&]
|
||||
{
|
||||
Nz::Vector2ui windowSize = window.GetSize();
|
||||
drawCommandBuffer = commandPool->BuildCommandBuffer([&](Nz::CommandBufferBuilder& builder)
|
||||
{
|
||||
Nz::Recti renderRect(0, 0, window.GetSize().x, window.GetSize().y);
|
||||
|
||||
Nz::CommandBufferBuilder::ClearValues clearValues[2];
|
||||
clearValues[0].color = Nz::Color(80, 80, 80);
|
||||
clearValues[1].depth = 1.f;
|
||||
clearValues[1].stencil = 0;
|
||||
|
||||
builder.BeginDebugRegion("Main window rendering", Nz::Color::Green);
|
||||
{
|
||||
builder.BeginRenderPass(windowImpl->GetFramebuffer(), windowImpl->GetRenderPass(), renderRect, { clearValues[0], clearValues[1] });
|
||||
{
|
||||
builder.SetScissor(Nz::Recti{ 0, 0, int(windowSize.x), int(windowSize.y) });
|
||||
builder.SetViewport(Nz::Recti{ 0, 0, int(windowSize.x), int(windowSize.y) });
|
||||
builder.BindShaderBinding(Nz::Graphics::ViewerBindingSet, viewerInstance.GetShaderBinding());
|
||||
|
||||
auto view = registry.view<const Nz::GraphicsComponent>();
|
||||
for (auto [entity, gfxComponent] : view.each())
|
||||
{
|
||||
const Nz::WorldInstance& worldInstance = gfxComponent.GetWorldInstance();
|
||||
for (const auto& renderable : gfxComponent.GetRenderables())
|
||||
renderable->Draw(builder, worldInstance);
|
||||
}
|
||||
}
|
||||
builder.EndRenderPass();
|
||||
}
|
||||
builder.EndDebugRegion();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Nz::Vector3f viewerPos = Nz::Vector3f::Zero();
|
||||
|
||||
Nz::EulerAnglesf camAngles(0.f, 0.f, 0.f);
|
||||
|
|
@ -254,13 +218,19 @@ int main()
|
|||
{
|
||||
auto view = registry.view<Nz::GraphicsComponent>();
|
||||
for (auto [entity, gfxComponent] : view.each())
|
||||
{
|
||||
gfxComponent.AttachRenderable(colliderModel);
|
||||
registry.patch<Nz::GraphicsComponent>(entity);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto view = registry.view<Nz::GraphicsComponent>();
|
||||
for (auto [entity, gfxComponent] : view.each())
|
||||
{
|
||||
gfxComponent.DetachRenderable(colliderModel);
|
||||
registry.patch<Nz::GraphicsComponent>(entity);
|
||||
}
|
||||
}
|
||||
rebuildCommandBuffer = true;
|
||||
}
|
||||
|
|
@ -278,15 +248,15 @@ int main()
|
|||
|
||||
camQuat = camAngles;
|
||||
|
||||
headingNode.SetRotation(camQuat);
|
||||
registry.get<Nz::NodeComponent>(headingEntity).SetRotation(camQuat);
|
||||
break;
|
||||
}
|
||||
|
||||
case Nz::WindowEventType::Resized:
|
||||
{
|
||||
Nz::Vector2ui windowSize = window.GetSize();
|
||||
viewerInstance.UpdateProjectionMatrix(Nz::Matrix4f::Perspective(Nz::DegreeAnglef(70.f), float(windowSize.x) / windowSize.y, 0.1f, 1000.f));
|
||||
viewerInstance.UpdateTargetSize(Nz::Vector2f(windowSize));
|
||||
//viewerInstance.UpdateProjectionMatrix(Nz::Matrix4f::Perspective(Nz::DegreeAnglef(70.f), float(windowSize.x) / windowSize.y, 0.1f, 1000.f));
|
||||
//viewerInstance.UpdateTargetSize(Nz::Vector2f(windowSize));
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -306,11 +276,11 @@ int main()
|
|||
Nz::RigidBody3DComponent& playerShipBody = registry.get<Nz::RigidBody3DComponent>(playerEntity);
|
||||
Nz::Quaternionf currentRotation = playerShipBody.GetRotation();
|
||||
|
||||
Nz::Vector3f desiredHeading = headingNode.GetForward();
|
||||
Nz::Vector3f desiredHeading = registry.get<Nz::NodeComponent>(headingEntity).GetForward();
|
||||
Nz::Vector3f currentHeading = currentRotation * Nz::Vector3f::Forward();
|
||||
Nz::Vector3f headingError = currentHeading.CrossProduct(desiredHeading);
|
||||
|
||||
Nz::Vector3f desiredUp = headingNode.GetUp();
|
||||
Nz::Vector3f desiredUp = registry.get<Nz::NodeComponent>(headingEntity).GetUp();
|
||||
Nz::Vector3f currentUp = currentRotation * Nz::Vector3f::Up();
|
||||
Nz::Vector3f upError = currentUp.CrossProduct(desiredUp);
|
||||
|
||||
|
|
@ -342,49 +312,7 @@ int main()
|
|||
if (!frame)
|
||||
continue;
|
||||
|
||||
Nz::UploadPool& uploadPool = frame.GetUploadPool();
|
||||
|
||||
viewerInstance.UpdateViewMatrix(Nz::Matrix4f::ViewMatrix(cameraNode.GetPosition(Nz::CoordSys::Global), cameraNode.GetRotation(Nz::CoordSys::Global)));
|
||||
|
||||
frame.Execute([&](Nz::CommandBufferBuilder& builder)
|
||||
{
|
||||
builder.BeginDebugRegion("UBO Update", Nz::Color::Yellow);
|
||||
{
|
||||
builder.PreTransferBarrier();
|
||||
|
||||
viewerInstance.UpdateBuffers(uploadPool, builder);
|
||||
/*
|
||||
modelInstance.UpdateBuffers(uploadPool, builder);
|
||||
modelInstance2.UpdateBuffers(uploadPool, builder);
|
||||
*/
|
||||
|
||||
auto view = registry.view<Nz::GraphicsComponent, const Nz::NodeComponent>();
|
||||
for (auto [entity, gfxComponent, nodeComponent] : view.each())
|
||||
{
|
||||
Nz::WorldInstance& worldInstance = gfxComponent.GetWorldInstance();
|
||||
worldInstance.UpdateWorldMatrix(nodeComponent.GetTransformMatrix());
|
||||
|
||||
worldInstance.UpdateBuffers(uploadPool, builder);
|
||||
}
|
||||
|
||||
if (material->Update(frame, builder))
|
||||
rebuildCommandBuffer = true;
|
||||
|
||||
if (colliderMat->Update(frame, builder))
|
||||
rebuildCommandBuffer = true;
|
||||
|
||||
builder.PostTransferBarrier();
|
||||
}
|
||||
builder.EndDebugRegion();
|
||||
}, Nz::QueueType::Transfer);
|
||||
|
||||
if (rebuildCommandBuffer || frame.IsFramebufferInvalidated())
|
||||
{
|
||||
frame.PushForRelease(std::move(drawCommandBuffer));
|
||||
RebuildCommandBuffer();
|
||||
}
|
||||
|
||||
frame.SubmitCommandBuffer(drawCommandBuffer.get(), Nz::QueueType::Graphics);
|
||||
renderSystem.Render(registry, frame);
|
||||
|
||||
frame.Present();
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
class CameraComponent;
|
||||
class GraphicsComponent;
|
||||
class NodeComponent;
|
||||
class RigidBody3DComponent;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,19 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
namespace Detail
|
||||
{
|
||||
template<typename T>
|
||||
struct RegisterComponent
|
||||
{
|
||||
void operator()(entt::id_type& expectedId)
|
||||
{
|
||||
if (entt::type_seq<T>() != expectedId++)
|
||||
throw std::runtime_error(std::string(entt::type_name<T>::value()) + " has wrong index, please initialize Nazara ECS before instancing your own components");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup core
|
||||
* \class Nz::ECS
|
||||
|
|
@ -21,14 +34,8 @@ namespace Nz
|
|||
|
||||
inline void ECS::RegisterComponents()
|
||||
{
|
||||
if (entt::type_seq<NodeComponent>() != 0)
|
||||
throw std::runtime_error("NodeComponent has wrong index, please initialize Nazara ECS before instancing your own components");
|
||||
|
||||
if (entt::type_seq<GraphicsComponent>() != 1)
|
||||
throw std::runtime_error("GraphicsComponent has wrong index, please initialize Nazara ECS before instancing your own components");
|
||||
|
||||
if (entt::type_seq<RigidBody3DComponent>() != 2)
|
||||
throw std::runtime_error("GraphicsComponent has wrong index, please initialize Nazara ECS before instancing your own components");
|
||||
entt::id_type expectedId = 0;
|
||||
TypeListApply<TypeList<NodeComponent, CameraComponent, GraphicsComponent, RigidBody3DComponent>, Detail::RegisterComponent>(expectedId);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,14 +29,17 @@
|
|||
#ifndef NAZARA_GLOBAL_GRAPHICS_HPP
|
||||
#define NAZARA_GLOBAL_GRAPHICS_HPP
|
||||
|
||||
#include <Nazara/Graphics/AbstractViewer.hpp>
|
||||
#include <Nazara/Graphics/BakedFrameGraph.hpp>
|
||||
#include <Nazara/Graphics/BasicMaterial.hpp>
|
||||
#include <Nazara/Graphics/Config.hpp>
|
||||
#include <Nazara/Graphics/CullingList.hpp>
|
||||
#include <Nazara/Graphics/Enums.hpp>
|
||||
#include <Nazara/Graphics/ForwardFramePipeline.hpp>
|
||||
#include <Nazara/Graphics/FrameGraph.hpp>
|
||||
#include <Nazara/Graphics/FramePass.hpp>
|
||||
#include <Nazara/Graphics/FramePassAttachment.hpp>
|
||||
#include <Nazara/Graphics/FramePipeline.hpp>
|
||||
#include <Nazara/Graphics/GraphicalMesh.hpp>
|
||||
#include <Nazara/Graphics/Graphics.hpp>
|
||||
#include <Nazara/Graphics/InstancedRenderable.hpp>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_ABSTRACTVIEWER_HPP
|
||||
#define NAZARA_ABSTRACTVIEWER_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Graphics/Config.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class RenderTarget;
|
||||
class ViewerInstance;
|
||||
|
||||
class NAZARA_GRAPHICS_API AbstractViewer
|
||||
{
|
||||
public:
|
||||
AbstractViewer() = default;
|
||||
~AbstractViewer() = default;
|
||||
|
||||
virtual const RenderTarget& GetRenderTarget() = 0;
|
||||
virtual ViewerInstance& GetViewerInstance() = 0;
|
||||
virtual const ViewerInstance& GetViewerInstance() const = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Graphics/AbstractViewer.inl>
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Graphics/AbstractViewer.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
}
|
||||
|
||||
#include <Nazara/Graphics/DebugOff.hpp>
|
||||
|
|
@ -29,6 +29,7 @@
|
|||
#ifndef NAZARA_GLOBAL_GRAPHICS_COMPONENTS_HPP
|
||||
#define NAZARA_GLOBAL_GRAPHICS_COMPONENTS_HPP
|
||||
|
||||
#include <Nazara/Graphics/Components/CameraComponent.hpp>
|
||||
#include <Nazara/Graphics/Components/GraphicsComponent.hpp>
|
||||
|
||||
#endif // NAZARA_GLOBAL_GRAPHICS_COMPONENTS_HPP
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
// Copyright (C) 2021 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_CAMERACOMPONENT_HPP
|
||||
#define NAZARA_CAMERACOMPONENT_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Graphics/AbstractViewer.hpp>
|
||||
#include <Nazara/Graphics/Enums.hpp>
|
||||
#include <Nazara/Graphics/ViewerInstance.hpp>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class NAZARA_GRAPHICS_API CameraComponent : public AbstractViewer
|
||||
{
|
||||
public:
|
||||
inline CameraComponent(const RenderTarget* renderTarget, ProjectionType projectionType = ProjectionType::Perspective);
|
||||
CameraComponent(const CameraComponent&) = default;
|
||||
CameraComponent(CameraComponent&&) = default;
|
||||
~CameraComponent() = default;
|
||||
|
||||
const RenderTarget& GetRenderTarget() override;
|
||||
ViewerInstance& GetViewerInstance() override;
|
||||
const ViewerInstance& GetViewerInstance() const override;
|
||||
|
||||
inline void UpdateTarget(const RenderTarget* framebuffer);
|
||||
inline void UpdateProjectionType(ProjectionType projectionType);
|
||||
|
||||
CameraComponent& operator=(const CameraComponent&) = default;
|
||||
CameraComponent& operator=(CameraComponent&&) = default;
|
||||
|
||||
private:
|
||||
inline void UpdateProjectionMatrix();
|
||||
|
||||
const RenderTarget* m_renderTarget;
|
||||
ProjectionType m_projectionType;
|
||||
ViewerInstance m_viewerInstance;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Graphics/Components/CameraComponent.inl>
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright (C) 2021 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <Nazara/Graphics/Components/CameraComponent.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
inline CameraComponent::CameraComponent(const RenderTarget* renderTarget, ProjectionType projectionType) :
|
||||
m_projectionType(projectionType),
|
||||
m_renderTarget(renderTarget)
|
||||
{
|
||||
UpdateProjectionMatrix();
|
||||
}
|
||||
|
||||
inline void CameraComponent::UpdateTarget(const RenderTarget* renderTarget)
|
||||
{
|
||||
m_renderTarget = renderTarget;
|
||||
}
|
||||
|
||||
inline void CameraComponent::UpdateProjectionType(ProjectionType projectionType)
|
||||
{
|
||||
m_projectionType = projectionType;
|
||||
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));
|
||||
break;
|
||||
|
||||
case ProjectionType::Perspective:
|
||||
m_viewerInstance.UpdateProjectionMatrix(Nz::Matrix4f::Perspective(Nz::DegreeAnglef(70.f), 16.f / 9.f, 1.f, 1000.f));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ namespace Nz
|
|||
class NAZARA_GRAPHICS_API GraphicsComponent
|
||||
{
|
||||
public:
|
||||
GraphicsComponent() = default;
|
||||
GraphicsComponent();
|
||||
GraphicsComponent(const GraphicsComponent&) = default;
|
||||
GraphicsComponent(GraphicsComponent&&) = default;
|
||||
~GraphicsComponent() = default;
|
||||
|
|
@ -34,9 +34,12 @@ namespace Nz
|
|||
GraphicsComponent& operator=(const GraphicsComponent&) = default;
|
||||
GraphicsComponent& operator=(GraphicsComponent&&) = default;
|
||||
|
||||
NazaraSignal(OnRenderableAttached, GraphicsComponent* /*graphicsComponent*/, const std::shared_ptr<InstancedRenderable>& /*renderable*/);
|
||||
NazaraSignal(OnRenderableDetach, GraphicsComponent* /*graphicsComponent*/, const std::shared_ptr<InstancedRenderable>& /*renderable*/);
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<InstancedRenderable>> m_renderables;
|
||||
WorldInstance m_worldInstance;
|
||||
std::unique_ptr<WorldInstance> m_worldInstance;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,22 +2,32 @@
|
|||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <Nazara/Utility/Components/NodeComponent.hpp>
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
#include "GraphicsComponent.hpp"
|
||||
#include <Nazara/Graphics/Components/GraphicsComponent.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
inline GraphicsComponent::GraphicsComponent()
|
||||
{
|
||||
m_worldInstance = std::make_unique<WorldInstance>(); //< FIXME
|
||||
}
|
||||
|
||||
inline void GraphicsComponent::AttachRenderable(std::shared_ptr<InstancedRenderable> renderable)
|
||||
{
|
||||
m_renderables.push_back(std::move(renderable));
|
||||
|
||||
OnRenderableAttached(this, m_renderables.back());
|
||||
}
|
||||
|
||||
inline void GraphicsComponent::DetachRenderable(const std::shared_ptr<InstancedRenderable>& renderable)
|
||||
{
|
||||
auto it = std::find(m_renderables.begin(), m_renderables.end(), renderable);
|
||||
if (it != m_renderables.end())
|
||||
{
|
||||
OnRenderableDetach(this, renderable);
|
||||
|
||||
m_renderables.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
inline const std::vector<std::shared_ptr<InstancedRenderable>>& GraphicsComponent::GetRenderables() const
|
||||
|
|
@ -27,11 +37,11 @@ namespace Nz
|
|||
|
||||
inline WorldInstance& GraphicsComponent::GetWorldInstance()
|
||||
{
|
||||
return m_worldInstance;
|
||||
return *m_worldInstance;
|
||||
}
|
||||
|
||||
inline const WorldInstance& GraphicsComponent::GetWorldInstance() const
|
||||
{
|
||||
return m_worldInstance;
|
||||
return *m_worldInstance;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,12 @@ namespace Nz
|
|||
Sphere,
|
||||
Volume
|
||||
};
|
||||
|
||||
enum class ProjectionType
|
||||
{
|
||||
Orthographic,
|
||||
Perspective
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_ENUMS_GRAPHICS_HPP
|
||||
|
|
|
|||
|
|
@ -0,0 +1,84 @@
|
|||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_FORWARDFRAMEPIPELINE_HPP
|
||||
#define NAZARA_FORWARDFRAMEPIPELINE_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Graphics/BakedFrameGraph.hpp>
|
||||
#include <Nazara/Graphics/Config.hpp>
|
||||
#include <Nazara/Graphics/FramePipeline.hpp>
|
||||
#include <Nazara/Graphics/InstancedRenderable.hpp>
|
||||
#include <Nazara/Graphics/Material.hpp>
|
||||
#include <Nazara/Renderer/ShaderBinding.hpp>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class NAZARA_GRAPHICS_API ForwardFramePipeline : public FramePipeline
|
||||
{
|
||||
public:
|
||||
ForwardFramePipeline();
|
||||
ForwardFramePipeline(const ForwardFramePipeline&) = delete;
|
||||
ForwardFramePipeline(ForwardFramePipeline&&) = delete;
|
||||
~ForwardFramePipeline() = default;
|
||||
|
||||
void InvalidateViewer(AbstractViewer* viewerInstance) override;
|
||||
void InvalidateWorldInstance(WorldInstance* worldInstance) override;
|
||||
|
||||
void RegisterInstancedDrawable(WorldInstance* worldInstance, const InstancedRenderable* instancedRenderable) override;
|
||||
void RegisterViewer(AbstractViewer* viewerInstance) override;
|
||||
|
||||
void Render(RenderFrame& renderFrame) override;
|
||||
|
||||
void UnregisterInstancedDrawable(WorldInstance* worldInstance, const InstancedRenderable* instancedRenderable) override;
|
||||
void UnregisterViewer(AbstractViewer* viewerInstance) override;
|
||||
|
||||
ForwardFramePipeline& operator=(const ForwardFramePipeline&) = delete;
|
||||
ForwardFramePipeline& operator=(ForwardFramePipeline&&) = delete;
|
||||
|
||||
private:
|
||||
BakedFrameGraph BuildFrameGraph();
|
||||
void RegisterMaterial(Material* material);
|
||||
void UnregisterMaterial(Material* material);
|
||||
|
||||
struct MaterialData
|
||||
{
|
||||
std::size_t usedCount = 0;
|
||||
|
||||
NazaraSlot(Material, OnMaterialInvalidated, onMaterialInvalided);
|
||||
};
|
||||
|
||||
struct RenderableData
|
||||
{
|
||||
NazaraSlot(InstancedRenderable, OnMaterialInvalidated, onMaterialInvalidated);
|
||||
};
|
||||
|
||||
struct ViewerData
|
||||
{
|
||||
std::size_t colorAttachment;
|
||||
std::size_t depthStencilAttachment;
|
||||
ShaderBindingPtr blitShaderBinding;
|
||||
};
|
||||
|
||||
std::size_t m_forwardPass;
|
||||
std::unordered_map<AbstractViewer*, ViewerData> m_viewers;
|
||||
std::unordered_map<Material*, MaterialData> m_materials;
|
||||
std::unordered_map<WorldInstance*, std::unordered_map<const InstancedRenderable*, RenderableData>> m_renderables;
|
||||
std::unordered_set<AbstractViewer*> m_invalidatedViewerInstances;
|
||||
std::unordered_set<Material*> m_invalidatedMaterials;
|
||||
std::unordered_set<WorldInstance*> m_invalidatedWorldInstances;
|
||||
BakedFrameGraph m_bakedFrameGraph;
|
||||
bool m_rebuildFrameGraph;
|
||||
bool m_rebuildForwardPass;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Graphics/ForwardFramePipeline.inl>
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Graphics/ForwardFramePipeline.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
}
|
||||
|
||||
#include <Nazara/Graphics/DebugOff.hpp>
|
||||
|
|
@ -9,8 +9,10 @@
|
|||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Core/Color.hpp>
|
||||
#include <Nazara/Math/Rect.hpp>
|
||||
#include <Nazara/Graphics/Config.hpp>
|
||||
#include <Nazara/Graphics/FramePassAttachment.hpp>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
|
@ -30,7 +32,7 @@ namespace Nz
|
|||
class NAZARA_GRAPHICS_API FramePass
|
||||
{
|
||||
public:
|
||||
using CommandCallback = std::function<void(CommandBufferBuilder& builder)>;
|
||||
using CommandCallback = std::function<void(CommandBufferBuilder& builder, const Recti& renderRect)>;
|
||||
using ExecutionCallback = std::function<FramePassExecution()>;
|
||||
struct DepthStencilClear;
|
||||
struct Input;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_FRAMEPIPELINE_HPP
|
||||
#define NAZARA_FRAMEPIPELINE_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Graphics/Config.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class AbstractViewer;
|
||||
class InstancedRenderable;
|
||||
class RenderFrame;
|
||||
class WorldInstance;
|
||||
|
||||
class NAZARA_GRAPHICS_API FramePipeline
|
||||
{
|
||||
public:
|
||||
FramePipeline() = default;
|
||||
FramePipeline(const FramePipeline&) = delete;
|
||||
FramePipeline(FramePipeline&&) noexcept = default;
|
||||
virtual ~FramePipeline();
|
||||
|
||||
virtual void InvalidateViewer(AbstractViewer* viewerInstance) = 0;
|
||||
virtual void InvalidateWorldInstance(WorldInstance* worldInstance) = 0;
|
||||
|
||||
virtual void RegisterInstancedDrawable(WorldInstance* worldInstance, const InstancedRenderable* instancedRenderable) = 0;
|
||||
virtual void RegisterViewer(AbstractViewer* viewerInstance) = 0;
|
||||
|
||||
virtual void Render(RenderFrame& renderFrame) = 0;
|
||||
|
||||
virtual void UnregisterInstancedDrawable(WorldInstance* worldInstance, const InstancedRenderable* instancedRenderable) = 0;
|
||||
virtual void UnregisterViewer(AbstractViewer* viewerInstance) = 0;
|
||||
|
||||
FramePipeline& operator=(const FramePipeline&) = delete;
|
||||
FramePipeline& operator=(FramePipeline&&) noexcept = default;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Graphics/FramePipeline.inl>
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Graphics/FramePipeline.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
}
|
||||
|
||||
#include <Nazara/Graphics/DebugOff.hpp>
|
||||
|
|
@ -31,6 +31,11 @@ namespace Nz
|
|||
Graphics(Config config);
|
||||
~Graphics();
|
||||
|
||||
inline const std::shared_ptr<RenderPipeline>& GetBlitPipeline() const;
|
||||
inline const std::shared_ptr<RenderPipelineLayout>& GetBlitPipelineLayout() const;
|
||||
inline const std::shared_ptr<AbstractBuffer>& GetFullscreenVertexBuffer() const;
|
||||
inline const std::shared_ptr<VertexDeclaration>& GetFullscreenVertexDeclaration() const;
|
||||
inline PixelFormat GetPreferredDepthStencilFormat() const;
|
||||
inline const std::shared_ptr<RenderPipelineLayout>& GetReferencePipelineLayout() const;
|
||||
inline const std::shared_ptr<RenderDevice>& GetRenderDevice() const;
|
||||
inline TextureSamplerCache& GetSamplerCache();
|
||||
|
|
@ -48,9 +53,18 @@ namespace Nz
|
|||
static void FillWorldPipelineLayout(RenderPipelineLayoutInfo& layoutInfo, UInt32 set = WorldBindingSet);
|
||||
|
||||
private:
|
||||
void BuildBlitPipeline();
|
||||
void BuildFullscreenVertexBuffer();
|
||||
void SelectDepthStencilFormats();
|
||||
|
||||
std::optional<TextureSamplerCache> m_samplerCache;
|
||||
std::shared_ptr<AbstractBuffer> m_fullscreenVertexBuffer;
|
||||
std::shared_ptr<RenderDevice> m_renderDevice;
|
||||
std::shared_ptr<RenderPipeline> m_blitPipeline;
|
||||
std::shared_ptr<RenderPipelineLayout> m_blitPipelineLayout;
|
||||
std::shared_ptr<RenderPipelineLayout> m_referencePipelineLayout;
|
||||
std::shared_ptr<VertexDeclaration> m_fullscreenVertexDeclaration;
|
||||
PixelFormat m_preferredDepthStencilFormat;
|
||||
|
||||
static Graphics* s_instance;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,6 +7,31 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
inline const std::shared_ptr<RenderPipeline>& Graphics::GetBlitPipeline() const
|
||||
{
|
||||
return m_blitPipeline;
|
||||
}
|
||||
|
||||
inline const std::shared_ptr<RenderPipelineLayout>& Graphics::GetBlitPipelineLayout() const
|
||||
{
|
||||
return m_blitPipelineLayout;
|
||||
}
|
||||
|
||||
inline const std::shared_ptr<AbstractBuffer>& Graphics::GetFullscreenVertexBuffer() const
|
||||
{
|
||||
return m_fullscreenVertexBuffer;
|
||||
}
|
||||
|
||||
inline const std::shared_ptr<VertexDeclaration>& Graphics::GetFullscreenVertexDeclaration() const
|
||||
{
|
||||
return m_fullscreenVertexDeclaration;
|
||||
}
|
||||
|
||||
inline PixelFormat Graphics::GetPreferredDepthStencilFormat() const
|
||||
{
|
||||
return m_preferredDepthStencilFormat;
|
||||
}
|
||||
|
||||
inline const std::shared_ptr<RenderPipelineLayout>& Graphics::GetReferencePipelineLayout() const
|
||||
{
|
||||
return m_referencePipelineLayout;
|
||||
|
|
|
|||
|
|
@ -8,11 +8,14 @@
|
|||
#define NAZARA_INSTANCEDRENDERABLE_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Core/Signal.hpp>
|
||||
#include <Nazara/Graphics/Config.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class CommandBufferBuilder;
|
||||
class Material;
|
||||
class WorldInstance;
|
||||
|
||||
class NAZARA_GRAPHICS_API InstancedRenderable
|
||||
|
|
@ -23,10 +26,15 @@ namespace Nz
|
|||
InstancedRenderable(InstancedRenderable&&) noexcept = default;
|
||||
~InstancedRenderable();
|
||||
|
||||
virtual void Draw(CommandBufferBuilder& commandBuffer, const WorldInstance& instance) const = 0;
|
||||
virtual void Draw(CommandBufferBuilder& commandBuffer) const = 0;
|
||||
|
||||
virtual const std::shared_ptr<Material>& GetMaterial(std::size_t i) const = 0;
|
||||
virtual std::size_t GetMaterialCount() const = 0;
|
||||
|
||||
InstancedRenderable& operator=(const InstancedRenderable&) = delete;
|
||||
InstancedRenderable& operator=(InstancedRenderable&&) noexcept = default;
|
||||
|
||||
NazaraSignal(OnMaterialInvalidated, InstancedRenderable* /*instancedRenderable*/, std::size_t /*materialIndex*/, const std::shared_ptr<Material>& /*newMaterial*/);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -75,8 +75,8 @@ namespace Nz
|
|||
inline const std::shared_ptr<Texture>& GetTexture(std::size_t textureIndex) const;
|
||||
inline const TextureSamplerInfo& GetTextureSampler(std::size_t textureIndex) const;
|
||||
inline const std::shared_ptr<AbstractBuffer>& GetUniformBuffer(std::size_t bufferIndex) const;
|
||||
inline std::vector<UInt8>& GetUniformBufferData(std::size_t bufferIndex);
|
||||
inline const std::vector<UInt8>& GetUniformBufferConstData(std::size_t bufferIndex);
|
||||
inline std::vector<UInt8>& GetUniformBufferData(std::size_t bufferIndex);
|
||||
|
||||
inline bool HasTexture(std::size_t textureIndex) const;
|
||||
inline bool HasVertexColor() const;
|
||||
|
|
@ -109,12 +109,14 @@ namespace Nz
|
|||
bool Update(RenderFrame& renderFrame, CommandBufferBuilder& builder);
|
||||
|
||||
// Signals:
|
||||
NazaraSignal(OnMaterialInvalidated, const Material* /*material*/);
|
||||
NazaraSignal(OnMaterialRelease, const Material* /*material*/);
|
||||
|
||||
private:
|
||||
inline void InvalidatePipeline();
|
||||
inline void InvalidateShaderBinding();
|
||||
inline void InvalidateTextureSampler(std::size_t textureIndex);
|
||||
inline void InvalidateUniformData(std::size_t uniformBufferIndex);
|
||||
inline void UpdatePipeline() const;
|
||||
void UpdateShaderBinding();
|
||||
|
||||
|
|
|
|||
|
|
@ -468,20 +468,21 @@ namespace Nz
|
|||
return m_uniformBuffers[bufferIndex].buffer;
|
||||
}
|
||||
|
||||
inline std::vector<UInt8>& Material::GetUniformBufferData(std::size_t bufferIndex)
|
||||
{
|
||||
NazaraAssert(bufferIndex < m_uniformBuffers.size(), "Invalid uniform buffer index");
|
||||
UniformBuffer& uboEntry = m_uniformBuffers[bufferIndex];
|
||||
uboEntry.dataInvalidated = true;
|
||||
return uboEntry.data;
|
||||
}
|
||||
|
||||
inline const std::vector<UInt8>& Material::GetUniformBufferConstData(std::size_t bufferIndex)
|
||||
{
|
||||
NazaraAssert(bufferIndex < m_uniformBuffers.size(), "Invalid uniform buffer index");
|
||||
return m_uniformBuffers[bufferIndex].data;
|
||||
}
|
||||
|
||||
inline std::vector<UInt8>& Material::GetUniformBufferData(std::size_t bufferIndex)
|
||||
{
|
||||
NazaraAssert(bufferIndex < m_uniformBuffers.size(), "Invalid uniform buffer index");
|
||||
UniformBuffer& uboEntry = m_uniformBuffers[bufferIndex];
|
||||
InvalidateUniformData(bufferIndex);
|
||||
|
||||
return uboEntry.data;
|
||||
}
|
||||
|
||||
inline bool Material::HasTexture(std::size_t textureIndex) const
|
||||
{
|
||||
return GetTexture(textureIndex) != nullptr;
|
||||
|
|
@ -740,11 +741,13 @@ namespace Nz
|
|||
inline void Material::InvalidatePipeline()
|
||||
{
|
||||
m_pipelineUpdated = false;
|
||||
OnMaterialInvalidated(this);
|
||||
}
|
||||
|
||||
inline void Material::InvalidateShaderBinding()
|
||||
{
|
||||
m_shaderBindingUpdated = false;
|
||||
OnMaterialInvalidated(this);
|
||||
}
|
||||
|
||||
inline void Material::InvalidateTextureSampler(std::size_t textureIndex)
|
||||
|
|
@ -755,6 +758,15 @@ namespace Nz
|
|||
InvalidateShaderBinding();
|
||||
}
|
||||
|
||||
inline void Material::InvalidateUniformData(std::size_t uniformBufferIndex)
|
||||
{
|
||||
assert(uniformBufferIndex < m_uniformBuffers.size());
|
||||
UniformBuffer& uboEntry = m_uniformBuffers[uniformBufferIndex];
|
||||
uboEntry.dataInvalidated = true;
|
||||
|
||||
OnMaterialInvalidated(this);
|
||||
}
|
||||
|
||||
inline void Material::UpdatePipeline() const
|
||||
{
|
||||
for (auto& shader : m_pipelineInfo.shaders)
|
||||
|
|
|
|||
|
|
@ -28,11 +28,12 @@ namespace Nz
|
|||
Model(Model&&) noexcept = default;
|
||||
~Model() = default;
|
||||
|
||||
void Draw(CommandBufferBuilder& commandBuffer, const WorldInstance& instance) const override;
|
||||
void Draw(CommandBufferBuilder& commandBuffer) const override;
|
||||
|
||||
const std::shared_ptr<AbstractBuffer>& GetIndexBuffer(std::size_t subMeshIndex) const;
|
||||
std::size_t GetIndexCount(std::size_t subMeshIndex) const;
|
||||
const std::shared_ptr<Material>& GetMaterial(std::size_t subMeshIndex) const;
|
||||
const std::shared_ptr<Material>& GetMaterial(std::size_t subMeshIndex) const override;
|
||||
std::size_t GetMaterialCount() const override;
|
||||
const std::shared_ptr<RenderPipeline>& GetRenderPipeline(std::size_t subMeshIndex) const;
|
||||
const std::shared_ptr<AbstractBuffer>& GetVertexBuffer(std::size_t subMeshIndex) const;
|
||||
inline std::size_t GetSubMeshCount() const;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ namespace Nz
|
|||
inline void Model::SetMaterial(std::size_t subMeshIndex, std::shared_ptr<Material> material)
|
||||
{
|
||||
assert(subMeshIndex < m_subMeshes.size());
|
||||
|
||||
OnMaterialInvalidated(this, subMeshIndex, material);
|
||||
m_subMeshes[subMeshIndex].material = std::move(material);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
// This file was automatically generated
|
||||
|
||||
/*
|
||||
Nazara Engine - Graphics module
|
||||
|
||||
Copyright (C) 2020 Jérôme "Lynix" Leclercq (Lynix680@gmail.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_GLOBAL_GRAPHICS_SYSTEMS_HPP
|
||||
#define NAZARA_GLOBAL_GRAPHICS_SYSTEMS_HPP
|
||||
|
||||
#include <Nazara/Graphics/Systems/RenderSystem.hpp>
|
||||
|
||||
#endif // NAZARA_GLOBAL_GRAPHICS_SYSTEMS_HPP
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright (C) 2021 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_RENDERSYSTEM_HPP
|
||||
#define NAZARA_RENDERSYSTEM_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Core/ECS.hpp>
|
||||
#include <Nazara/Graphics/Graphics.hpp>
|
||||
#include <Nazara/Graphics/Components/GraphicsComponent.hpp>
|
||||
#include <Nazara/Utility/Node.hpp>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class CommandBufferBuilder;
|
||||
class FramePipeline;
|
||||
class RenderFrame;
|
||||
class UploadPool;
|
||||
|
||||
class NAZARA_GRAPHICS_API RenderSystem
|
||||
{
|
||||
public:
|
||||
RenderSystem(entt::registry& registry);
|
||||
RenderSystem(const RenderSystem&) = delete;
|
||||
RenderSystem(RenderSystem&&) = delete;
|
||||
~RenderSystem();
|
||||
|
||||
void Render(entt::registry& registry, RenderFrame& renderFrame);
|
||||
|
||||
RenderSystem& operator=(const RenderSystem&) = delete;
|
||||
RenderSystem& operator=(RenderSystem&&) = delete;
|
||||
|
||||
private:
|
||||
void OnCameraDestroy(entt::registry& registry, entt::entity entity);
|
||||
void OnGraphicsDestroy(entt::registry& registry, entt::entity entity);
|
||||
void OnNodeDestroy(entt::registry& registry, entt::entity entity);
|
||||
void UpdateInstances(entt::registry& registry);
|
||||
|
||||
struct CameraEntity
|
||||
{
|
||||
NazaraSlot(Node, OnNodeInvalidation, onNodeInvalidation);
|
||||
};
|
||||
|
||||
struct GraphicsEntity
|
||||
{
|
||||
NazaraSlot(GraphicsComponent, OnRenderableAttached, onRenderableAttached);
|
||||
NazaraSlot(GraphicsComponent, OnRenderableDetach, onRenderableDetach);
|
||||
NazaraSlot(Node, OnNodeInvalidation, onNodeInvalidation);
|
||||
};
|
||||
|
||||
entt::connection m_cameraDestroyConnection;
|
||||
entt::connection m_graphicsDestroyConnection;
|
||||
entt::connection m_nodeDestroyConnection;
|
||||
entt::observer m_cameraConstructObserver;
|
||||
entt::observer m_graphicsConstructObserver;
|
||||
std::set<entt::entity> m_invalidatedCameraNode;
|
||||
std::set<entt::entity> m_invalidatedWorldNode;
|
||||
std::unique_ptr<FramePipeline> m_pipeline;
|
||||
std::unordered_map<entt::entity, CameraEntity> m_cameraEntities;
|
||||
std::unordered_map<entt::entity, GraphicsEntity> m_graphicsEntities;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Graphics/Systems/RenderSystem.inl>
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright (C) 2021 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <Nazara/Graphics/Systems/RenderSystem.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
}
|
||||
|
||||
#include <Nazara/Graphics/DebugOff.hpp>
|
||||
|
|
@ -103,7 +103,7 @@ namespace std
|
|||
|
||||
NazaraRenderStateEnum(faceFilling);
|
||||
|
||||
if (pipelineInfo.blending) //< Remember, at this time we know lhs.blending == rhs.blending
|
||||
if (pipelineInfo.blending) //< we don't care about blending state if blending isn't enabled
|
||||
{
|
||||
NazaraRenderStateEnum(blend.dstAlpha);
|
||||
NazaraRenderStateEnum(blend.dstColor);
|
||||
|
|
@ -119,7 +119,7 @@ namespace std
|
|||
if (pipelineInfo.faceCulling)
|
||||
NazaraRenderStateEnum(cullingSide);
|
||||
|
||||
if (pipelineInfo.stencilTest)
|
||||
if (pipelineInfo.stencilTest) //< we don't care about stencil state if stencil isn't enabled
|
||||
{
|
||||
NazaraRenderStateEnum(stencilBack.compare);
|
||||
NazaraRenderStateUInt32(stencilBack.compareMask);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Graphics/AbstractViewer.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (C) 2021 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <Nazara/Graphics/Components/CameraComponent.hpp>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
const RenderTarget& CameraComponent::GetRenderTarget()
|
||||
{
|
||||
if (!m_renderTarget)
|
||||
throw std::runtime_error("no rendertarget set");
|
||||
|
||||
return* m_renderTarget;
|
||||
}
|
||||
|
||||
ViewerInstance& CameraComponent::GetViewerInstance()
|
||||
{
|
||||
return m_viewerInstance;
|
||||
}
|
||||
|
||||
const ViewerInstance& CameraComponent::GetViewerInstance() const
|
||||
{
|
||||
return m_viewerInstance;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,296 @@
|
|||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Graphics/ForwardFramePipeline.hpp>
|
||||
#include <Nazara/Graphics/AbstractViewer.hpp>
|
||||
#include <Nazara/Graphics/FrameGraph.hpp>
|
||||
#include <Nazara/Graphics/Graphics.hpp>
|
||||
#include <Nazara/Graphics/InstancedRenderable.hpp>
|
||||
#include <Nazara/Graphics/ViewerInstance.hpp>
|
||||
#include <Nazara/Graphics/WorldInstance.hpp>
|
||||
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
|
||||
#include <Nazara/Renderer/Framebuffer.hpp>
|
||||
#include <Nazara/Renderer/RenderFrame.hpp>
|
||||
#include <Nazara/Renderer/RenderTarget.hpp>
|
||||
#include <Nazara/Renderer/UploadPool.hpp>
|
||||
#include <array>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
ForwardFramePipeline::ForwardFramePipeline() :
|
||||
m_rebuildFrameGraph(true),
|
||||
m_rebuildForwardPass(false)
|
||||
{
|
||||
}
|
||||
|
||||
void ForwardFramePipeline::InvalidateViewer(AbstractViewer* viewerInstance)
|
||||
{
|
||||
m_invalidatedViewerInstances.insert(viewerInstance);
|
||||
}
|
||||
|
||||
void ForwardFramePipeline::InvalidateWorldInstance(WorldInstance* worldInstance)
|
||||
{
|
||||
m_invalidatedWorldInstances.insert(worldInstance);
|
||||
}
|
||||
|
||||
void ForwardFramePipeline::RegisterInstancedDrawable(WorldInstance* worldInstance, const InstancedRenderable* instancedRenderable)
|
||||
{
|
||||
auto& renderableMap = m_renderables[worldInstance];
|
||||
if (auto it = renderableMap.find(instancedRenderable); it == renderableMap.end())
|
||||
{
|
||||
auto& renderableData = renderableMap.emplace(instancedRenderable, RenderableData{}).first->second;
|
||||
renderableData.onMaterialInvalidated.Connect(instancedRenderable->OnMaterialInvalidated, [this](InstancedRenderable* instancedRenderable, std::size_t materialIndex, const std::shared_ptr<Material>& newMaterial)
|
||||
{
|
||||
if (newMaterial)
|
||||
RegisterMaterial(newMaterial.get());
|
||||
|
||||
const auto& prevMaterial = instancedRenderable->GetMaterial(materialIndex);
|
||||
if (prevMaterial)
|
||||
UnregisterMaterial(prevMaterial.get());
|
||||
|
||||
m_rebuildForwardPass = true;
|
||||
});
|
||||
|
||||
std::size_t matCount = instancedRenderable->GetMaterialCount();
|
||||
for (std::size_t i = 0; i < matCount; ++i)
|
||||
{
|
||||
if (Material* mat = instancedRenderable->GetMaterial(i).get())
|
||||
RegisterMaterial(mat);
|
||||
}
|
||||
|
||||
m_rebuildForwardPass = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ForwardFramePipeline::RegisterViewer(AbstractViewer* viewerInstance)
|
||||
{
|
||||
m_viewers.emplace(viewerInstance, ViewerData{});
|
||||
}
|
||||
|
||||
void ForwardFramePipeline::Render(RenderFrame& renderFrame)
|
||||
{
|
||||
Graphics* graphics = Graphics::Instance();
|
||||
|
||||
if (m_rebuildFrameGraph)
|
||||
{
|
||||
renderFrame.PushForRelease(std::move(m_bakedFrameGraph));
|
||||
m_bakedFrameGraph = BuildFrameGraph();
|
||||
m_rebuildForwardPass = false; //< No need to rebuild forward pass twice
|
||||
}
|
||||
|
||||
// Update UBOs and materials
|
||||
UploadPool& uploadPool = renderFrame.GetUploadPool();
|
||||
|
||||
renderFrame.Execute([&](CommandBufferBuilder& builder)
|
||||
{
|
||||
builder.BeginDebugRegion("UBO Update", Color::Yellow);
|
||||
{
|
||||
builder.PreTransferBarrier();
|
||||
|
||||
for (AbstractViewer* viewer : m_invalidatedViewerInstances)
|
||||
viewer->GetViewerInstance().UpdateBuffers(uploadPool, builder);
|
||||
|
||||
m_invalidatedViewerInstances.clear();
|
||||
|
||||
for (WorldInstance* worldInstance : m_invalidatedWorldInstances)
|
||||
worldInstance->UpdateBuffers(uploadPool, builder);
|
||||
|
||||
m_invalidatedWorldInstances.clear();
|
||||
|
||||
for (Material* material : m_invalidatedMaterials)
|
||||
{
|
||||
if (material->Update(renderFrame, builder))
|
||||
m_rebuildForwardPass = true;
|
||||
}
|
||||
m_invalidatedMaterials.clear();
|
||||
|
||||
builder.PostTransferBarrier();
|
||||
}
|
||||
builder.EndDebugRegion();
|
||||
}, QueueType::Transfer);
|
||||
|
||||
const Vector2ui& frameSize = renderFrame.GetSize();
|
||||
if (m_bakedFrameGraph.Resize(frameSize.x, frameSize.y))
|
||||
{
|
||||
const std::shared_ptr<TextureSampler>& sampler = graphics->GetSamplerCache().Get({});
|
||||
for (auto&& [_, viewerData] : m_viewers)
|
||||
{
|
||||
if (viewerData.blitShaderBinding)
|
||||
renderFrame.PushForRelease(std::move(viewerData.blitShaderBinding));
|
||||
|
||||
viewerData.blitShaderBinding = graphics->GetBlitPipelineLayout()->AllocateShaderBinding(0);
|
||||
viewerData.blitShaderBinding->Update({
|
||||
{
|
||||
0,
|
||||
ShaderBinding::TextureBinding {
|
||||
m_bakedFrameGraph.GetAttachmentTexture(viewerData.colorAttachment).get(),
|
||||
sampler.get()
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
m_bakedFrameGraph.Execute(renderFrame);
|
||||
|
||||
for (auto&& [viewer, viewerData] : m_viewers)
|
||||
{
|
||||
const RenderTarget& renderTarget = viewer->GetRenderTarget();
|
||||
Recti renderRegion(0, 0, frameSize.x, frameSize.y);
|
||||
const ShaderBindingPtr& blitShaderBinding = viewerData.blitShaderBinding;
|
||||
const std::shared_ptr<Texture>& sourceTexture = m_bakedFrameGraph.GetAttachmentTexture(viewerData.colorAttachment);
|
||||
|
||||
renderFrame.Execute([&](CommandBufferBuilder& builder)
|
||||
{
|
||||
builder.TextureBarrier(PipelineStage::ColorOutput, PipelineStage::FragmentShader, MemoryAccess::ColorWrite, MemoryAccess::ShaderRead, TextureLayout::ColorOutput, TextureLayout::ColorInput, *sourceTexture);
|
||||
|
||||
std::array<CommandBufferBuilder::ClearValues, 2> clearValues;
|
||||
clearValues[0].color = Color::Black;
|
||||
clearValues[1].depth = 1.f;
|
||||
clearValues[1].stencil = 0;
|
||||
|
||||
builder.BeginDebugRegion("Main window rendering", Color::Green);
|
||||
{
|
||||
builder.BeginRenderPass(renderTarget.GetFramebuffer(renderFrame.GetFramebufferIndex()), renderTarget.GetRenderPass(), renderRegion, { clearValues[0], clearValues[1] });
|
||||
{
|
||||
builder.SetScissor(renderRegion);
|
||||
builder.SetViewport(renderRegion);
|
||||
|
||||
builder.BindPipeline(*graphics->GetBlitPipeline());
|
||||
builder.BindVertexBuffer(0, graphics->GetFullscreenVertexBuffer().get());
|
||||
builder.BindShaderBinding(0, *blitShaderBinding);
|
||||
|
||||
builder.Draw(3);
|
||||
}
|
||||
builder.EndRenderPass();
|
||||
}
|
||||
builder.EndDebugRegion();
|
||||
|
||||
}, QueueType::Graphics);
|
||||
}
|
||||
}
|
||||
|
||||
void ForwardFramePipeline::UnregisterInstancedDrawable(WorldInstance* worldInstance, const InstancedRenderable* instancedRenderable)
|
||||
{
|
||||
auto instanceIt = m_renderables.find(worldInstance);
|
||||
if (instanceIt == m_renderables.end())
|
||||
return;
|
||||
|
||||
auto& instancedRenderables = instanceIt->second;
|
||||
|
||||
auto renderableIt = instancedRenderables.find(instancedRenderable);
|
||||
if (renderableIt == instancedRenderables.end())
|
||||
return;
|
||||
|
||||
if (instancedRenderables.size() > 1)
|
||||
instancedRenderables.erase(renderableIt);
|
||||
else
|
||||
m_renderables.erase(worldInstance);
|
||||
|
||||
std::size_t matCount = instancedRenderable->GetMaterialCount();
|
||||
for (std::size_t i = 0; i < matCount; ++i)
|
||||
{
|
||||
if (Material* mat = instancedRenderable->GetMaterial(i).get())
|
||||
UnregisterMaterial(mat);
|
||||
}
|
||||
|
||||
m_rebuildForwardPass = true;
|
||||
}
|
||||
|
||||
void ForwardFramePipeline::UnregisterViewer(AbstractViewer* viewerInstance)
|
||||
{
|
||||
m_viewers.erase(viewerInstance);
|
||||
m_rebuildFrameGraph = true;
|
||||
}
|
||||
|
||||
BakedFrameGraph ForwardFramePipeline::BuildFrameGraph()
|
||||
{
|
||||
FrameGraph frameGraph;
|
||||
|
||||
for (auto&& [viewer, viewerData] : m_viewers)
|
||||
{
|
||||
viewerData.colorAttachment = frameGraph.AddAttachment({
|
||||
"Color",
|
||||
PixelFormat::RGBA8
|
||||
});
|
||||
|
||||
viewerData.depthStencilAttachment = frameGraph.AddAttachment({
|
||||
"Depth-stencil buffer",
|
||||
Graphics::Instance()->GetPreferredDepthStencilFormat()
|
||||
});
|
||||
}
|
||||
|
||||
for (auto&& [viewer, viewerData] : m_viewers)
|
||||
{
|
||||
FramePass& framePass = frameGraph.AddPass("Forward pass");
|
||||
|
||||
framePass.AddOutput(viewerData.colorAttachment);
|
||||
framePass.SetDepthStencilOutput(viewerData.depthStencilAttachment);
|
||||
|
||||
framePass.SetClearColor(0, Color::Black);
|
||||
framePass.SetDepthStencilClear(1.f, 0);
|
||||
|
||||
framePass.SetExecutionCallback([this]()
|
||||
{
|
||||
if (m_rebuildForwardPass)
|
||||
{
|
||||
m_rebuildForwardPass = false;
|
||||
return FramePassExecution::UpdateAndExecute;
|
||||
}
|
||||
else
|
||||
return FramePassExecution::Execute;
|
||||
});
|
||||
|
||||
framePass.SetCommandCallback([this, viewer = viewer](CommandBufferBuilder& builder, const Recti& renderRect)
|
||||
{
|
||||
builder.SetScissor(renderRect);
|
||||
builder.SetViewport(renderRect);
|
||||
builder.BindShaderBinding(Graphics::ViewerBindingSet, viewer->GetViewerInstance().GetShaderBinding());
|
||||
|
||||
for (const auto& [worldInstance, renderables] : m_renderables)
|
||||
{
|
||||
builder.BindShaderBinding(Graphics::WorldBindingSet, worldInstance->GetShaderBinding());
|
||||
|
||||
for (const auto& [renderable, renderableData] : renderables)
|
||||
renderable->Draw(builder);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//FIXME: This doesn't handle multiple window viewers
|
||||
for (auto&& [viewer, viewerData] : m_viewers)
|
||||
frameGraph.SetBackbufferOutput(viewerData.colorAttachment);
|
||||
|
||||
return frameGraph.Bake();
|
||||
}
|
||||
|
||||
void ForwardFramePipeline::RegisterMaterial(Material* material)
|
||||
{
|
||||
auto it = m_materials.find(material);
|
||||
if (it == m_materials.end())
|
||||
{
|
||||
it = m_materials.emplace(material, MaterialData{}).first;
|
||||
it->second.onMaterialInvalided.Connect(material->OnMaterialInvalidated, [this, material](const Material* /*material*/)
|
||||
{
|
||||
m_invalidatedMaterials.insert(material);
|
||||
});
|
||||
|
||||
m_invalidatedMaterials.insert(material);
|
||||
}
|
||||
|
||||
it->second.usedCount++;
|
||||
}
|
||||
|
||||
void ForwardFramePipeline::UnregisterMaterial(Material* material)
|
||||
{
|
||||
auto it = m_materials.find(material);
|
||||
assert(it != m_materials.end());
|
||||
|
||||
MaterialData& materialData = it->second;
|
||||
assert(materialData.usedCount > 0);
|
||||
if (--materialData.usedCount == 0)
|
||||
m_materials.erase(material);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Graphics/FramePipeline.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
FramePipeline::~FramePipeline() = default;
|
||||
}
|
||||
|
|
@ -11,13 +11,21 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
const UInt8 r_blitShader[] = {
|
||||
#include <Nazara/Graphics/Resources/Shaders/blit.nzsl.h>
|
||||
};
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup graphics
|
||||
* \class Nz::Graphics
|
||||
* \brief Graphics class that represents the module initializer of Graphics
|
||||
*/
|
||||
Graphics::Graphics(Config config) :
|
||||
ModuleBase("Graphics", this)
|
||||
ModuleBase("Graphics", this),
|
||||
m_preferredDepthStencilFormat(PixelFormat::Undefined)
|
||||
{
|
||||
ECS::RegisterComponents();
|
||||
|
||||
|
|
@ -60,11 +68,20 @@ namespace Nz
|
|||
FillWorldPipelineLayout(referenceLayoutInfo);
|
||||
|
||||
m_referencePipelineLayout = m_renderDevice->InstantiateRenderPipelineLayout(std::move(referenceLayoutInfo));
|
||||
|
||||
BuildFullscreenVertexBuffer();
|
||||
BuildBlitPipeline();
|
||||
SelectDepthStencilFormats();
|
||||
}
|
||||
|
||||
Graphics::~Graphics()
|
||||
{
|
||||
MaterialPipeline::Uninitialize();
|
||||
m_samplerCache.reset();
|
||||
m_fullscreenVertexBuffer.reset();
|
||||
m_fullscreenVertexDeclaration.reset();
|
||||
m_blitPipeline.reset();
|
||||
m_blitPipelineLayout.reset();
|
||||
}
|
||||
|
||||
void Graphics::FillViewerPipelineLayout(RenderPipelineLayoutInfo& layoutInfo, UInt32 set)
|
||||
|
|
@ -85,5 +102,80 @@ namespace Nz
|
|||
});
|
||||
}
|
||||
|
||||
void Graphics::BuildBlitPipeline()
|
||||
{
|
||||
RenderPipelineLayoutInfo layoutInfo;
|
||||
layoutInfo.bindings.assign({
|
||||
{
|
||||
0, 0,
|
||||
ShaderBindingType::Texture,
|
||||
ShaderStageType::Fragment
|
||||
}
|
||||
});
|
||||
|
||||
m_blitPipelineLayout = m_renderDevice->InstantiateRenderPipelineLayout(std::move(layoutInfo));
|
||||
if (!m_blitPipelineLayout)
|
||||
throw std::runtime_error("failed to instantiate fullscreen renderpipeline layout");
|
||||
|
||||
auto blitShader = m_renderDevice->InstantiateShaderModule(ShaderStageType::Fragment | ShaderStageType::Vertex, ShaderLanguage::NazaraShader, r_blitShader, sizeof(r_blitShader), {});
|
||||
if (!blitShader)
|
||||
throw std::runtime_error("failed to instantiate blit shader");
|
||||
|
||||
RenderPipelineInfo pipelineInfo;
|
||||
pipelineInfo.pipelineLayout = m_blitPipelineLayout;
|
||||
pipelineInfo.shaderModules.push_back(std::move(blitShader));
|
||||
pipelineInfo.vertexBuffers.assign({
|
||||
{
|
||||
0,
|
||||
m_fullscreenVertexDeclaration
|
||||
}
|
||||
});
|
||||
|
||||
m_blitPipeline = m_renderDevice->InstantiateRenderPipeline(std::move(pipelineInfo));
|
||||
}
|
||||
|
||||
void Graphics::BuildFullscreenVertexBuffer()
|
||||
{
|
||||
m_fullscreenVertexDeclaration = VertexDeclaration::Get(VertexLayout::XY_UV);
|
||||
std::array<Nz::VertexStruct_XY_UV, 3> vertexData = {
|
||||
{
|
||||
{
|
||||
Nz::Vector2f(-1.f, 1.f),
|
||||
Nz::Vector2f(0.0f, 1.0f),
|
||||
},
|
||||
{
|
||||
Nz::Vector2f(-1.f, -3.f),
|
||||
Nz::Vector2f(0.0f, -1.0f),
|
||||
},
|
||||
{
|
||||
Nz::Vector2f(3.f, 1.f),
|
||||
Nz::Vector2f(2.0f, 1.0f),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
m_fullscreenVertexBuffer = m_renderDevice->InstantiateBuffer(BufferType::Vertex);
|
||||
if (!m_fullscreenVertexBuffer->Initialize(m_fullscreenVertexDeclaration->GetStride() * vertexData.size(), BufferUsage::DeviceLocal))
|
||||
throw std::runtime_error("failed to initialize fullscreen vertex buffer");
|
||||
|
||||
if (!m_fullscreenVertexBuffer->Fill(vertexData.data(), 0, m_fullscreenVertexDeclaration->GetStride() * vertexData.size()))
|
||||
throw std::runtime_error("failed to fill fullscreen vertex buffer");
|
||||
}
|
||||
|
||||
void Graphics::SelectDepthStencilFormats()
|
||||
{
|
||||
for (PixelFormat depthStencilCandidate : { PixelFormat::Depth24Stencil8, PixelFormat::Depth32FStencil8, PixelFormat::Depth16Stencil8 })
|
||||
{
|
||||
if (m_renderDevice->IsTextureFormatSupported(depthStencilCandidate, TextureUsage::DepthStencilAttachment))
|
||||
{
|
||||
m_preferredDepthStencilFormat = depthStencilCandidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_preferredDepthStencilFormat == PixelFormat::Undefined)
|
||||
throw std::runtime_error("no supported depth-stencil format found");
|
||||
}
|
||||
|
||||
Graphics* Graphics::s_instance = nullptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,10 +29,8 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
|
||||
void Model::Draw(CommandBufferBuilder& commandBuffer, const WorldInstance& instance) const
|
||||
void Model::Draw(CommandBufferBuilder& commandBuffer) const
|
||||
{
|
||||
commandBuffer.BindShaderBinding(Graphics::WorldBindingSet, instance.GetShaderBinding());
|
||||
|
||||
for (std::size_t i = 0; i < m_subMeshes.size(); ++i)
|
||||
{
|
||||
const auto& submeshData = m_subMeshes[i];
|
||||
|
|
@ -66,6 +64,11 @@ namespace Nz
|
|||
return subMeshData.material;
|
||||
}
|
||||
|
||||
std::size_t Model::GetMaterialCount() const
|
||||
{
|
||||
return m_subMeshes.size();
|
||||
}
|
||||
|
||||
const std::shared_ptr<RenderPipeline>& Model::GetRenderPipeline(std::size_t subMeshIndex) const
|
||||
{
|
||||
assert(subMeshIndex < m_subMeshes.size());
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
external
|
||||
{
|
||||
[binding(0)] texture: sampler2D<f32>
|
||||
}
|
||||
|
||||
struct VertIn
|
||||
{
|
||||
[location(0)] position: vec2<f32>,
|
||||
[location(1)] uv: vec2<f32>
|
||||
}
|
||||
|
||||
struct VertOut
|
||||
{
|
||||
[builtin(position)] position: vec4<f32>,
|
||||
[location(0)] uv: vec2<f32>
|
||||
}
|
||||
|
||||
[entry(vert)]
|
||||
fn main(vertIn: VertIn) -> VertOut
|
||||
{
|
||||
let output: VertOut;
|
||||
output.position = vec4<f32>(vertIn.position, 0.0, 1.0);
|
||||
output.uv = vertIn.uv;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
struct FragOut
|
||||
{
|
||||
[location(0)] color: vec4<f32>
|
||||
}
|
||||
|
||||
[entry(frag)]
|
||||
fn main(input: VertOut) -> FragOut
|
||||
{
|
||||
let output: FragOut;
|
||||
output.color = texture.Sample(input.uv);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
101,120,116,101,114,110,97,108,10,123,10,32,32,32,32,91,98,105,110,100,105,110,103,40,48,41,93,32,116,101,120,116,117,114,101,58,32,115,97,109,112,108,101,114,50,68,60,102,51,50,62,10,125,10,10,115,116,114,117,99,116,32,86,101,114,116,73,110,10,123,10,32,32,32,32,91,108,111,99,97,116,105,111,110,40,48,41,93,32,112,111,115,105,116,105,111,110,58,32,118,101,99,50,60,102,51,50,62,44,10,32,32,32,32,91,108,111,99,97,116,105,111,110,40,49,41,93,32,117,118,58,32,118,101,99,50,60,102,51,50,62,10,125,10,10,115,116,114,117,99,116,32,86,101,114,116,79,117,116,10,123,10,32,32,32,32,91,98,117,105,108,116,105,110,40,112,111,115,105,116,105,111,110,41,93,32,112,111,115,105,116,105,111,110,58,32,118,101,99,52,60,102,51,50,62,44,10,32,32,32,32,91,108,111,99,97,116,105,111,110,40,48,41,93,32,117,118,58,32,118,101,99,50,60,102,51,50,62,10,125,10,10,91,101,110,116,114,121,40,118,101,114,116,41,93,10,102,110,32,109,97,105,110,40,118,101,114,116,73,110,58,32,86,101,114,116,73,110,41,32,45,62,32,86,101,114,116,79,117,116,10,123,10,32,32,32,32,108,101,116,32,111,117,116,112,117,116,58,32,86,101,114,116,79,117,116,59,10,32,32,32,32,111,117,116,112,117,116,46,112,111,115,105,116,105,111,110,32,61,32,118,101,99,52,60,102,51,50,62,40,118,101,114,116,73,110,46,112,111,115,105,116,105,111,110,44,32,48,46,48,44,32,49,46,48,41,59,10,32,32,32,32,111,117,116,112,117,116,46,117,118,32,61,32,118,101,114,116,73,110,46,117,118,59,10,10,32,32,32,32,114,101,116,117,114,110,32,111,117,116,112,117,116,59,10,125,10,10,115,116,114,117,99,116,32,70,114,97,103,79,117,116,10,123,10,32,32,32,32,91,108,111,99,97,116,105,111,110,40,48,41,93,32,99,111,108,111,114,58,32,118,101,99,52,60,102,51,50,62,10,125,10,10,91,101,110,116,114,121,40,102,114,97,103,41,93,10,102,110,32,109,97,105,110,40,105,110,112,117,116,58,32,86,101,114,116,79,117,116,41,32,45,62,32,70,114,97,103,79,117,116,10,123,10,32,32,32,32,108,101,116,32,111,117,116,112,117,116,58,32,70,114,97,103,79,117,116,59,10,32,32,32,32,111,117,116,112,117,116,46,99,111,108,111,114,32,61,32,116,101,120,116,117,114,101,46,83,97,109,112,108,101,40,105,110,112,117,116,46,117,118,41,59,10,10,32,32,32,32,114,101,116,117,114,110,32,111,117,116,112,117,116,59,10,125,10,
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
// Copyright (C) 2021 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <Nazara/Graphics/Systems/RenderSystem.hpp>
|
||||
#include <Nazara/Graphics/ForwardFramePipeline.hpp>
|
||||
#include <Nazara/Graphics/ViewerInstance.hpp>
|
||||
#include <Nazara/Graphics/WorldInstance.hpp>
|
||||
#include <Nazara/Graphics/Components/CameraComponent.hpp>
|
||||
#include <Nazara/Graphics/Components/GraphicsComponent.hpp>
|
||||
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
|
||||
#include <Nazara/Renderer/Renderframe.hpp>
|
||||
#include <Nazara/Renderer/UploadPool.hpp>
|
||||
#include <Nazara/Utility/Components/NodeComponent.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
RenderSystem::RenderSystem(entt::registry& registry) :
|
||||
m_cameraConstructObserver(registry, entt::collector.group<CameraComponent, NodeComponent>()),
|
||||
m_graphicsConstructObserver(registry, entt::collector.group<GraphicsComponent, NodeComponent>())
|
||||
{
|
||||
m_cameraDestroyConnection = registry.on_destroy<CameraComponent>().connect<&RenderSystem::OnCameraDestroy>(this);
|
||||
m_graphicsDestroyConnection = registry.on_destroy<GraphicsComponent>().connect<&RenderSystem::OnGraphicsDestroy>(this);
|
||||
m_nodeDestroyConnection = registry.on_destroy<NodeComponent>().connect<&RenderSystem::OnNodeDestroy>(this);
|
||||
|
||||
m_pipeline = std::make_unique<ForwardFramePipeline>();
|
||||
}
|
||||
|
||||
RenderSystem::~RenderSystem()
|
||||
{
|
||||
m_cameraConstructObserver.disconnect();
|
||||
m_graphicsConstructObserver.disconnect();
|
||||
m_cameraDestroyConnection.release();
|
||||
m_graphicsDestroyConnection.release();
|
||||
m_nodeDestroyConnection.release();
|
||||
}
|
||||
|
||||
void RenderSystem::Render(entt::registry& registry, RenderFrame& renderFrame)
|
||||
{
|
||||
m_cameraConstructObserver.each([&](entt::entity entity)
|
||||
{
|
||||
CameraComponent& entityCamera = registry.get<CameraComponent>(entity);
|
||||
NodeComponent& entityNode = registry.get<NodeComponent>(entity);
|
||||
|
||||
m_pipeline->RegisterViewer(&entityCamera);
|
||||
|
||||
m_invalidatedCameraNode.insert(entity);
|
||||
|
||||
assert(m_cameraEntities.find(entity) == m_cameraEntities.end());
|
||||
auto& cameraEntity = m_cameraEntities[entity];
|
||||
cameraEntity.onNodeInvalidation.Connect(entityNode.OnNodeInvalidation, [this, entity](const Node* node)
|
||||
{
|
||||
m_invalidatedCameraNode.insert(entity);
|
||||
});
|
||||
});
|
||||
|
||||
m_graphicsConstructObserver.each([&](entt::entity entity)
|
||||
{
|
||||
GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(entity);
|
||||
NodeComponent& entityNode = registry.get<NodeComponent>(entity);
|
||||
|
||||
WorldInstance& worldInstance = entityGfx.GetWorldInstance();
|
||||
for (const auto& renderable : entityGfx.GetRenderables())
|
||||
m_pipeline->RegisterInstancedDrawable(&worldInstance, renderable.get());
|
||||
|
||||
m_invalidatedWorldNode.insert(entity);
|
||||
|
||||
assert(m_graphicsEntities.find(entity) == m_graphicsEntities.end());
|
||||
auto& graphicsEntity = m_graphicsEntities[entity];
|
||||
graphicsEntity.onNodeInvalidation.Connect(entityNode.OnNodeInvalidation, [this, entity](const Node* node)
|
||||
{
|
||||
m_invalidatedWorldNode.insert(entity);
|
||||
});
|
||||
|
||||
graphicsEntity.onRenderableAttached.Connect(entityGfx.OnRenderableAttached, [this](GraphicsComponent* gfx, const std::shared_ptr<InstancedRenderable>& renderable)
|
||||
{
|
||||
WorldInstance& worldInstance = gfx->GetWorldInstance();
|
||||
m_pipeline->RegisterInstancedDrawable(&worldInstance, renderable.get());
|
||||
});
|
||||
|
||||
graphicsEntity.onRenderableDetach.Connect(entityGfx.OnRenderableDetach, [this](GraphicsComponent* gfx, const std::shared_ptr<InstancedRenderable>& renderable)
|
||||
{
|
||||
WorldInstance& worldInstance = gfx->GetWorldInstance();
|
||||
m_pipeline->UnregisterInstancedDrawable(&worldInstance, renderable.get());
|
||||
});
|
||||
});
|
||||
|
||||
UpdateInstances(registry);
|
||||
|
||||
m_pipeline->Render(renderFrame);
|
||||
}
|
||||
|
||||
void RenderSystem::OnCameraDestroy(entt::registry& registry, entt::entity entity)
|
||||
{
|
||||
m_cameraEntities.erase(entity);
|
||||
m_invalidatedCameraNode.erase(entity);
|
||||
|
||||
CameraComponent& entityCamera = registry.get<CameraComponent>(entity);
|
||||
m_pipeline->UnregisterViewer(&entityCamera);
|
||||
}
|
||||
|
||||
void RenderSystem::OnGraphicsDestroy(entt::registry& registry, entt::entity entity)
|
||||
{
|
||||
m_graphicsEntities.erase(entity);
|
||||
m_invalidatedWorldNode.erase(entity);
|
||||
|
||||
GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(entity);
|
||||
WorldInstance& worldInstance = entityGfx.GetWorldInstance();
|
||||
for (const auto& renderable : entityGfx.GetRenderables())
|
||||
m_pipeline->UnregisterInstancedDrawable(&worldInstance, renderable.get());
|
||||
}
|
||||
|
||||
void RenderSystem::OnNodeDestroy(entt::registry& registry, entt::entity entity)
|
||||
{
|
||||
if (registry.try_get<CameraComponent>(entity))
|
||||
OnCameraDestroy(registry, entity);
|
||||
|
||||
if (registry.try_get<GraphicsComponent>(entity))
|
||||
OnGraphicsDestroy(registry, entity);
|
||||
}
|
||||
|
||||
void RenderSystem::UpdateInstances(entt::registry& registry)
|
||||
{
|
||||
for (entt::entity entity : m_invalidatedCameraNode)
|
||||
{
|
||||
const NodeComponent& entityNode = registry.get<const NodeComponent>(entity);
|
||||
CameraComponent& entityCamera = registry.get<CameraComponent>(entity);
|
||||
|
||||
ViewerInstance& viewerInstance = entityCamera.GetViewerInstance();
|
||||
viewerInstance.UpdateViewMatrix(Nz::Matrix4f::ViewMatrix(entityNode.GetPosition(CoordSys::Global), entityNode.GetRotation(CoordSys::Global)));
|
||||
|
||||
m_pipeline->InvalidateViewer(&entityCamera);
|
||||
}
|
||||
m_invalidatedCameraNode.clear();
|
||||
|
||||
for (entt::entity entity : m_invalidatedWorldNode)
|
||||
{
|
||||
const NodeComponent& entityNode = registry.get<const NodeComponent>(entity);
|
||||
GraphicsComponent& entityGraphics = registry.get<GraphicsComponent>(entity);
|
||||
|
||||
WorldInstance& worldInstance = entityGraphics.GetWorldInstance();
|
||||
worldInstance.UpdateWorldMatrix(entityNode.GetTransformMatrix());
|
||||
|
||||
m_pipeline->InvalidateWorldInstance(&worldInstance);
|
||||
}
|
||||
m_invalidatedWorldNode.clear();
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue