Graphics: Add RenderSystem and frame pipeline
This commit is contained in:
10
src/Nazara/Graphics/AbstractViewer.cpp
Normal file
10
src/Nazara/Graphics/AbstractViewer.cpp
Normal file
@@ -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
|
||||
{
|
||||
}
|
||||
28
src/Nazara/Graphics/Components/CameraComponent.cpp
Normal file
28
src/Nazara/Graphics/Components/CameraComponent.cpp
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
296
src/Nazara/Graphics/ForwardFramePipeline.cpp
Normal file
296
src/Nazara/Graphics/ForwardFramePipeline.cpp
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
11
src/Nazara/Graphics/FramePipeline.cpp
Normal file
11
src/Nazara/Graphics/FramePipeline.cpp
Normal file
@@ -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());
|
||||
|
||||
40
src/Nazara/Graphics/Resources/Shaders/blit.nzsl
Normal file
40
src/Nazara/Graphics/Resources/Shaders/blit.nzsl
Normal file
@@ -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;
|
||||
}
|
||||
1
src/Nazara/Graphics/Resources/Shaders/blit.nzsl.h
Normal file
1
src/Nazara/Graphics/Resources/Shaders/blit.nzsl.h
Normal file
@@ -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,
|
||||
149
src/Nazara/Graphics/Systems/RenderSystem.cpp
Normal file
149
src/Nazara/Graphics/Systems/RenderSystem.cpp
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user