diff --git a/bin/resources/depth_vert.nzsl b/bin/resources/depth_vert.nzsl new file mode 100644 index 000000000..cece2692d --- /dev/null +++ b/bin/resources/depth_vert.nzsl @@ -0,0 +1,53 @@ +option HAS_DIFFUSE_TEXTURE: bool; +option HAS_ALPHA_TEXTURE: bool; +option ALPHA_TEST: bool; + +const HasUV = HAS_DIFFUSE_TEXTURE || HAS_ALPHA_TEXTURE; + +[layout(std140)] +struct InstanceData +{ + worldMatrix: mat4, + invWorldMatrix: mat4 +} + +[layout(std140)] +struct ViewerData +{ + projectionMatrix: mat4, + invProjectionMatrix: mat4, + viewMatrix: mat4, + invViewMatrix: mat4, + viewProjMatrix: mat4, + invViewProjMatrix: mat4, + renderTargetSize: vec2, + invRenderTargetSize: vec2, + eyePosition: vec3 +} + +external +{ + [set(0), binding(0)] viewerData: uniform, + [set(1), binding(0)] instanceData: uniform +} + +// Vertex stage +struct VertIn +{ + [location(0)] pos: vec3, + [location(1), cond(HasUV)] uv: vec2 +} + +struct VertOut +{ + [builtin(position)] position: vec4 +} + +[entry(vert)] +fn main(input: VertIn) -> VertOut +{ + let output: VertOut; + output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4(input.pos, 1.0); + + return output; +} diff --git a/include/Nazara/Graphics/ForwardFramePipeline.hpp b/include/Nazara/Graphics/ForwardFramePipeline.hpp index f046b6195..90ff2b240 100644 --- a/include/Nazara/Graphics/ForwardFramePipeline.hpp +++ b/include/Nazara/Graphics/ForwardFramePipeline.hpp @@ -44,8 +44,8 @@ namespace Nz private: BakedFrameGraph BuildFrameGraph(); - void RegisterMaterial(MaterialPass* material); - void UnregisterMaterial(MaterialPass* material); + void RegisterMaterialPass(MaterialPass* material); + void UnregisterMaterialPass(MaterialPass* material); struct MaterialData { diff --git a/include/Nazara/Graphics/InstancedRenderable.hpp b/include/Nazara/Graphics/InstancedRenderable.hpp index c1836bb04..9d0d96def 100644 --- a/include/Nazara/Graphics/InstancedRenderable.hpp +++ b/include/Nazara/Graphics/InstancedRenderable.hpp @@ -15,7 +15,7 @@ namespace Nz { class CommandBufferBuilder; - class MaterialPass; + class Material; class WorldInstance; class NAZARA_GRAPHICS_API InstancedRenderable @@ -26,15 +26,15 @@ namespace Nz InstancedRenderable(InstancedRenderable&&) noexcept = default; ~InstancedRenderable(); - virtual void Draw(CommandBufferBuilder& commandBuffer) const = 0; + virtual void Draw(const std::string& pass, CommandBufferBuilder& commandBuffer) const = 0; - virtual const std::shared_ptr& GetMaterial(std::size_t i) const = 0; + virtual const std::shared_ptr& 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& /*newMaterial*/); + NazaraSignal(OnMaterialInvalidated, InstancedRenderable* /*instancedRenderable*/, std::size_t /*materialIndex*/, const std::shared_ptr& /*newMaterial*/); }; } diff --git a/include/Nazara/Graphics/Material.hpp b/include/Nazara/Graphics/Material.hpp new file mode 100644 index 000000000..652047c01 --- /dev/null +++ b/include/Nazara/Graphics/Material.hpp @@ -0,0 +1,36 @@ +// 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_MATERIAL_HPP +#define NAZARA_MATERIAL_HPP + +#include +#include + +namespace Nz +{ + class NAZARA_GRAPHICS_API Material : public Resource + { + public: + Material(); + ~Material() = default; + + void AddPass(std::string name, std::shared_ptr pass); + + inline MaterialPass* GetPass(const std::string& name) const; + + bool HasPass(const std::string& name) const; + + void RemovePass(const std::string& name); + + private: + std::unordered_map> m_passes; + }; +} + +#include + +#endif // NAZARA_MATERIAL_HPP diff --git a/include/Nazara/Graphics/Material.inl b/include/Nazara/Graphics/Material.inl new file mode 100644 index 000000000..72fb35aab --- /dev/null +++ b/include/Nazara/Graphics/Material.inl @@ -0,0 +1,20 @@ +// 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 + +#include +#include + +namespace Nz +{ + inline MaterialPass* Material::GetPass(const std::string& name) const + { + auto it = m_passes.find(name); + if (it == m_passes.end()) + return nullptr; + + return it->second.get(); + } +} + +#include diff --git a/include/Nazara/Graphics/Model.hpp b/include/Nazara/Graphics/Model.hpp index a4a3e4f92..a2ee4b5ee 100644 --- a/include/Nazara/Graphics/Model.hpp +++ b/include/Nazara/Graphics/Model.hpp @@ -18,7 +18,7 @@ namespace Nz { class GraphicalMesh; - class MaterialPass; + class Material; class NAZARA_GRAPHICS_API Model : public InstancedRenderable { @@ -28,17 +28,17 @@ namespace Nz Model(Model&&) noexcept = default; ~Model() = default; - void Draw(CommandBufferBuilder& commandBuffer) const override; + void Draw(const std::string& pass, CommandBufferBuilder& commandBuffer) const override; const std::shared_ptr& GetIndexBuffer(std::size_t subMeshIndex) const; std::size_t GetIndexCount(std::size_t subMeshIndex) const; - const std::shared_ptr& GetMaterial(std::size_t subMeshIndex) const override; + const std::shared_ptr& GetMaterial(std::size_t subMeshIndex) const override; std::size_t GetMaterialCount() const override; - const std::shared_ptr& GetRenderPipeline(std::size_t subMeshIndex) const; + const std::vector& GetVertexBufferData(std::size_t subMeshIndex) const; const std::shared_ptr& GetVertexBuffer(std::size_t subMeshIndex) const; inline std::size_t GetSubMeshCount() const; - inline void SetMaterial(std::size_t subMeshIndex, std::shared_ptr material); + inline void SetMaterial(std::size_t subMeshIndex, std::shared_ptr material); Model& operator=(const Model&) = delete; Model& operator=(Model&&) noexcept = default; @@ -46,7 +46,7 @@ namespace Nz private: struct SubMeshData { - std::shared_ptr material; + std::shared_ptr material; std::vector vertexBufferData; }; diff --git a/include/Nazara/Graphics/Model.inl b/include/Nazara/Graphics/Model.inl index 58e22a02a..d68b51d7e 100644 --- a/include/Nazara/Graphics/Model.inl +++ b/include/Nazara/Graphics/Model.inl @@ -13,7 +13,7 @@ namespace Nz return m_subMeshes.size(); } - inline void Model::SetMaterial(std::size_t subMeshIndex, std::shared_ptr material) + inline void Model::SetMaterial(std::size_t subMeshIndex, std::shared_ptr material) { assert(subMeshIndex < m_subMeshes.size()); diff --git a/include/Nazara/Renderer/RenderStates.hpp b/include/Nazara/Renderer/RenderStates.hpp index 05b371fcf..9c9dddbd3 100644 --- a/include/Nazara/Renderer/RenderStates.hpp +++ b/include/Nazara/Renderer/RenderStates.hpp @@ -22,7 +22,7 @@ namespace Nz FaceFilling faceFilling = FaceFilling::Fill; FaceSide cullingSide = FaceSide::Back; FrontFace frontFace = FrontFace::CounterClockwise; - RendererComparison depthCompare = RendererComparison::Less; + RendererComparison depthCompare = RendererComparison::LessOrEqual; PrimitiveMode primitiveMode = PrimitiveMode::TriangleList; struct diff --git a/src/Nazara/Graphics/ForwardFramePipeline.cpp b/src/Nazara/Graphics/ForwardFramePipeline.cpp index 3d41f4efd..af6d85d38 100644 --- a/src/Nazara/Graphics/ForwardFramePipeline.cpp +++ b/src/Nazara/Graphics/ForwardFramePipeline.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -41,14 +42,26 @@ namespace Nz 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& newMaterial) + renderableData.onMaterialInvalidated.Connect(instancedRenderable->OnMaterialInvalidated, [this](InstancedRenderable* instancedRenderable, std::size_t materialIndex, const std::shared_ptr& newMaterial) { if (newMaterial) - RegisterMaterial(newMaterial.get()); + { + if (MaterialPass* pass = newMaterial->GetPass("DepthPass")) + RegisterMaterialPass(pass); + + if (MaterialPass* pass = newMaterial->GetPass("ForwardPass")) + RegisterMaterialPass(pass); + } const auto& prevMaterial = instancedRenderable->GetMaterial(materialIndex); if (prevMaterial) - UnregisterMaterial(prevMaterial.get()); + { + if (MaterialPass* pass = prevMaterial->GetPass("DepthPass")) + UnregisterMaterialPass(pass); + + if (MaterialPass* pass = prevMaterial->GetPass("ForwardPass")) + UnregisterMaterialPass(pass); + } m_rebuildForwardPass = true; }); @@ -56,8 +69,14 @@ namespace Nz std::size_t matCount = instancedRenderable->GetMaterialCount(); for (std::size_t i = 0; i < matCount; ++i) { - if (MaterialPass* mat = instancedRenderable->GetMaterial(i).get()) - RegisterMaterial(mat); + if (Material* mat = instancedRenderable->GetMaterial(i).get()) + { + if (MaterialPass* pass = mat->GetPass("DepthPass")) + RegisterMaterialPass(pass); + + if (MaterialPass* pass = mat->GetPass("ForwardPass")) + RegisterMaterialPass(pass); + } } m_rebuildForwardPass = true; @@ -77,7 +96,6 @@ namespace Nz { renderFrame.PushForRelease(std::move(m_bakedFrameGraph)); m_bakedFrameGraph = BuildFrameGraph(); - m_rebuildForwardPass = false; //< No need to rebuild forward pass twice } // Update UBOs and materials @@ -111,8 +129,7 @@ namespace Nz builder.EndDebugRegion(); }, QueueType::Transfer); - const Vector2ui& frameSize = renderFrame.GetSize(); - if (m_bakedFrameGraph.Resize(frameSize.x, frameSize.y)) + if (m_bakedFrameGraph.Resize(renderFrame)) { const std::shared_ptr& sampler = graphics->GetSamplerCache().Get({}); for (auto&& [_, viewerData] : m_viewers) @@ -134,7 +151,10 @@ namespace Nz } m_bakedFrameGraph.Execute(renderFrame); + m_rebuildForwardPass = false; + m_rebuildFrameGraph = false; + const Vector2ui& frameSize = renderFrame.GetSize(); for (auto&& [viewer, viewerData] : m_viewers) { const RenderTarget& renderTarget = viewer->GetRenderTarget(); @@ -192,8 +212,8 @@ namespace Nz std::size_t matCount = instancedRenderable->GetMaterialCount(); for (std::size_t i = 0; i < matCount; ++i) { - if (MaterialPass* mat = instancedRenderable->GetMaterial(i).get()) - UnregisterMaterial(mat); + if (MaterialPass* pass = instancedRenderable->GetMaterial(i)->GetPass("ForwardPass")) + UnregisterMaterialPass(pass); } m_rebuildForwardPass = true; @@ -224,31 +244,25 @@ namespace Nz 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]() + FramePass& depthPrepass = frameGraph.AddPass("Depth pre-pass"); + depthPrepass.SetDepthStencilOutput(viewerData.depthStencilAttachment); + depthPrepass.SetDepthStencilClear(1.f, 0); + + depthPrepass.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*/) + + depthPrepass.SetCommandCallback([this, viewer = viewer](CommandBufferBuilder& builder, const Recti& /*renderRect*/) { Recti viewport = viewer->GetViewport(); builder.SetScissor(viewport); builder.SetViewport(viewport); + builder.BindShaderBinding(Graphics::ViewerBindingSet, viewer->GetViewerInstance().GetShaderBinding()); for (const auto& [worldInstance, renderables] : m_renderables) @@ -256,7 +270,41 @@ namespace Nz builder.BindShaderBinding(Graphics::WorldBindingSet, worldInstance->GetShaderBinding()); for (const auto& [renderable, renderableData] : renderables) - renderable->Draw(builder); + renderable->Draw("DepthPass", builder); + } + }); + + FramePass& forwardPass = frameGraph.AddPass("Forward pass"); + forwardPass.AddOutput(viewerData.colorAttachment); + forwardPass.SetDepthStencilInput(viewerData.depthStencilAttachment); + forwardPass.SetDepthStencilOutput(viewerData.depthStencilAttachment); + + forwardPass.SetClearColor(0, Color::Black); + forwardPass.SetDepthStencilClear(1.f, 0); + + forwardPass.SetExecutionCallback([this]() + { + if (m_rebuildForwardPass) + return FramePassExecution::UpdateAndExecute; + else + return FramePassExecution::Execute; + }); + + forwardPass.SetCommandCallback([this, viewer = viewer](CommandBufferBuilder& builder, const Recti& /*renderRect*/) + { + Recti viewport = viewer->GetViewport(); + + builder.SetScissor(viewport); + builder.SetViewport(viewport); + + builder.BindShaderBinding(Graphics::ViewerBindingSet, viewer->GetViewerInstance().GetShaderBinding()); + + for (const auto& [worldInstance, renderables] : m_renderables) + { + builder.BindShaderBinding(Graphics::WorldBindingSet, worldInstance->GetShaderBinding()); + + for (const auto& [renderable, renderableData] : renderables) + renderable->Draw("ForwardPass", builder); } }); } @@ -268,7 +316,7 @@ namespace Nz return frameGraph.Bake(); } - void ForwardFramePipeline::RegisterMaterial(MaterialPass* material) + void ForwardFramePipeline::RegisterMaterialPass(MaterialPass* material) { auto it = m_materials.find(material); if (it == m_materials.end()) @@ -285,7 +333,7 @@ namespace Nz it->second.usedCount++; } - void ForwardFramePipeline::UnregisterMaterial(MaterialPass* material) + void ForwardFramePipeline::UnregisterMaterialPass(MaterialPass* material) { auto it = m_materials.find(material); assert(it != m_materials.end()); diff --git a/src/Nazara/Graphics/Material.cpp b/src/Nazara/Graphics/Material.cpp new file mode 100644 index 000000000..8f58d8aa9 --- /dev/null +++ b/src/Nazara/Graphics/Material.cpp @@ -0,0 +1,31 @@ +// 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 + +#include +#include + +namespace Nz +{ + Material::Material() + { + } + + void Material::AddPass(std::string name, std::shared_ptr pass) + { + if (HasPass(name)) + return; + + m_passes.emplace(std::move(name), std::move(pass)); + } + + bool Material::HasPass(const std::string& name) const + { + return m_passes.find(name) != m_passes.end(); + } + + void Material::RemovePass(const std::string& name) + { + m_passes.erase(name); + } +} diff --git a/src/Nazara/Graphics/Model.cpp b/src/Nazara/Graphics/Model.cpp index f97a2fa09..6ebb00419 100644 --- a/src/Nazara/Graphics/Model.cpp +++ b/src/Nazara/Graphics/Model.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include #include @@ -29,16 +29,21 @@ namespace Nz } } - void Model::Draw(CommandBufferBuilder& commandBuffer) const + void Model::Draw(const std::string& pass, CommandBufferBuilder& commandBuffer) const { for (std::size_t i = 0; i < m_subMeshes.size(); ++i) { const auto& submeshData = m_subMeshes[i]; + + MaterialPass* materialPass = submeshData.material->GetPass(pass); + if (!materialPass) + continue; + const auto& indexBuffer = m_graphicalMesh->GetIndexBuffer(i); const auto& vertexBuffer = m_graphicalMesh->GetVertexBuffer(i); - const auto& renderPipeline = submeshData.material->GetPipeline()->GetRenderPipeline(submeshData.vertexBufferData); + const auto& renderPipeline = materialPass->GetPipeline()->GetRenderPipeline(submeshData.vertexBufferData); - commandBuffer.BindShaderBinding(Graphics::MaterialBindingSet, submeshData.material->GetShaderBinding()); + commandBuffer.BindShaderBinding(Graphics::MaterialBindingSet, materialPass->GetShaderBinding()); commandBuffer.BindIndexBuffer(indexBuffer.get()); commandBuffer.BindVertexBuffer(0, vertexBuffer.get()); commandBuffer.BindPipeline(*renderPipeline); @@ -57,7 +62,7 @@ namespace Nz return m_graphicalMesh->GetIndexCount(subMeshIndex); } - const std::shared_ptr& Model::GetMaterial(std::size_t subMeshIndex) const + const std::shared_ptr& Model::GetMaterial(std::size_t subMeshIndex) const { assert(subMeshIndex < m_subMeshes.size()); const auto& subMeshData = m_subMeshes[subMeshIndex]; @@ -69,11 +74,11 @@ namespace Nz return m_subMeshes.size(); } - const std::shared_ptr& Model::GetRenderPipeline(std::size_t subMeshIndex) const + const std::vector& Model::GetVertexBufferData(std::size_t subMeshIndex) const { assert(subMeshIndex < m_subMeshes.size()); const auto& subMeshData = m_subMeshes[subMeshIndex]; - return subMeshData.material->GetPipeline()->GetRenderPipeline(subMeshData.vertexBufferData); + return subMeshData.vertexBufferData; } const std::shared_ptr& Model::GetVertexBuffer(std::size_t subMeshIndex) const