From b0a3941f4eb7bc03b04039ec94b16a9c4174bd73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 11 Jan 2022 19:47:29 +0100 Subject: [PATCH 01/14] Add Phong lighting (WIP) --- bin/resources/god_rays.nzsl | 4 +- examples/GraphicsTest/main.cpp | 20 +- include/Nazara/Graphics/BasicMaterial.hpp | 55 ++- include/Nazara/Graphics/BasicMaterial.inl | 59 ++- include/Nazara/Graphics/DepthMaterial.hpp | 2 +- include/Nazara/Graphics/DepthMaterial.inl | 2 +- include/Nazara/Graphics/ElementRenderer.hpp | 10 +- include/Nazara/Graphics/Enums.hpp | 10 + .../Nazara/Graphics/ForwardFramePipeline.hpp | 1 + include/Nazara/Graphics/Graphics.hpp | 4 - include/Nazara/Graphics/MaterialPass.hpp | 2 +- include/Nazara/Graphics/MaterialPass.inl | 2 +- .../Nazara/Graphics/PhongLightingMaterial.hpp | 80 ++-- .../Nazara/Graphics/PhongLightingMaterial.inl | 134 +++--- .../Graphics/PredefinedShaderStructs.hpp | 15 +- include/Nazara/Graphics/Sprite.inl | 7 +- .../Nazara/Graphics/SpriteChainRenderer.hpp | 2 +- include/Nazara/Graphics/SubmeshRenderer.hpp | 8 +- include/Nazara/Graphics/ViewerInstance.hpp | 3 + include/Nazara/Graphics/ViewerInstance.inl | 11 + include/Nazara/Shader/Ast/Enums.hpp | 2 + include/Nazara/Shader/Ast/SanitizeVisitor.hpp | 1 + src/Nazara/Graphics/BasicMaterial.cpp | 128 +++--- src/Nazara/Graphics/DepthMaterial.cpp | 17 +- src/Nazara/Graphics/ElementRenderer.cpp | 2 +- src/Nazara/Graphics/ForwardFramePipeline.cpp | 25 +- src/Nazara/Graphics/Graphics.cpp | 30 -- src/Nazara/Graphics/PhongLightingMaterial.cpp | 396 ++++++++++++------ .../Graphics/PredefinedShaderStructs.cpp | 44 +- .../Resources/Shaders/basic_material.nzsl | 74 +++- .../Resources/Shaders/phong_material.nzsl | 286 +++++++++++++ src/Nazara/Graphics/SpriteChainRenderer.cpp | 12 +- src/Nazara/Graphics/SubmeshRenderer.cpp | 16 +- src/Nazara/Graphics/Systems/RenderSystem.cpp | 5 +- src/Nazara/Graphics/ViewerInstance.cpp | 5 +- src/Nazara/Shader/Ast/SanitizeVisitor.cpp | 31 +- src/Nazara/Shader/GlslWriter.cpp | 17 +- src/Nazara/Shader/LangWriter.cpp | 8 + src/Nazara/Shader/SpirvAstVisitor.cpp | 36 ++ src/Nazara/Shader/SpirvWriter.cpp | 2 + 40 files changed, 1141 insertions(+), 427 deletions(-) create mode 100644 src/Nazara/Graphics/Resources/Shaders/phong_material.nzsl diff --git a/bin/resources/god_rays.nzsl b/bin/resources/god_rays.nzsl index b1b14e7e9..3224ff683 100644 --- a/bin/resources/god_rays.nzsl +++ b/bin/resources/god_rays.nzsl @@ -65,8 +65,7 @@ fn main(input: FragIn) -> FragOut let outputColor = vec4(0.0, 0.0, 0.0, 1.0); - let i = 0; - while (i < SampleCount) + for i in 0 -> SampleCount { uv -= deltaUV; let sample = occluderTexture.Sample(uv); @@ -75,7 +74,6 @@ fn main(input: FragIn) -> FragOut outputColor += sample; illuminationDecay *= settings.decay; - i += 1; } let output: FragOut; diff --git a/examples/GraphicsTest/main.cpp b/examples/GraphicsTest/main.cpp index 6543edb53..00c76499e 100644 --- a/examples/GraphicsTest/main.cpp +++ b/examples/GraphicsTest/main.cpp @@ -30,7 +30,7 @@ int main() meshParams.center = true; meshParams.storage = Nz::DataStorage::Software; meshParams.matrix = Nz::Matrix4f::Rotate(Nz::EulerAnglesf(0.f, -90.f, 0.f)) * Nz::Matrix4f::Scale(Nz::Vector3f(0.002f)); - meshParams.vertexDeclaration = Nz::VertexDeclaration::Get(Nz::VertexLayout::XYZ_UV); + meshParams.vertexDeclaration = Nz::VertexDeclaration::Get(Nz::VertexLayout::XYZ_Normal_UV); std::shared_ptr device = Nz::Graphics::Instance()->GetRenderDevice(); @@ -64,16 +64,16 @@ int main() std::shared_ptr material = std::make_shared(); - std::shared_ptr materialPass = std::make_shared(Nz::BasicMaterial::GetSettings()); + std::shared_ptr materialPass = std::make_shared(Nz::PhongLightingMaterial::GetSettings()); materialPass->EnableDepthBuffer(true); materialPass->EnableFaceCulling(true); material->AddPass("ForwardPass", materialPass); - Nz::BasicMaterial basicMat(*materialPass); - basicMat.EnableAlphaTest(false); - basicMat.SetAlphaMap(Nz::Texture::LoadFromFile(resourceDir / "alphatile.png", texParams)); - basicMat.SetDiffuseMap(Nz::Texture::LoadFromFile(resourceDir / "Spaceship/Texture/diffuse.png", texParams)); + Nz::PhongLightingMaterial phongMat(*materialPass); + phongMat.EnableAlphaTest(false); + phongMat.SetAlphaMap(Nz::Texture::LoadFromFile(resourceDir / "alphatile.png", texParams)); + phongMat.SetDiffuseMap(Nz::Texture::LoadFromFile(resourceDir / "Spaceship/Texture/diffuse.png", texParams)); Nz::Model model(std::move(gfxMesh), spaceshipMesh->GetAABB()); for (std::size_t i = 0; i < model.GetSubMeshCount(); ++i) @@ -93,6 +93,8 @@ int main() Nz::WorldInstancePtr modelInstance2 = std::make_shared(); modelInstance2->UpdateWorldMatrix(Nz::Matrix4f::Translate(Nz::Vector3f::Forward() * 2 + Nz::Vector3f::Right())); + model.UpdateScissorBox(Nz::Recti(Nz::Vector2i(window.GetSize()))); + Nz::ForwardFramePipeline framePipeline; framePipeline.RegisterViewer(&camera, 0); framePipeline.RegisterInstancedDrawable(modelInstance, &model, 0xFFFFFFFF); @@ -124,7 +126,7 @@ int main() case Nz::WindowEventType::KeyPressed: if (event.key.virtualKey == Nz::Keyboard::VKey::A) - basicMat.EnableAlphaTest(!basicMat.IsAlphaTestEnabled()); + phongMat.EnableAlphaTest(!phongMat.IsAlphaTestEnabled()); break; @@ -190,9 +192,9 @@ int main() if (!frame) continue; - Nz::UploadPool& uploadPool = frame.GetUploadPool(); - viewerInstance.UpdateViewMatrix(Nz::Matrix4f::ViewMatrix(viewerPos, camAngles)); + viewerInstance.UpdateEyePosition(viewerPos); + framePipeline.InvalidateViewer(&camera); framePipeline.Render(frame); diff --git a/include/Nazara/Graphics/BasicMaterial.hpp b/include/Nazara/Graphics/BasicMaterial.hpp index 813ee73d1..830b3be19 100644 --- a/include/Nazara/Graphics/BasicMaterial.hpp +++ b/include/Nazara/Graphics/BasicMaterial.hpp @@ -19,7 +19,7 @@ namespace Nz friend class MaterialPipeline; public: - struct UniformOffsets; + struct BasicUniformOffsets; BasicMaterial(MaterialPass& material); ~BasicMaterial() = default; @@ -48,10 +48,10 @@ namespace Nz inline void SetDiffuseMap(std::shared_ptr diffuseMap); inline void SetDiffuseSampler(TextureSamplerInfo diffuseSampler); - static inline const UniformOffsets& GetOffsets(); + static inline const BasicUniformOffsets& GetOffsets(); static inline const std::shared_ptr& GetSettings(); - struct UniformOffsets + struct BasicUniformOffsets { std::size_t alphaThreshold; std::size_t diffuseColor; @@ -59,38 +59,59 @@ namespace Nz }; protected: - struct OptionIndexes + struct NoInit {}; + + inline BasicMaterial(MaterialPass& material, NoInit); + + struct BasicOptionIndexes { std::size_t alphaTest; std::size_t hasAlphaMap; std::size_t hasDiffuseMap; }; - struct TextureIndexes + struct BasicTextureIndexes { std::size_t alpha; std::size_t diffuse; }; - static MaterialSettings::Builder Build(const UniformOffsets& offsets, std::vector defaultValues, std::vector> uberShaders, std::size_t* uniformBlockIndex = nullptr, OptionIndexes* optionIndexes = nullptr, TextureIndexes* textureIndexes = nullptr); + struct BasicBuildOptions + { + // Common + std::vector defaultValues; + std::size_t* uniformBlockIndex = nullptr; + std::vector> shaders; + + // Basic + BasicUniformOffsets basicOffsets; + BasicOptionIndexes* basicOptionIndexes = nullptr; + BasicTextureIndexes* basicTextureIndexes = nullptr; + }; + + inline MaterialPass& GetMaterial(); + inline const MaterialPass& GetMaterial() const; + + static MaterialSettings::Builder Build(BasicBuildOptions& options); static std::vector> BuildShaders(); - static std::pair BuildUniformOffsets(); + static std::pair BuildUniformOffsets(); + + std::size_t m_uniformBlockIndex; + BasicOptionIndexes m_basicOptionIndexes; + BasicTextureIndexes m_basicTextureIndexes; + BasicUniformOffsets m_basicUniformOffsets; + + static std::shared_ptr s_basicMaterialSettings; + static std::size_t s_uniformBlockIndex; + static BasicOptionIndexes s_basicOptionIndexes; + static BasicTextureIndexes s_basicTextureIndexes; + static BasicUniformOffsets s_basicUniformOffsets; private: static bool Initialize(); static void Uninitialize(); MaterialPass& m_material; - std::size_t m_uniformBlockIndex; - OptionIndexes m_optionIndexes; - TextureIndexes m_textureIndexes; - UniformOffsets m_uniformOffsets; - - static std::shared_ptr s_materialSettings; - static std::size_t s_uniformBlockIndex; - static OptionIndexes s_optionIndexes; - static TextureIndexes s_textureIndexes; - static UniformOffsets s_uniformOffsets; }; } diff --git a/include/Nazara/Graphics/BasicMaterial.inl b/include/Nazara/Graphics/BasicMaterial.inl index 8e808d56d..879c31347 100644 --- a/include/Nazara/Graphics/BasicMaterial.inl +++ b/include/Nazara/Graphics/BasicMaterial.inl @@ -9,6 +9,11 @@ namespace Nz { + inline BasicMaterial::BasicMaterial(MaterialPass& material, NoInit) : + m_material(material) + { + } + /*! * \brief Enable/Disable alpha test for this material * @@ -26,37 +31,37 @@ namespace Nz inline void BasicMaterial::EnableAlphaTest(bool alphaTest) { NazaraAssert(HasAlphaTest(), "Material has no alpha test option"); - m_material.SetOptionValue(m_optionIndexes.alphaTest, alphaTest); + m_material.SetOptionValue(m_basicOptionIndexes.alphaTest, alphaTest); } inline const std::shared_ptr& BasicMaterial::GetAlphaMap() const { NazaraAssert(HasAlphaMap(), "Material has no alpha texture slot"); - return m_material.GetTexture(m_textureIndexes.alpha); + return m_material.GetTexture(m_basicTextureIndexes.alpha); } inline const TextureSamplerInfo& BasicMaterial::GetAlphaSampler() const { NazaraAssert(HasAlphaMap(), "Material has no alpha texture slot"); - return m_material.GetTextureSampler(m_textureIndexes.alpha); + return m_material.GetTextureSampler(m_basicTextureIndexes.alpha); } inline const std::shared_ptr& BasicMaterial::GetDiffuseMap() const { NazaraAssert(HasDiffuseMap(), "Material has no alpha texture slot"); - return m_material.GetTexture(m_textureIndexes.diffuse); + return m_material.GetTexture(m_basicTextureIndexes.diffuse); } inline const TextureSamplerInfo& BasicMaterial::GetDiffuseSampler() const { NazaraAssert(HasDiffuseMap(), "Material has no alpha texture slot"); - return m_material.GetTextureSampler(m_textureIndexes.diffuse); + return m_material.GetTextureSampler(m_basicTextureIndexes.diffuse); } inline bool BasicMaterial::IsAlphaTestEnabled() const { NazaraAssert(HasAlphaTest(), "Material has no alpha test option"); - const auto& optionOpt = m_material.GetOptionValue(m_optionIndexes.alphaTest); + const auto& optionOpt = m_material.GetOptionValue(m_basicOptionIndexes.alphaTest); if (std::holds_alternative(optionOpt)) return false; @@ -65,69 +70,79 @@ namespace Nz inline bool BasicMaterial::HasAlphaMap() const { - return m_textureIndexes.alpha != MaterialSettings::InvalidIndex; + return m_basicTextureIndexes.alpha != MaterialSettings::InvalidIndex; } inline bool BasicMaterial::HasAlphaTest() const { - return m_optionIndexes.alphaTest != MaterialSettings::InvalidIndex; + return m_basicOptionIndexes.alphaTest != MaterialSettings::InvalidIndex; } inline bool BasicMaterial::HasAlphaTestThreshold() const { - return m_uniformOffsets.alphaThreshold != MaterialSettings::InvalidIndex; + return m_basicUniformOffsets.alphaThreshold != MaterialSettings::InvalidIndex; } inline bool BasicMaterial::HasDiffuseColor() const { - return m_uniformOffsets.diffuseColor != MaterialSettings::InvalidIndex; + return m_basicUniformOffsets.diffuseColor != MaterialSettings::InvalidIndex; } inline bool BasicMaterial::HasDiffuseMap() const { - return m_textureIndexes.diffuse != MaterialSettings::InvalidIndex; + return m_basicTextureIndexes.diffuse != MaterialSettings::InvalidIndex; } inline void BasicMaterial::SetAlphaMap(std::shared_ptr alphaMap) { NazaraAssert(HasAlphaMap(), "Material has no alpha map slot"); bool hasAlphaMap = (alphaMap != nullptr); - m_material.SetTexture(m_textureIndexes.alpha, std::move(alphaMap)); + m_material.SetTexture(m_basicTextureIndexes.alpha, std::move(alphaMap)); - if (m_optionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex) - m_material.SetOptionValue(m_optionIndexes.hasAlphaMap, hasAlphaMap); + if (m_basicOptionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex) + m_material.SetOptionValue(m_basicOptionIndexes.hasAlphaMap, hasAlphaMap); } inline void BasicMaterial::SetAlphaSampler(TextureSamplerInfo alphaSampler) { NazaraAssert(HasAlphaMap(), "Material has no alpha map slot"); - m_material.SetTextureSampler(m_textureIndexes.alpha, std::move(alphaSampler)); + m_material.SetTextureSampler(m_basicTextureIndexes.alpha, std::move(alphaSampler)); } inline void BasicMaterial::SetDiffuseMap(std::shared_ptr diffuseMap) { NazaraAssert(HasDiffuseMap(), "Material has no diffuse map slot"); bool hasDiffuseMap = (diffuseMap != nullptr); - m_material.SetTexture(m_textureIndexes.diffuse, std::move(diffuseMap)); + m_material.SetTexture(m_basicTextureIndexes.diffuse, std::move(diffuseMap)); - if (m_optionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex) - m_material.SetOptionValue(m_optionIndexes.hasDiffuseMap, hasDiffuseMap); + if (m_basicOptionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex) + m_material.SetOptionValue(m_basicOptionIndexes.hasDiffuseMap, hasDiffuseMap); } inline void BasicMaterial::SetDiffuseSampler(TextureSamplerInfo diffuseSampler) { NazaraAssert(HasDiffuseMap(), "Material has no diffuse map slot"); - m_material.SetTextureSampler(m_textureIndexes.diffuse, std::move(diffuseSampler)); + m_material.SetTextureSampler(m_basicTextureIndexes.diffuse, std::move(diffuseSampler)); + } + + inline MaterialPass& BasicMaterial::GetMaterial() + { + return m_material; + } + + inline const MaterialPass& BasicMaterial::GetMaterial() const + { + return m_material; } inline const std::shared_ptr& BasicMaterial::GetSettings() { - return s_materialSettings; + return s_basicMaterialSettings; } - inline auto BasicMaterial::GetOffsets() -> const UniformOffsets& + inline auto BasicMaterial::GetOffsets() -> const BasicUniformOffsets& { - return s_uniformOffsets; + return s_basicUniformOffsets; } } diff --git a/include/Nazara/Graphics/DepthMaterial.hpp b/include/Nazara/Graphics/DepthMaterial.hpp index 9973a6088..3d59b19e6 100644 --- a/include/Nazara/Graphics/DepthMaterial.hpp +++ b/include/Nazara/Graphics/DepthMaterial.hpp @@ -29,7 +29,7 @@ namespace Nz static bool Initialize(); static void Uninitialize(); - static std::shared_ptr s_materialSettings; + static std::shared_ptr s_basicMaterialSettings; }; } diff --git a/include/Nazara/Graphics/DepthMaterial.inl b/include/Nazara/Graphics/DepthMaterial.inl index 717c7d45f..0eb450c61 100644 --- a/include/Nazara/Graphics/DepthMaterial.inl +++ b/include/Nazara/Graphics/DepthMaterial.inl @@ -9,7 +9,7 @@ namespace Nz { inline const std::shared_ptr& DepthMaterial::GetSettings() { - return s_materialSettings; + return s_basicMaterialSettings; } } diff --git a/include/Nazara/Graphics/ElementRenderer.hpp b/include/Nazara/Graphics/ElementRenderer.hpp index cc4e0326e..6d76a83d7 100644 --- a/include/Nazara/Graphics/ElementRenderer.hpp +++ b/include/Nazara/Graphics/ElementRenderer.hpp @@ -16,6 +16,7 @@ namespace Nz { + class AbstractBuffer; class CommandBufferBuilder; class RenderElement; class RenderFrame; @@ -25,13 +26,20 @@ namespace Nz class NAZARA_GRAPHICS_API ElementRenderer { public: + struct RenderStates; + ElementRenderer() = default; virtual ~ElementRenderer(); virtual std::unique_ptr InstanciateData() = 0; - virtual void Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, const Pointer* elements, std::size_t elementCount); + virtual void Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, const RenderStates& renderStates, const Pointer* elements, std::size_t elementCount); virtual void Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, const Pointer* elements, std::size_t elementCount) = 0; virtual void Reset(ElementRendererData& rendererData, RenderFrame& currentFrame); + + struct RenderStates + { + std::shared_ptr lightData; + }; }; struct NAZARA_GRAPHICS_API ElementRendererData diff --git a/include/Nazara/Graphics/Enums.hpp b/include/Nazara/Graphics/Enums.hpp index efb71518e..3566afc28 100644 --- a/include/Nazara/Graphics/Enums.hpp +++ b/include/Nazara/Graphics/Enums.hpp @@ -12,6 +12,15 @@ namespace Nz { + enum class BasicLightType + { + Directional, + Point, + Spot, + + Max = Spot + }; + enum class BasicRenderElement { SpriteChain = 0, @@ -54,6 +63,7 @@ namespace Nz enum class PredefinedShaderBinding { InstanceDataUbo, + LightDataUbo, OverlayTexture, ViewerDataUbo, diff --git a/include/Nazara/Graphics/ForwardFramePipeline.hpp b/include/Nazara/Graphics/ForwardFramePipeline.hpp index e72570fa2..3c3ad6dfc 100644 --- a/include/Nazara/Graphics/ForwardFramePipeline.hpp +++ b/include/Nazara/Graphics/ForwardFramePipeline.hpp @@ -108,6 +108,7 @@ namespace Nz std::size_t m_depthPassIndex; std::size_t m_forwardPassIndex; + std::shared_ptr m_lightDataBuffer; std::unordered_map m_viewers; std::unordered_map m_materials; std::unordered_map> m_renderables; diff --git a/include/Nazara/Graphics/Graphics.hpp b/include/Nazara/Graphics/Graphics.hpp index a5b8f1abc..493aa1591 100644 --- a/include/Nazara/Graphics/Graphics.hpp +++ b/include/Nazara/Graphics/Graphics.hpp @@ -57,10 +57,6 @@ namespace Nz std::array, ImageTypeCount> whiteTextures; }; - static void FillDrawDataPipelineLayout(RenderPipelineLayoutInfo& layoutInfo, UInt32 set); - static void FillViewerPipelineLayout(RenderPipelineLayoutInfo& layoutInfo, UInt32 set); - static void FillWorldPipelineLayout(RenderPipelineLayoutInfo& layoutInfo, UInt32 set); - private: void BuildBlitPipeline(); void BuildDefaultTextures(); diff --git a/include/Nazara/Graphics/MaterialPass.hpp b/include/Nazara/Graphics/MaterialPass.hpp index 004390b9e..82569af11 100644 --- a/include/Nazara/Graphics/MaterialPass.hpp +++ b/include/Nazara/Graphics/MaterialPass.hpp @@ -75,7 +75,7 @@ namespace Nz inline const std::shared_ptr& GetTexture(std::size_t textureIndex) const; inline const TextureSamplerInfo& GetTextureSampler(std::size_t textureIndex) const; inline const std::shared_ptr& GetUniformBuffer(std::size_t bufferIndex) const; - inline const std::vector& GetUniformBufferConstData(std::size_t bufferIndex); + inline const std::vector& GetUniformBufferConstData(std::size_t bufferIndex) const; inline std::vector& GetUniformBufferData(std::size_t bufferIndex); inline bool HasTexture(std::size_t textureIndex) const; diff --git a/include/Nazara/Graphics/MaterialPass.inl b/include/Nazara/Graphics/MaterialPass.inl index 8f964c7bf..47c2075c8 100644 --- a/include/Nazara/Graphics/MaterialPass.inl +++ b/include/Nazara/Graphics/MaterialPass.inl @@ -391,7 +391,7 @@ namespace Nz return m_uniformBuffers[bufferIndex].buffer; } - inline const std::vector& MaterialPass::GetUniformBufferConstData(std::size_t bufferIndex) + inline const std::vector& MaterialPass::GetUniformBufferConstData(std::size_t bufferIndex) const { NazaraAssert(bufferIndex < m_uniformBuffers.size(), "Invalid uniform buffer index"); return m_uniformBuffers[bufferIndex].data; diff --git a/include/Nazara/Graphics/PhongLightingMaterial.hpp b/include/Nazara/Graphics/PhongLightingMaterial.hpp index 14266a247..c6d4b88f9 100644 --- a/include/Nazara/Graphics/PhongLightingMaterial.hpp +++ b/include/Nazara/Graphics/PhongLightingMaterial.hpp @@ -8,38 +8,31 @@ #define NAZARA_GRAPHICS_PHONGLIGHTINGMATERIAL_HPP #include +#include #include namespace Nz { - class NAZARA_GRAPHICS_API PhongLightingMaterial + class NAZARA_GRAPHICS_API PhongLightingMaterial : public BasicMaterial { friend class MaterialPipeline; public: PhongLightingMaterial(MaterialPass& material); - inline const std::shared_ptr& GetAlphaMap() const; - float GetAlphaThreshold() const; Color GetAmbientColor() const; - Color GetDiffuseColor() const; - inline const std::shared_ptr& GetDiffuseMap() const; - inline TextureSampler& GetDiffuseSampler(); - inline const TextureSampler& GetDiffuseSampler() const; inline const std::shared_ptr& GetEmissiveMap() const; + inline const TextureSamplerInfo& GetEmissiveSampler() const; inline const std::shared_ptr& GetHeightMap() const; + inline const TextureSamplerInfo& GetHeightSampler() const; inline const std::shared_ptr& GetNormalMap() const; + inline const TextureSamplerInfo& GetNormalSampler() const; float GetShininess() const; Color GetSpecularColor() const; inline const std::shared_ptr& GetSpecularMap() const; - inline TextureSampler& GetSpecularSampler(); - inline const TextureSampler& GetSpecularSampler() const; + inline const TextureSamplerInfo& GetSpecularSampler() const; - inline bool HasAlphaMap() const; - inline bool HasAlphaThreshold() const; inline bool HasAmbientColor() const; - inline bool HasDiffuseColor() const; - inline bool HasDiffuseMap() const; inline bool HasEmissiveMap() const; inline bool HasHeightMap() const; inline bool HasNormalMap() const; @@ -47,53 +40,68 @@ namespace Nz inline bool HasSpecularColor() const; inline bool HasSpecularMap() const; - inline void SetAlphaMap(std::shared_ptr alphaMap); - void SetAlphaThreshold(float alphaThreshold); void SetAmbientColor(const Color& ambient); - void SetDiffuseColor(const Color& diffuse); - inline void SetDiffuseMap(std::shared_ptr diffuseMap); - inline void SetDiffuseSampler(const TextureSampler& sampler); - inline void SetEmissiveMap(std::shared_ptr textureName); - inline void SetHeightMap(std::shared_ptr textureName); - inline void SetNormalMap(std::shared_ptr textureName); + inline void SetEmissiveMap(std::shared_ptr emissiveMap); + inline void SetEmissiveSampler(TextureSamplerInfo emissiveSampler); + inline void SetHeightMap(std::shared_ptr heightMap); + inline void SetHeightSampler(TextureSamplerInfo heightSampler); + inline void SetNormalMap(std::shared_ptr normalMap); + inline void SetNormalSampler(TextureSamplerInfo normalSampler); void SetShininess(float shininess); void SetSpecularColor(const Color& specular); inline void SetSpecularMap(std::shared_ptr specularMap); - inline void SetSpecularSampler(const TextureSampler& sampler); + inline void SetSpecularSampler(TextureSamplerInfo specularSampler); static const std::shared_ptr& GetSettings(); - private: + protected: + struct PhongOptionIndexes + { + std::size_t hasEmissiveMap; + std::size_t hasHeightMap; + std::size_t hasNormalMap; + std::size_t hasSpecularMap; + }; + struct PhongUniformOffsets { - std::size_t alphaThreshold; - std::size_t shininess; std::size_t ambientColor; - std::size_t diffuseColor; + std::size_t shininess; + std::size_t totalSize; std::size_t specularColor; }; - struct TextureIndexes + struct PhongTextureIndexes { - std::size_t alpha; - std::size_t diffuse; std::size_t emissive; std::size_t height; std::size_t normal; std::size_t specular; }; + struct PhongBuildOptions : BasicBuildOptions + { + PhongUniformOffsets phongOffsets; + PhongOptionIndexes* phongOptionIndexes = nullptr; + PhongTextureIndexes* phongTextureIndexes = nullptr; + }; + + PhongOptionIndexes m_phongOptionIndexes; + PhongTextureIndexes m_phongTextureIndexes; + PhongUniformOffsets m_phongUniformOffsets; + + static MaterialSettings::Builder Build(PhongBuildOptions& options); + static std::vector> BuildShaders(); + static std::pair BuildUniformOffsets(); + + private: static bool Initialize(); static void Uninitialize(); - MaterialPass& m_material; - std::size_t m_phongUniformIndex; - TextureIndexes m_textureIndexes; - PhongUniformOffsets m_phongUniformOffsets; - - static std::shared_ptr s_materialSettings; + static std::shared_ptr s_phongMaterialSettings; static std::size_t s_phongUniformBlockIndex; - static TextureIndexes s_textureIndexes; + static PhongOptionIndexes s_phongOptionIndexes; + static PhongTextureIndexes s_phongTextureIndexes; static PhongUniformOffsets s_phongUniformOffsets; }; } diff --git a/include/Nazara/Graphics/PhongLightingMaterial.inl b/include/Nazara/Graphics/PhongLightingMaterial.inl index 2b5c0b67b..0cce436b7 100644 --- a/include/Nazara/Graphics/PhongLightingMaterial.inl +++ b/include/Nazara/Graphics/PhongLightingMaterial.inl @@ -9,50 +9,52 @@ namespace Nz { - inline const std::shared_ptr& PhongLightingMaterial::GetAlphaMap() const - { - NazaraAssert(HasAlphaMap(), "Material has no alpha map slot"); - return m_material.GetTexture(m_textureIndexes.alpha); - } - - inline const std::shared_ptr& PhongLightingMaterial::GetDiffuseMap() const - { - NazaraAssert(HasDiffuseMap(), "Material has no alpha map slot"); - return m_material.GetTexture(m_textureIndexes.diffuse); - } - inline const std::shared_ptr& PhongLightingMaterial::GetEmissiveMap() const { - NazaraAssert(HasEmissiveMap(), "Material has no alpha map slot"); - return m_material.GetTexture(m_textureIndexes.emissive); + NazaraAssert(HasEmissiveMap(), "Material has no emissive map slot"); + return GetMaterial().GetTexture(m_phongTextureIndexes.emissive); + } + + inline const TextureSamplerInfo& PhongLightingMaterial::GetEmissiveSampler() const + { + NazaraAssert(HasSpecularMap(), "Material has no emissive map slot"); + return GetMaterial().GetTextureSampler(m_phongTextureIndexes.emissive); } inline const std::shared_ptr& PhongLightingMaterial::GetHeightMap() const { - NazaraAssert(HasHeightMap(), "Material has no alpha map slot"); - return m_material.GetTexture(m_textureIndexes.height); + NazaraAssert(HasHeightMap(), "Material has no height map slot"); + return GetMaterial().GetTexture(m_phongTextureIndexes.height); + } + + inline const TextureSamplerInfo& PhongLightingMaterial::GetHeightSampler() const + { + NazaraAssert(HasSpecularMap(), "Material has no height map slot"); + return GetMaterial().GetTextureSampler(m_phongTextureIndexes.height); } inline const std::shared_ptr& PhongLightingMaterial::GetNormalMap() const { - NazaraAssert(HasNormalMap(), "Material has no alpha map slot"); - return m_material.GetTexture(m_textureIndexes.normal); + NazaraAssert(HasNormalMap(), "Material has no normal map slot"); + return GetMaterial().GetTexture(m_phongTextureIndexes.normal); + } + + inline const TextureSamplerInfo& PhongLightingMaterial::GetNormalSampler() const + { + NazaraAssert(HasSpecularMap(), "Material has no normal map slot"); + return GetMaterial().GetTextureSampler(m_phongTextureIndexes.normal); } inline const std::shared_ptr& PhongLightingMaterial::GetSpecularMap() const { - NazaraAssert(HasSpecularMap(), "Material has no alpha map slot"); - return m_material.GetTexture(m_textureIndexes.specular); + NazaraAssert(HasSpecularMap(), "Material has no specular map slot"); + return GetMaterial().GetTexture(m_phongTextureIndexes.specular); } - inline bool PhongLightingMaterial::HasAlphaMap() const + inline const TextureSamplerInfo& PhongLightingMaterial::GetSpecularSampler() const { - return m_textureIndexes.alpha != MaterialSettings::InvalidIndex; - } - - inline bool PhongLightingMaterial::HasAlphaThreshold() const - { - return m_phongUniformOffsets.alphaThreshold != MaterialSettings::InvalidIndex; + NazaraAssert(HasSpecularMap(), "Material has no specular map slot"); + return GetMaterial().GetTextureSampler(m_phongTextureIndexes.specular); } inline bool PhongLightingMaterial::HasAmbientColor() const @@ -60,29 +62,19 @@ namespace Nz return m_phongUniformOffsets.ambientColor != MaterialSettings::InvalidIndex; } - inline bool PhongLightingMaterial::HasDiffuseColor() const - { - return m_phongUniformOffsets.diffuseColor != MaterialSettings::InvalidIndex; - } - - inline bool PhongLightingMaterial::HasDiffuseMap() const - { - return m_textureIndexes.diffuse != MaterialSettings::InvalidIndex; - } - inline bool PhongLightingMaterial::HasEmissiveMap() const { - return m_textureIndexes.emissive != MaterialSettings::InvalidIndex; + return m_phongTextureIndexes.emissive != MaterialSettings::InvalidIndex; } inline bool PhongLightingMaterial::HasHeightMap() const { - return m_textureIndexes.height != MaterialSettings::InvalidIndex; + return m_phongTextureIndexes.height != MaterialSettings::InvalidIndex; } inline bool PhongLightingMaterial::HasNormalMap() const { - return m_textureIndexes.normal != MaterialSettings::InvalidIndex; + return m_phongTextureIndexes.normal != MaterialSettings::InvalidIndex; } inline bool PhongLightingMaterial::HasShininess() const @@ -97,25 +89,71 @@ namespace Nz inline bool PhongLightingMaterial::HasSpecularMap() const { - return m_textureIndexes.specular != MaterialSettings::InvalidIndex; + return m_phongTextureIndexes.specular != MaterialSettings::InvalidIndex; } - inline void PhongLightingMaterial::SetAlphaMap(std::shared_ptr alphaMap) + inline void PhongLightingMaterial::SetEmissiveMap(std::shared_ptr emissiveMap) { - NazaraAssert(HasAlphaMap(), "Material has no alpha map slot"); - m_material.SetTexture(m_textureIndexes.alpha, std::move(alphaMap)); + NazaraAssert(HasEmissiveMap(), "Material has no emissive map slot"); + bool hasEmissiveMap = (emissiveMap != nullptr); + GetMaterial().SetTexture(m_phongTextureIndexes.emissive, std::move(emissiveMap)); + + if (m_phongOptionIndexes.hasEmissiveMap != MaterialSettings::InvalidIndex) + GetMaterial().SetOptionValue(m_phongOptionIndexes.hasEmissiveMap, hasEmissiveMap); } - inline void PhongLightingMaterial::SetDiffuseMap(std::shared_ptr diffuseMap) + inline void PhongLightingMaterial::SetEmissiveSampler(TextureSamplerInfo emissiveSampler) { - NazaraAssert(HasDiffuseMap(), "Material has no diffuse map slot"); - m_material.SetTexture(m_textureIndexes.diffuse, std::move(diffuseMap)); + NazaraAssert(HasEmissiveMap(), "Material has no emissive map slot"); + GetMaterial().SetTextureSampler(m_phongTextureIndexes.emissive, std::move(emissiveSampler)); + } + + inline void PhongLightingMaterial::SetHeightMap(std::shared_ptr heightMap) + { + NazaraAssert(HasHeightMap(), "Material has no specular map slot"); + bool hasHeightMap = (heightMap != nullptr); + GetMaterial().SetTexture(m_phongTextureIndexes.height, std::move(heightMap)); + + if (m_phongOptionIndexes.hasHeightMap != MaterialSettings::InvalidIndex) + GetMaterial().SetOptionValue(m_phongOptionIndexes.hasHeightMap, hasHeightMap); + } + + inline void PhongLightingMaterial::SetHeightSampler(TextureSamplerInfo heightSampler) + { + NazaraAssert(HasHeightMap(), "Material has no height map slot"); + GetMaterial().SetTextureSampler(m_phongTextureIndexes.height, std::move(heightSampler)); } inline void PhongLightingMaterial::SetNormalMap(std::shared_ptr normalMap) { NazaraAssert(HasNormalMap(), "Material has no normal map slot"); - m_material.SetTexture(m_textureIndexes.normal, std::move(normalMap)); + bool hasNormalMap = (normalMap != nullptr); + GetMaterial().SetTexture(m_phongTextureIndexes.normal, std::move(normalMap)); + + if (m_phongOptionIndexes.hasNormalMap != MaterialSettings::InvalidIndex) + GetMaterial().SetOptionValue(m_phongOptionIndexes.hasNormalMap, hasNormalMap); + } + + inline void PhongLightingMaterial::SetNormalSampler(TextureSamplerInfo normalSampler) + { + NazaraAssert(HasNormalMap(), "Material has no normal map slot"); + GetMaterial().SetTextureSampler(m_phongTextureIndexes.normal, std::move(normalSampler)); + } + + inline void PhongLightingMaterial::SetSpecularMap(std::shared_ptr specularMap) + { + NazaraAssert(HasNormalMap(), "Material has no specular map slot"); + bool hasSpecularMap = (specularMap != nullptr); + GetMaterial().SetTexture(m_phongTextureIndexes.specular, std::move(specularMap)); + + if (m_phongOptionIndexes.hasSpecularMap != MaterialSettings::InvalidIndex) + GetMaterial().SetOptionValue(m_phongOptionIndexes.hasSpecularMap, hasSpecularMap); + } + + inline void PhongLightingMaterial::SetSpecularSampler(TextureSamplerInfo specularSampler) + { + NazaraAssert(HasSpecularMap(), "Material has no specular map slot"); + GetMaterial().SetTextureSampler(m_phongTextureIndexes.specular, std::move(specularSampler)); } } diff --git a/include/Nazara/Graphics/PredefinedShaderStructs.hpp b/include/Nazara/Graphics/PredefinedShaderStructs.hpp index a86ba29ea..05b144988 100644 --- a/include/Nazara/Graphics/PredefinedShaderStructs.hpp +++ b/include/Nazara/Graphics/PredefinedShaderStructs.hpp @@ -15,7 +15,7 @@ namespace Nz { struct NAZARA_GRAPHICS_API PredefinedLightData { - struct InnerStruct + struct Light { std::size_t type; std::size_t color; @@ -24,15 +24,18 @@ namespace Nz std::size_t parameter2; std::size_t parameter3; std::size_t shadowMappingFlag; - std::size_t totalSize; }; - InnerStruct innerOffsets; - std::array lightArray; - std::size_t lightArraySize; + std::size_t lightsOffset; + std::size_t lightCountOffset; + std::size_t lightSize; + std::size_t totalSize; + Light lightMemberOffsets; + + static constexpr std::size_t MaxLightCount = 3; static PredefinedLightData GetOffsets(); - static MaterialSettings::SharedUniformBlock GetUniformBlock(); + static MaterialSettings::SharedUniformBlock GetUniformBlock(UInt32 bindingIndex, ShaderStageTypeFlags shaderStages); }; struct NAZARA_GRAPHICS_API PredefinedInstanceData diff --git a/include/Nazara/Graphics/Sprite.inl b/include/Nazara/Graphics/Sprite.inl index 636d13766..276728c40 100644 --- a/include/Nazara/Graphics/Sprite.inl +++ b/include/Nazara/Graphics/Sprite.inl @@ -89,7 +89,7 @@ namespace Nz inline void Sprite::UpdateVertices() { - Boxf aabb; + Boxf aabb = Boxf::Zero(); VertexStruct_XYZ_Color_UV* vertices = m_vertices.data(); @@ -105,7 +105,10 @@ namespace Nz vertices->position = Vector3f(m_size * cornerExtent[UnderlyingCast(corner)], 0.f) - m_origin; vertices->uv = m_textureCoords.GetCorner(corner); - aabb.Set(vertices->position); + if (aabb.IsValid()) + aabb.ExtendTo(vertices->position); + else + aabb.Set(vertices->position); vertices++; } diff --git a/include/Nazara/Graphics/SpriteChainRenderer.hpp b/include/Nazara/Graphics/SpriteChainRenderer.hpp index 2b86f232f..bc1079fba 100644 --- a/include/Nazara/Graphics/SpriteChainRenderer.hpp +++ b/include/Nazara/Graphics/SpriteChainRenderer.hpp @@ -31,7 +31,7 @@ namespace Nz ~SpriteChainRenderer() = default; std::unique_ptr InstanciateData() override; - void Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, const Pointer* elements, std::size_t elementCount) override; + void Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, const RenderStates& renderStates, const Pointer* elements, std::size_t elementCount) override; void Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, const Pointer* elements, std::size_t elementCount) override; void Reset(ElementRendererData& rendererData, RenderFrame& currentFrame) override; diff --git a/include/Nazara/Graphics/SubmeshRenderer.hpp b/include/Nazara/Graphics/SubmeshRenderer.hpp index 88ba8e525..dc973505e 100644 --- a/include/Nazara/Graphics/SubmeshRenderer.hpp +++ b/include/Nazara/Graphics/SubmeshRenderer.hpp @@ -21,13 +21,13 @@ namespace Nz class NAZARA_GRAPHICS_API SubmeshRenderer : public ElementRenderer { public: - SubmeshRenderer(); + SubmeshRenderer() = default; ~SubmeshRenderer() = default; - std::unique_ptr InstanciateData(); - void Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, const Pointer* elements, std::size_t elementCount); + std::unique_ptr InstanciateData() override; + void Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, const RenderStates& renderStates, const Pointer* elements, std::size_t elementCount) override; void Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, const Pointer* elements, std::size_t elementCount) override; - void Reset(ElementRendererData& rendererData, RenderFrame& currentFrame); + void Reset(ElementRendererData& rendererData, RenderFrame& currentFrame) override; private: std::vector m_bindingCache; diff --git a/include/Nazara/Graphics/ViewerInstance.hpp b/include/Nazara/Graphics/ViewerInstance.hpp index ebe9fd715..320d04d49 100644 --- a/include/Nazara/Graphics/ViewerInstance.hpp +++ b/include/Nazara/Graphics/ViewerInstance.hpp @@ -28,6 +28,7 @@ namespace Nz ViewerInstance(ViewerInstance&&) noexcept = default; ~ViewerInstance() = default; + inline const Vector3f& GetEyePosition() const; inline const Matrix4f& GetInvProjectionMatrix() const; inline const Matrix4f& GetInvViewMatrix() const; inline const Matrix4f& GetInvViewProjMatrix() const; @@ -39,6 +40,7 @@ namespace Nz inline const std::shared_ptr& GetViewerBuffer() const; void UpdateBuffers(UploadPool& uploadPool, CommandBufferBuilder& builder); + inline void UpdateEyePosition(const Vector3f& eyePosition); inline void UpdateProjectionMatrix(const Matrix4f& projectionMatrix); inline void UpdateProjectionMatrix(const Matrix4f& projectionMatrix, const Matrix4f& invProjectionMatrix); inline void UpdateProjViewMatrices(const Matrix4f& projectionMatrix, const Matrix4f& viewMatrix); @@ -60,6 +62,7 @@ namespace Nz Matrix4f m_viewProjMatrix; Matrix4f m_viewMatrix; Vector2f m_targetSize; + Vector3f m_eyePosition; bool m_dataInvalided; }; } diff --git a/include/Nazara/Graphics/ViewerInstance.inl b/include/Nazara/Graphics/ViewerInstance.inl index b492955cb..26dcf906a 100644 --- a/include/Nazara/Graphics/ViewerInstance.inl +++ b/include/Nazara/Graphics/ViewerInstance.inl @@ -8,6 +8,11 @@ namespace Nz { + inline const Vector3f& ViewerInstance::GetEyePosition() const + { + return m_eyePosition; + } + inline const Matrix4f& ViewerInstance::GetInvProjectionMatrix() const { return m_invProjectionMatrix; @@ -53,6 +58,12 @@ namespace Nz return m_viewerDataBuffer; } + inline void ViewerInstance::UpdateEyePosition(const Vector3f& eyePosition) + { + m_eyePosition = eyePosition; + m_dataInvalided = true; + } + inline void ViewerInstance::UpdateProjectionMatrix(const Matrix4f& projectionMatrix) { m_projectionMatrix = projectionMatrix; diff --git a/include/Nazara/Shader/Ast/Enums.hpp b/include/Nazara/Shader/Ast/Enums.hpp index e15b2ce1d..4c0d3cb85 100644 --- a/include/Nazara/Shader/Ast/Enums.hpp +++ b/include/Nazara/Shader/Ast/Enums.hpp @@ -103,7 +103,9 @@ namespace Nz Length = 3, Max = 4, Min = 5, + Normalize = 9, Pow = 6, + Reflect = 8, SampleTexture = 2, }; diff --git a/include/Nazara/Shader/Ast/SanitizeVisitor.hpp b/include/Nazara/Shader/Ast/SanitizeVisitor.hpp index e9383f1ca..7274b399a 100644 --- a/include/Nazara/Shader/Ast/SanitizeVisitor.hpp +++ b/include/Nazara/Shader/Ast/SanitizeVisitor.hpp @@ -40,6 +40,7 @@ namespace Nz::ShaderAst std::unordered_set reservedIdentifiers; std::unordered_map optionValues; bool makeVariableNameUnique = false; + bool removeConstDeclaration = false; bool reduceLoopsToWhile = false; bool removeCompoundAssignments = false; bool removeOptionDeclaration = false; diff --git a/src/Nazara/Graphics/BasicMaterial.cpp b/src/Nazara/Graphics/BasicMaterial.cpp index 0d62ff96c..870d32833 100644 --- a/src/Nazara/Graphics/BasicMaterial.cpp +++ b/src/Nazara/Graphics/BasicMaterial.cpp @@ -25,30 +25,37 @@ namespace Nz } BasicMaterial::BasicMaterial(MaterialPass& material) : - m_material(material) + BasicMaterial(material, NoInit{}) { // Most common case: don't fetch texture indexes as a little optimization const std::shared_ptr& materialSettings = material.GetSettings(); - if (materialSettings == s_materialSettings) + if (materialSettings == s_basicMaterialSettings) { - m_optionIndexes = s_optionIndexes; - m_textureIndexes = s_textureIndexes; + m_basicOptionIndexes = s_basicOptionIndexes; + m_basicTextureIndexes = s_basicTextureIndexes; m_uniformBlockIndex = s_uniformBlockIndex; - m_uniformOffsets = s_uniformOffsets; + m_basicUniformOffsets = s_basicUniformOffsets; } else { - m_optionIndexes.alphaTest = materialSettings->GetOptionIndex("AlphaTest"); - m_optionIndexes.hasAlphaMap = materialSettings->GetOptionIndex("HasAlphaMap"); - m_optionIndexes.hasDiffuseMap = materialSettings->GetOptionIndex("HasDiffuseMap"); + m_basicOptionIndexes.alphaTest = materialSettings->GetOptionIndex("AlphaTest"); + m_basicOptionIndexes.hasAlphaMap = materialSettings->GetOptionIndex("HasAlphaMap"); + m_basicOptionIndexes.hasDiffuseMap = materialSettings->GetOptionIndex("HasDiffuseMap"); - m_textureIndexes.alpha = materialSettings->GetTextureIndex("Alpha"); - m_textureIndexes.diffuse = materialSettings->GetTextureIndex("Diffuse"); + m_basicTextureIndexes.alpha = materialSettings->GetTextureIndex("Alpha"); + m_basicTextureIndexes.diffuse = materialSettings->GetTextureIndex("Diffuse"); - m_uniformBlockIndex = materialSettings->GetUniformBlockIndex("BasicSettings"); - - m_uniformOffsets.alphaThreshold = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "AlphaThreshold"); - m_uniformOffsets.diffuseColor = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "DiffuseColor"); + m_uniformBlockIndex = materialSettings->GetUniformBlockIndex("MaterialSettings"); + if (m_uniformBlockIndex != MaterialSettings::InvalidIndex) + { + m_basicUniformOffsets.alphaThreshold = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "AlphaThreshold"); + m_basicUniformOffsets.diffuseColor = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "DiffuseColor"); + } + else + { + m_basicUniformOffsets.alphaThreshold = MaterialSettings::InvalidIndex; + m_basicUniformOffsets.diffuseColor = MaterialSettings::InvalidIndex; + } } } @@ -58,7 +65,7 @@ namespace Nz const std::vector& bufferData = m_material.GetUniformBufferConstData(m_uniformBlockIndex); - return AccessByOffset(bufferData.data(), m_uniformOffsets.alphaThreshold); + return AccessByOffset(bufferData.data(), m_basicUniformOffsets.alphaThreshold); } Color BasicMaterial::GetDiffuseColor() const @@ -67,7 +74,7 @@ namespace Nz const std::vector& bufferData = m_material.GetUniformBufferConstData(m_uniformBlockIndex); - const float* colorPtr = AccessByOffset(bufferData.data(), m_uniformOffsets.diffuseColor); + const float* colorPtr = AccessByOffset(bufferData.data(), m_basicUniformOffsets.diffuseColor); return Color(colorPtr[0] * 255, colorPtr[1] * 255, colorPtr[2] * 255, colorPtr[3] * 255); //< TODO: Make color able to use float } @@ -76,7 +83,7 @@ namespace Nz NazaraAssert(HasAlphaTestThreshold(), "Material has no alpha threshold uniform"); std::vector& bufferData = m_material.GetUniformBufferData(m_uniformBlockIndex); - AccessByOffset(bufferData.data(), m_uniformOffsets.alphaThreshold) = alphaThreshold; + AccessByOffset(bufferData.data(), m_basicUniformOffsets.alphaThreshold) = alphaThreshold; } void BasicMaterial::SetDiffuseColor(const Color& diffuse) @@ -85,44 +92,45 @@ namespace Nz std::vector& bufferData = m_material.GetUniformBufferData(m_uniformBlockIndex); - float* colorPtr = AccessByOffset(bufferData.data(), m_uniformOffsets.diffuseColor); + float* colorPtr = AccessByOffset(bufferData.data(), m_basicUniformOffsets.diffuseColor); colorPtr[0] = diffuse.r / 255.f; colorPtr[1] = diffuse.g / 255.f; colorPtr[2] = diffuse.b / 255.f; colorPtr[3] = diffuse.a / 255.f; } - MaterialSettings::Builder BasicMaterial::Build(const UniformOffsets& offsets, std::vector defaultValues, std::vector> uberShaders, std::size_t* uniformBlockIndex, OptionIndexes* optionIndexes, TextureIndexes* textureIndexes) + MaterialSettings::Builder BasicMaterial::Build(BasicBuildOptions& options) { MaterialSettings::Builder settings; std::vector variables; - if (offsets.alphaThreshold != std::numeric_limits::max()) + if (options.basicOffsets.alphaThreshold != std::numeric_limits::max()) { variables.push_back({ "AlphaThreshold", - offsets.alphaThreshold + options.basicOffsets.alphaThreshold }); } - if (offsets.diffuseColor != std::numeric_limits::max()) + if (options.basicOffsets.diffuseColor != std::numeric_limits::max()) { variables.push_back({ "DiffuseColor", - offsets.diffuseColor + options.basicOffsets.diffuseColor }); } - if (offsets.alphaThreshold != std::numeric_limits::max()) - AccessByOffset(defaultValues.data(), offsets.alphaThreshold) = 0.2f; - static_assert(sizeof(Vector4f) == 4 * sizeof(float), "Vector4f is expected to be exactly 4 floats wide"); - if (offsets.diffuseColor != std::numeric_limits::max()) - AccessByOffset(defaultValues.data(), offsets.diffuseColor) = Vector4f(1.f, 1.f, 1.f, 1.f); + + if (options.basicOffsets.alphaThreshold != std::numeric_limits::max()) + AccessByOffset(options.defaultValues.data(), options.basicOffsets.alphaThreshold) = 0.2f; + + if (options.basicOffsets.diffuseColor != std::numeric_limits::max()) + AccessByOffset(options.defaultValues.data(), options.basicOffsets.diffuseColor) = Vector4f(1.f, 1.f, 1.f, 1.f); // Textures - if (textureIndexes) - textureIndexes->alpha = settings.textures.size(); + if (options.basicTextureIndexes) + options.basicTextureIndexes->alpha = settings.textures.size(); settings.textures.push_back({ 2, @@ -130,8 +138,8 @@ namespace Nz ImageType::E2D }); - if (textureIndexes) - textureIndexes->diffuse = settings.textures.size(); + if (options.basicTextureIndexes) + options.basicTextureIndexes->diffuse = settings.textures.size(); settings.textures.push_back({ 1, @@ -139,15 +147,15 @@ namespace Nz ImageType::E2D }); - if (uniformBlockIndex) - *uniformBlockIndex = settings.uniformBlocks.size(); + if (options.uniformBlockIndex) + *options.uniformBlockIndex = settings.uniformBlocks.size(); settings.uniformBlocks.push_back({ 0, - "BasicSettings", - offsets.totalSize, + "MaterialSettings", + options.basicOffsets.totalSize, std::move(variables), - std::move(defaultValues) + options.defaultValues }); // Common data @@ -164,7 +172,7 @@ namespace Nz settings.predefinedBindings[UnderlyingCast(PredefinedShaderBinding::OverlayTexture)] = 3; settings.predefinedBindings[UnderlyingCast(PredefinedShaderBinding::ViewerDataUbo)] = 5; - settings.shaders = std::move(uberShaders); + settings.shaders = options.shaders; for (std::shared_ptr uberShader : settings.shaders) { @@ -230,20 +238,20 @@ namespace Nz // Options // HasDiffuseMap - if (optionIndexes) - optionIndexes->hasDiffuseMap = settings.options.size(); + if (options.basicOptionIndexes) + options.basicOptionIndexes->hasDiffuseMap = settings.options.size(); MaterialSettings::BuildOption(settings.options, settings.shaders, "HasDiffuseMap", "HasDiffuseTexture"); // HasAlphaMap - if (optionIndexes) - optionIndexes->hasAlphaMap = settings.options.size(); + if (options.basicOptionIndexes) + options.basicOptionIndexes->hasAlphaMap = settings.options.size(); MaterialSettings::BuildOption(settings.options, settings.shaders, "HasAlphaMap", "HasAlphaTexture"); // AlphaTest - if (optionIndexes) - optionIndexes->alphaTest = settings.options.size(); + if (options.basicOptionIndexes) + options.basicOptionIndexes->alphaTest = settings.options.size(); MaterialSettings::BuildOption(settings.options, settings.shaders, "AlphaTest", "AlphaTest"); @@ -258,36 +266,46 @@ namespace Nz return { std::move(shader) }; } - auto BasicMaterial::BuildUniformOffsets() -> std::pair + auto BasicMaterial::BuildUniformOffsets() -> std::pair { FieldOffsets fieldOffsets(StructLayout::Std140); - UniformOffsets uniformOffsets; + BasicUniformOffsets uniformOffsets; uniformOffsets.alphaThreshold = fieldOffsets.AddField(StructFieldType::Float1); uniformOffsets.diffuseColor = fieldOffsets.AddField(StructFieldType::Float4); - uniformOffsets.totalSize = fieldOffsets.GetSize(); + uniformOffsets.totalSize = fieldOffsets.GetAlignedSize(); return std::make_pair(std::move(uniformOffsets), std::move(fieldOffsets)); } bool BasicMaterial::Initialize() { - std::tie(s_uniformOffsets, std::ignore) = BuildUniformOffsets(); + std::tie(s_basicUniformOffsets, std::ignore) = BuildUniformOffsets(); - std::vector defaultValues(s_uniformOffsets.totalSize); - s_materialSettings = std::make_shared(Build(s_uniformOffsets, std::move(defaultValues), BuildShaders(), &s_uniformBlockIndex, &s_optionIndexes, &s_textureIndexes)); + std::vector defaultValues(s_basicUniformOffsets.totalSize); + + BasicBuildOptions options; + options.defaultValues.resize(s_basicUniformOffsets.totalSize); + options.shaders = BuildShaders(); + + options.basicOffsets = s_basicUniformOffsets; + options.basicOptionIndexes = &s_basicOptionIndexes; + options.basicTextureIndexes = &s_basicTextureIndexes; + options.uniformBlockIndex = &s_uniformBlockIndex; + + s_basicMaterialSettings = std::make_shared(Build(options)); return true; } void BasicMaterial::Uninitialize() { - s_materialSettings.reset(); + s_basicMaterialSettings.reset(); } - std::shared_ptr BasicMaterial::s_materialSettings; + std::shared_ptr BasicMaterial::s_basicMaterialSettings; std::size_t BasicMaterial::s_uniformBlockIndex; - BasicMaterial::OptionIndexes BasicMaterial::s_optionIndexes; - BasicMaterial::TextureIndexes BasicMaterial::s_textureIndexes; - BasicMaterial::UniformOffsets BasicMaterial::s_uniformOffsets; + BasicMaterial::BasicOptionIndexes BasicMaterial::s_basicOptionIndexes; + BasicMaterial::BasicTextureIndexes BasicMaterial::s_basicTextureIndexes; + BasicMaterial::BasicUniformOffsets BasicMaterial::s_basicUniformOffsets; } diff --git a/src/Nazara/Graphics/DepthMaterial.cpp b/src/Nazara/Graphics/DepthMaterial.cpp index 2e722e0e1..580db8d71 100644 --- a/src/Nazara/Graphics/DepthMaterial.cpp +++ b/src/Nazara/Graphics/DepthMaterial.cpp @@ -26,19 +26,26 @@ namespace Nz bool DepthMaterial::Initialize() { - UniformOffsets offsets; + BasicUniformOffsets offsets; std::tie(offsets, std::ignore) = BuildUniformOffsets(); - std::vector defaultValues(offsets.totalSize); - s_materialSettings = std::make_shared(Build(offsets, std::move(defaultValues), BuildShaders())); + BasicBuildOptions options; + options.defaultValues.resize(offsets.totalSize); + options.shaders = BuildShaders(); + + options.basicOffsets = s_basicUniformOffsets; + options.basicOptionIndexes = &s_basicOptionIndexes; + options.basicTextureIndexes = &s_basicTextureIndexes; + + s_basicMaterialSettings = std::make_shared(Build(options)); return true; } void DepthMaterial::Uninitialize() { - s_materialSettings.reset(); + s_basicMaterialSettings.reset(); } - std::shared_ptr DepthMaterial::s_materialSettings; + std::shared_ptr DepthMaterial::s_basicMaterialSettings; } diff --git a/src/Nazara/Graphics/ElementRenderer.cpp b/src/Nazara/Graphics/ElementRenderer.cpp index 92c358d85..b43681d03 100644 --- a/src/Nazara/Graphics/ElementRenderer.cpp +++ b/src/Nazara/Graphics/ElementRenderer.cpp @@ -9,7 +9,7 @@ namespace Nz { ElementRenderer::~ElementRenderer() = default; - void ElementRenderer::Prepare(const ViewerInstance& /*viewerInstance*/, ElementRendererData& /*rendererData*/, RenderFrame& /*currentFrame*/, const Pointer* /*elements*/, std::size_t /*elementCount*/) + void ElementRenderer::Prepare(const ViewerInstance& /*viewerInstance*/, ElementRendererData& /*rendererData*/, RenderFrame& /*currentFrame*/, const RenderStates& /*renderStates*/, const Pointer* /*elements*/, std::size_t /*elementCount*/) { } diff --git a/src/Nazara/Graphics/ForwardFramePipeline.cpp b/src/Nazara/Graphics/ForwardFramePipeline.cpp index 67346b724..ad0eff987 100644 --- a/src/Nazara/Graphics/ForwardFramePipeline.cpp +++ b/src/Nazara/Graphics/ForwardFramePipeline.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,23 @@ namespace Nz m_elementRenderers.resize(BasicRenderElementCount); m_elementRenderers[UnderlyingCast(BasicRenderElement::SpriteChain)] = std::make_unique(*Graphics::Instance()->GetRenderDevice()); m_elementRenderers[UnderlyingCast(BasicRenderElement::Submesh)] = std::make_unique(); + + auto lightOffset = PredefinedLightData::GetOffsets(); + + m_lightDataBuffer = Graphics::Instance()->GetRenderDevice()->InstantiateBuffer(BufferType::Uniform); + if (!m_lightDataBuffer->Initialize(lightOffset.totalSize, BufferUsage::DeviceLocal)) + throw std::runtime_error("failed to create light data buffer"); + + std::vector staticLightData(lightOffset.totalSize); + AccessByOffset(staticLightData.data(), lightOffset.lightCountOffset) = 1; + AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.type) = 0; + AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.color) = Vector4f(1.f, 1.f, 1.f, 1.f); + AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.factor) = Vector2f(0.2f, 1.f); + AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.parameter1) = Vector4f(0.f, 0.f, -1.f, 1.f); + AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.shadowMappingFlag) = 0; + + if (!m_lightDataBuffer->Fill(staticLightData.data(), 0, staticLightData.size())) + throw std::runtime_error("failed to fill light data buffer"); } void ForwardFramePipeline::InvalidateViewer(AbstractViewer* viewerInstance) @@ -320,16 +338,19 @@ namespace Nz const auto& viewerInstance = viewer->GetViewerInstance(); + ElementRenderer::RenderStates renderStates; + renderStates.lightData = m_lightDataBuffer; + ProcessRenderQueue(viewerData.depthPrepassRenderQueue, [&](std::size_t elementType, const Pointer* elements, std::size_t elementCount) { ElementRenderer& elementRenderer = *m_elementRenderers[elementType]; - elementRenderer.Prepare(viewerInstance, *rendererData[elementType], renderFrame, elements, elementCount); + elementRenderer.Prepare(viewerInstance, *rendererData[elementType], renderFrame, renderStates, elements, elementCount); }); ProcessRenderQueue(viewerData.forwardRenderQueue, [&](std::size_t elementType, const Pointer* elements, std::size_t elementCount) { ElementRenderer& elementRenderer = *m_elementRenderers[elementType]; - elementRenderer.Prepare(viewerInstance, *rendererData[elementType], renderFrame, elements, elementCount); + elementRenderer.Prepare(viewerInstance, *rendererData[elementType], renderFrame, renderStates, elements, elementCount); }); } diff --git a/src/Nazara/Graphics/Graphics.cpp b/src/Nazara/Graphics/Graphics.cpp index ec982ccd0..3583a692a 100644 --- a/src/Nazara/Graphics/Graphics.cpp +++ b/src/Nazara/Graphics/Graphics.cpp @@ -113,36 +113,6 @@ namespace Nz m_defaultTextures.whiteTextures.fill(nullptr); } - void Graphics::FillDrawDataPipelineLayout(RenderPipelineLayoutInfo& layoutInfo, UInt32 set) - { - // TextureOverlay - layoutInfo.bindings.push_back({ - set, 0, - ShaderBindingType::Texture, - ShaderStageType_All - }); - } - - void Graphics::FillViewerPipelineLayout(RenderPipelineLayoutInfo& layoutInfo, UInt32 set) - { - // ViewerData - layoutInfo.bindings.push_back({ - set, 0, - ShaderBindingType::UniformBuffer, - ShaderStageType_All - }); - } - - void Graphics::FillWorldPipelineLayout(RenderPipelineLayoutInfo& layoutInfo, UInt32 set) - { - // InstanceData - layoutInfo.bindings.push_back({ - set, 0, - ShaderBindingType::UniformBuffer, - ShaderStageType_All - }); - } - void Graphics::BuildBlitPipeline() { RenderPipelineLayoutInfo layoutInfo; diff --git a/src/Nazara/Graphics/PhongLightingMaterial.cpp b/src/Nazara/Graphics/PhongLightingMaterial.cpp index a205fd146..663184e72 100644 --- a/src/Nazara/Graphics/PhongLightingMaterial.cpp +++ b/src/Nazara/Graphics/PhongLightingMaterial.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -15,69 +16,84 @@ namespace Nz { + namespace + { + const UInt8 r_shader[] = { + #include + }; + } + PhongLightingMaterial::PhongLightingMaterial(MaterialPass& material) : - m_material(material) + BasicMaterial(material, NoInit{}) { // Most common case: don't fetch texture indexes as a little optimization - const std::shared_ptr& materialSettings = m_material.GetSettings(); - if (materialSettings == s_materialSettings) + const std::shared_ptr& materialSettings = GetMaterial().GetSettings(); + if (materialSettings == s_phongMaterialSettings) { - m_textureIndexes = s_textureIndexes; - m_phongUniformIndex = s_phongUniformBlockIndex; + m_basicUniformOffsets = s_basicUniformOffsets; + m_basicOptionIndexes = s_basicOptionIndexes; + m_basicTextureIndexes = s_basicTextureIndexes; + + m_phongOptionIndexes = s_phongOptionIndexes; + m_phongTextureIndexes = s_phongTextureIndexes; m_phongUniformOffsets = s_phongUniformOffsets; } else { - m_textureIndexes.alpha = materialSettings->GetTextureIndex("Alpha"); - m_textureIndexes.diffuse = materialSettings->GetTextureIndex("Diffuse"); - m_textureIndexes.emissive = materialSettings->GetTextureIndex("Emissive"); - m_textureIndexes.height = materialSettings->GetTextureIndex("Height"); - m_textureIndexes.normal = materialSettings->GetTextureIndex("Normal"); - m_textureIndexes.specular = materialSettings->GetTextureIndex("Specular"); + m_basicOptionIndexes.alphaTest = materialSettings->GetOptionIndex("AlphaTest"); + m_basicOptionIndexes.hasAlphaMap = materialSettings->GetOptionIndex("HasAlphaMap"); + m_basicOptionIndexes.hasDiffuseMap = materialSettings->GetOptionIndex("HasDiffuseMap"); - m_phongUniformIndex = materialSettings->GetUniformBlockIndex("PhongSettings"); + m_phongOptionIndexes.hasEmissiveMap = materialSettings->GetOptionIndex("HasEmissiveMap"); + m_phongOptionIndexes.hasHeightMap = materialSettings->GetOptionIndex("HasHeightMap"); + m_phongOptionIndexes.hasNormalMap = materialSettings->GetOptionIndex("HasNormalMap"); + m_phongOptionIndexes.hasSpecularMap = materialSettings->GetOptionIndex("HasSpecularMap"); - m_phongUniformOffsets.alphaThreshold = materialSettings->GetUniformBlockVariableOffset(m_phongUniformIndex, "AlphaThreshold"); - m_phongUniformOffsets.ambientColor = materialSettings->GetUniformBlockVariableOffset(m_phongUniformIndex, "AmbientColor"); - m_phongUniformOffsets.diffuseColor = materialSettings->GetUniformBlockVariableOffset(m_phongUniformIndex, "DiffuseColor"); - m_phongUniformOffsets.shininess = materialSettings->GetUniformBlockVariableOffset(m_phongUniformIndex, "Shininess"); - m_phongUniformOffsets.specularColor = materialSettings->GetUniformBlockVariableOffset(m_phongUniformIndex, "SpecularColor"); + m_basicTextureIndexes.alpha = materialSettings->GetTextureIndex("Alpha"); + m_basicTextureIndexes.diffuse = materialSettings->GetTextureIndex("Diffuse"); + + m_phongTextureIndexes.emissive = materialSettings->GetTextureIndex("Emissive"); + m_phongTextureIndexes.height = materialSettings->GetTextureIndex("Height"); + m_phongTextureIndexes.normal = materialSettings->GetTextureIndex("Normal"); + m_phongTextureIndexes.specular = materialSettings->GetTextureIndex("Specular"); + + m_uniformBlockIndex = materialSettings->GetUniformBlockIndex("MaterialSettings"); + if (m_uniformBlockIndex != MaterialSettings::InvalidIndex) + { + m_basicUniformOffsets.alphaThreshold = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "AlphaThreshold"); + m_basicUniformOffsets.diffuseColor = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "DiffuseColor"); + + m_phongUniformOffsets.ambientColor = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "AmbientColor"); + m_phongUniformOffsets.shininess = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "Shininess"); + m_phongUniformOffsets.specularColor = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "SpecularColor"); + } + else + { + m_basicUniformOffsets.alphaThreshold = MaterialSettings::InvalidIndex; + m_basicUniformOffsets.diffuseColor = MaterialSettings::InvalidIndex; + + m_phongUniformOffsets.ambientColor = MaterialSettings::InvalidIndex; + m_phongUniformOffsets.shininess = MaterialSettings::InvalidIndex; + m_phongUniformOffsets.specularColor = MaterialSettings::InvalidIndex; + } } } - float PhongLightingMaterial::GetAlphaThreshold() const - { - NazaraAssert(HasAlphaThreshold(), "Material has no alpha threshold uniform"); - - const std::vector& bufferData = m_material.GetUniformBufferConstData(m_phongUniformIndex); - return AccessByOffset(bufferData.data(), m_phongUniformOffsets.alphaThreshold); - } - Color PhongLightingMaterial::GetAmbientColor() const { NazaraAssert(HasAmbientColor(), "Material has no ambient color uniform"); - const std::vector& bufferData = m_material.GetUniformBufferConstData(m_phongUniformIndex); + const std::vector& bufferData = GetMaterial().GetUniformBufferConstData(m_uniformBlockIndex); const float* colorPtr = AccessByOffset(bufferData.data(), m_phongUniformOffsets.ambientColor); return Color(colorPtr[0] * 255, colorPtr[1] * 255, colorPtr[2] * 255, colorPtr[3] * 255); //< TODO: Make color able to use float } - Color PhongLightingMaterial::GetDiffuseColor() const - { - NazaraAssert(HasDiffuseColor(), "Material has no diffuse color uniform"); - - const std::vector& bufferData = m_material.GetUniformBufferConstData(m_phongUniformIndex); - - const float* colorPtr = AccessByOffset(bufferData.data(), m_phongUniformOffsets.diffuseColor); - return Color(colorPtr[0] * 255, colorPtr[1] * 255, colorPtr[2] * 255, colorPtr[3] * 255); //< TODO: Make color able to use float - } - float Nz::PhongLightingMaterial::GetShininess() const { NazaraAssert(HasShininess(), "Material has no shininess uniform"); - const std::vector& bufferData = m_material.GetUniformBufferConstData(m_phongUniformIndex); + const std::vector& bufferData = GetMaterial().GetUniformBufferConstData(m_uniformBlockIndex); return AccessByOffset(bufferData.data(), m_phongUniformOffsets.shininess); } @@ -85,25 +101,17 @@ namespace Nz { NazaraAssert(HasSpecularColor(), "Material has no specular color uniform"); - const std::vector& bufferData = m_material.GetUniformBufferConstData(m_phongUniformIndex); + const std::vector& bufferData = GetMaterial().GetUniformBufferConstData(m_uniformBlockIndex); const float* colorPtr = AccessByOffset(bufferData.data(), m_phongUniformOffsets.specularColor); return Color(colorPtr[0] * 255, colorPtr[1] * 255, colorPtr[2] * 255, colorPtr[3] * 255); //< TODO: Make color able to use float } - void PhongLightingMaterial::SetAlphaThreshold(float alphaThreshold) - { - NazaraAssert(HasAlphaThreshold(), "Material has no alpha threshold uniform"); - - std::vector& bufferData = m_material.GetUniformBufferData(m_phongUniformIndex); - AccessByOffset(bufferData.data(), m_phongUniformOffsets.alphaThreshold) = alphaThreshold; - } - void PhongLightingMaterial::SetAmbientColor(const Color& ambient) { NazaraAssert(HasAmbientColor(), "Material has no ambient color uniform"); - std::vector& bufferData = m_material.GetUniformBufferData(m_phongUniformIndex); + std::vector& bufferData = GetMaterial().GetUniformBufferData(m_uniformBlockIndex); float* colorPtr = AccessByOffset(bufferData.data(), m_phongUniformOffsets.ambientColor); colorPtr[0] = ambient.r / 255.f; colorPtr[1] = ambient.g / 255.f; @@ -111,23 +119,19 @@ namespace Nz colorPtr[3] = ambient.a / 255.f; } - void PhongLightingMaterial::SetDiffuseColor(const Color& diffuse) + void PhongLightingMaterial::SetShininess(float shininess) { - NazaraAssert(HasDiffuseColor(), "Material has no diffuse color uniform"); + NazaraAssert(HasShininess(), "Material has no shininess uniform"); - std::vector& bufferData = m_material.GetUniformBufferData(m_phongUniformIndex); - float* colorPtr = AccessByOffset(bufferData.data(), m_phongUniformOffsets.diffuseColor); - colorPtr[0] = diffuse.r / 255.f; - colorPtr[1] = diffuse.g / 255.f; - colorPtr[2] = diffuse.b / 255.f; - colorPtr[3] = diffuse.a / 255.f; + std::vector& bufferData = GetMaterial().GetUniformBufferData(m_uniformBlockIndex); + AccessByOffset(bufferData.data(), m_phongUniformOffsets.shininess) = shininess; } void PhongLightingMaterial::SetSpecularColor(const Color& diffuse) { NazaraAssert(HasSpecularColor(), "Material has no specular color uniform"); - std::vector& bufferData = m_material.GetUniformBufferData(m_phongUniformIndex); + std::vector& bufferData = GetMaterial().GetUniformBufferData(m_uniformBlockIndex); float* colorPtr = AccessByOffset(bufferData.data(), m_phongUniformOffsets.specularColor); colorPtr[0] = diffuse.r / 255.f; colorPtr[1] = diffuse.g / 255.f; @@ -137,118 +141,256 @@ namespace Nz const std::shared_ptr& PhongLightingMaterial::GetSettings() { - return s_materialSettings; + return s_phongMaterialSettings; } - bool PhongLightingMaterial::Initialize() + MaterialSettings::Builder PhongLightingMaterial::Build(PhongBuildOptions& options) { - // MaterialPhongSettings - FieldOffsets phongUniformStruct(StructLayout::Std140); + MaterialSettings::Builder settings = BasicMaterial::Build(options); - s_phongUniformOffsets.alphaThreshold = phongUniformStruct.AddField(StructFieldType::Float1); - s_phongUniformOffsets.shininess = phongUniformStruct.AddField(StructFieldType::Float1); - s_phongUniformOffsets.ambientColor = phongUniformStruct.AddField(StructFieldType::Float4); - s_phongUniformOffsets.diffuseColor = phongUniformStruct.AddField(StructFieldType::Float4); - s_phongUniformOffsets.specularColor = phongUniformStruct.AddField(StructFieldType::Float4); + assert(settings.uniformBlocks.size() == 1); + std::vector variables = std::move(settings.uniformBlocks.front().uniforms); + settings.uniformBlocks.clear(); - MaterialSettings::Builder settings; - - std::vector phongVariables; - phongVariables.assign({ - { - "AlphaThreshold", - s_phongUniformOffsets.alphaThreshold - }, - { - "Shininess", - s_phongUniformOffsets.shininess - }, - { + if (options.phongOffsets.ambientColor != std::numeric_limits::max()) + { + variables.push_back({ "AmbientColor", - s_phongUniformOffsets.ambientColor - }, - { - "DiffuseColor", - s_phongUniformOffsets.diffuseColor - }, - { + options.phongOffsets.ambientColor + }); + } + + if (options.phongOffsets.shininess != std::numeric_limits::max()) + { + variables.push_back({ + "Shininess", + options.phongOffsets.shininess + }); + } + + if (options.phongOffsets.shininess != std::numeric_limits::max()) + { + variables.push_back({ "SpecularColor", - s_phongUniformOffsets.specularColor - } - }); + options.phongOffsets.specularColor + }); + } static_assert(sizeof(Vector4f) == 4 * sizeof(float), "Vector4f is expected to be exactly 4 floats wide"); - std::vector defaultValues(phongUniformStruct.GetSize()); - AccessByOffset(defaultValues.data(), s_phongUniformOffsets.ambientColor) = Vector4f(0.5f, 0.5f, 0.5f, 1.f); - AccessByOffset(defaultValues.data(), s_phongUniformOffsets.diffuseColor) = Vector4f(1.f, 1.f, 1.f, 1.f); - AccessByOffset(defaultValues.data(), s_phongUniformOffsets.specularColor) = Vector4f(1.f, 1.f, 1.f, 1.f); - AccessByOffset(defaultValues.data(), s_phongUniformOffsets.alphaThreshold) = 0.2f; - AccessByOffset(defaultValues.data(), s_phongUniformOffsets.shininess) = 50.f; + if (options.phongOffsets.ambientColor != std::numeric_limits::max()) + AccessByOffset(options.defaultValues.data(), options.phongOffsets.ambientColor) = Vector4f(0.f, 0.f, 0.f, 1.f); - s_phongUniformBlockIndex = settings.uniformBlocks.size(); - settings.uniformBlocks.push_back({ - 0, - "PhongSettings", - phongUniformStruct.GetSize(), - std::move(phongVariables), - std::move(defaultValues) - }); + if (options.phongOffsets.specularColor != std::numeric_limits::max()) + AccessByOffset(options.defaultValues.data(), options.phongOffsets.specularColor) = Vector4f(1.f, 1.f, 1.f, 1.f); - s_textureIndexes.alpha = settings.textures.size(); - settings.textures.push_back({ - 2, - "Alpha", - ImageType::E2D - }); - - s_textureIndexes.diffuse = settings.textures.size(); - settings.textures.push_back({ - 1, - "Diffuse", - ImageType::E2D - }); + if (options.phongOffsets.shininess != std::numeric_limits::max()) + AccessByOffset(options.defaultValues.data(), options.phongOffsets.shininess) = 2.f; + + // Textures + if (options.phongTextureIndexes) + options.phongTextureIndexes->emissive = settings.textures.size(); - s_textureIndexes.emissive = settings.textures.size(); settings.textures.push_back({ - 3, + 7, "Emissive", ImageType::E2D }); - s_textureIndexes.height = settings.textures.size(); + if (options.phongTextureIndexes) + options.phongTextureIndexes->height = settings.textures.size(); + settings.textures.push_back({ - 4, + 8, "Height", ImageType::E2D }); - s_textureIndexes.normal = settings.textures.size(); + if (options.phongTextureIndexes) + options.phongTextureIndexes->normal = settings.textures.size(); + settings.textures.push_back({ - 5, + 9, "Normal", ImageType::E2D }); - s_textureIndexes.specular = settings.textures.size(); + if (options.phongTextureIndexes) + options.phongTextureIndexes->specular = settings.textures.size(); + settings.textures.push_back({ - 6, + 10, "Specular", ImageType::E2D }); - s_materialSettings = std::make_shared(std::move(settings)); + if (options.uniformBlockIndex) + *options.uniformBlockIndex = settings.uniformBlocks.size(); + + settings.uniformBlocks.push_back({ + 0, + "MaterialSettings", + options.phongOffsets.totalSize, + std::move(variables), + options.defaultValues + }); + + settings.sharedUniformBlocks.push_back(PredefinedLightData::GetUniformBlock(6, ShaderStageType::Fragment)); + settings.predefinedBindings[UnderlyingCast(PredefinedShaderBinding::LightDataUbo)] = 6; + + settings.shaders = options.shaders; + + for (std::shared_ptr uberShader : settings.shaders) + { + constexpr std::size_t InvalidOption = std::numeric_limits::max(); + + auto FetchLocationOption = [&](const std::string& optionName) + { + const UberShader::Option* optionPtr; + if (!uberShader->HasOption(optionName, &optionPtr)) + return InvalidOption; + + if (optionPtr->type != ShaderAst::ExpressionType{ ShaderAst::PrimitiveType::Int32 }) + throw std::runtime_error("Location options must be of type i32"); + + return optionPtr->index; + }; + + std::size_t positionLocationIndex = FetchLocationOption("PosLocation"); + std::size_t colorLocationIndex = FetchLocationOption("ColorLocation"); + std::size_t normalLocationIndex = FetchLocationOption("NormalLocation"); + std::size_t uvLocationIndex = FetchLocationOption("UvLocation"); + + uberShader->UpdateConfigCallback([=](UberShader::Config& config, const std::vector& vertexBuffers) + { + if (vertexBuffers.empty()) + return; + + const VertexDeclaration& vertexDeclaration = *vertexBuffers.front().declaration; + const auto& components = vertexDeclaration.GetComponents(); + + std::size_t locationIndex = 0; + for (const auto& component : components) + { + switch (component.component) + { + case VertexComponent::Position: + if (positionLocationIndex != InvalidOption) + config.optionValues[positionLocationIndex] = static_cast(locationIndex); + + break; + + case VertexComponent::Color: + if (colorLocationIndex != InvalidOption) + config.optionValues[colorLocationIndex] = static_cast(locationIndex); + + break; + + case VertexComponent::Normal: + if (normalLocationIndex != InvalidOption) + config.optionValues[normalLocationIndex] = static_cast(locationIndex); + + break; + + case VertexComponent::TexCoord: + if (uvLocationIndex != InvalidOption) + config.optionValues[uvLocationIndex] = static_cast(locationIndex); + + break; + + case VertexComponent::Unused: + default: + break; + } + + ++locationIndex; + } + }); + } + + // Options + + // HasEmissiveMap + if (options.phongOptionIndexes) + options.phongOptionIndexes->hasEmissiveMap = settings.options.size(); + + MaterialSettings::BuildOption(settings.options, settings.shaders, "HasEmissiveMap", "HasEmissiveTexture"); + + // HasHeightMap + if (options.phongOptionIndexes) + options.phongOptionIndexes->hasHeightMap = settings.options.size(); + + MaterialSettings::BuildOption(settings.options, settings.shaders, "HasHeightMap", "HasHeightTexture"); + + // HasNormalMap + if (options.phongOptionIndexes) + options.phongOptionIndexes->hasNormalMap = settings.options.size(); + + MaterialSettings::BuildOption(settings.options, settings.shaders, "HasNormalMap", "HasNormalTexture"); + + // HasSpecularMap + if (options.phongOptionIndexes) + options.phongOptionIndexes->hasSpecularMap = settings.options.size(); + + MaterialSettings::BuildOption(settings.options, settings.shaders, "HasSpecularMap", "HasSpecularTexture"); + + return settings; + } + + std::vector> PhongLightingMaterial::BuildShaders() + { + ShaderAst::StatementPtr shaderAst = ShaderLang::Parse(std::string_view(reinterpret_cast(r_shader), sizeof(r_shader))); + auto shader = std::make_shared(ShaderStageType::Fragment | ShaderStageType::Vertex, shaderAst); + + return { std::move(shader) }; + } + + auto PhongLightingMaterial::BuildUniformOffsets() -> std::pair + { + auto basicOffsets = BasicMaterial::BuildUniformOffsets(); + FieldOffsets fieldOffsets = basicOffsets.second; + + PhongUniformOffsets uniformOffsets; + uniformOffsets.ambientColor = fieldOffsets.AddField(StructFieldType::Float3); + uniformOffsets.specularColor = fieldOffsets.AddField(StructFieldType::Float3); + uniformOffsets.shininess = fieldOffsets.AddField(StructFieldType::Float1); + + uniformOffsets.totalSize = fieldOffsets.GetAlignedSize(); + + return std::make_pair(std::move(uniformOffsets), std::move(fieldOffsets)); + } + + bool PhongLightingMaterial::Initialize() + { + std::tie(s_phongUniformOffsets, std::ignore) = BuildUniformOffsets(); + + std::vector defaultValues(s_phongUniformOffsets.totalSize); + + PhongBuildOptions options; + options.defaultValues = std::move(defaultValues); + options.shaders = BuildShaders(); + + // Basic material + options.basicOffsets = s_basicUniformOffsets; + + // Phong Material + options.phongOffsets = s_phongUniformOffsets; + options.phongOptionIndexes = &s_phongOptionIndexes; + options.phongTextureIndexes = &s_phongTextureIndexes; + + s_phongMaterialSettings = std::make_shared(Build(options)); return true; } void PhongLightingMaterial::Uninitialize() { - s_materialSettings.reset(); + s_phongMaterialSettings.reset(); } - std::shared_ptr PhongLightingMaterial::s_materialSettings; + std::shared_ptr PhongLightingMaterial::s_phongMaterialSettings; std::size_t PhongLightingMaterial::s_phongUniformBlockIndex; - PhongLightingMaterial::TextureIndexes PhongLightingMaterial::s_textureIndexes; + PhongLightingMaterial::PhongOptionIndexes PhongLightingMaterial::s_phongOptionIndexes; + PhongLightingMaterial::PhongTextureIndexes PhongLightingMaterial::s_phongTextureIndexes; PhongLightingMaterial::PhongUniformOffsets PhongLightingMaterial::s_phongUniformOffsets; } diff --git a/src/Nazara/Graphics/PredefinedShaderStructs.cpp b/src/Nazara/Graphics/PredefinedShaderStructs.cpp index 06999c7fb..c071001bb 100644 --- a/src/Nazara/Graphics/PredefinedShaderStructs.cpp +++ b/src/Nazara/Graphics/PredefinedShaderStructs.cpp @@ -13,42 +13,40 @@ namespace Nz PredefinedLightData lightData; FieldOffsets lightStruct(StructLayout::Std140); - lightData.innerOffsets.type = lightStruct.AddField(StructFieldType::Int1); - lightData.innerOffsets.color = lightStruct.AddField(StructFieldType::Float4); - lightData.innerOffsets.factor = lightStruct.AddField(StructFieldType::Float2); - lightData.innerOffsets.parameter1 = lightStruct.AddField(StructFieldType::Float4); - lightData.innerOffsets.parameter2 = lightStruct.AddField(StructFieldType::Float4); - lightData.innerOffsets.parameter3 = lightStruct.AddField(StructFieldType::Float2); - lightData.innerOffsets.shadowMappingFlag = lightStruct.AddField(StructFieldType::Bool1); + lightData.lightMemberOffsets.type = lightStruct.AddField(StructFieldType::Int1); + lightData.lightMemberOffsets.color = lightStruct.AddField(StructFieldType::Float4); + lightData.lightMemberOffsets.factor = lightStruct.AddField(StructFieldType::Float2); + lightData.lightMemberOffsets.parameter1 = lightStruct.AddField(StructFieldType::Float4); + lightData.lightMemberOffsets.parameter2 = lightStruct.AddField(StructFieldType::Float4); + lightData.lightMemberOffsets.parameter3 = lightStruct.AddField(StructFieldType::Float4); + lightData.lightMemberOffsets.shadowMappingFlag = lightStruct.AddField(StructFieldType::Bool1); - lightData.innerOffsets.totalSize = lightStruct.GetAlignedSize(); + lightData.lightSize = lightStruct.GetAlignedSize(); FieldOffsets lightDataStruct(StructLayout::Std140); - for (std::size_t& lightOffset : lightData.lightArray) - lightOffset = lightDataStruct.AddStruct(lightStruct); + lightData.lightsOffset = lightDataStruct.AddStructArray(lightStruct, MaxLightCount); + lightData.lightCountOffset = lightDataStruct.AddField(StructFieldType::UInt1); - lightData.lightArraySize = lightDataStruct.GetAlignedSize(); + lightData.totalSize = lightDataStruct.GetAlignedSize(); return lightData; } - MaterialSettings::SharedUniformBlock PredefinedLightData::GetUniformBlock() + MaterialSettings::SharedUniformBlock PredefinedLightData::GetUniformBlock(UInt32 bindingIndex, ShaderStageTypeFlags shaderStages) { PredefinedLightData lightData = GetOffsets(); - std::vector lightDataVariables; - for (std::size_t i = 0; i < lightData.lightArray.size(); ++i) - { - lightDataVariables.push_back({ - "LightData[" + std::to_string(i) + "]", - lightData.lightArray[i] - }); - } + std::vector variables = { + { + { "Lights", lightData.lightsOffset } + } + }; MaterialSettings::SharedUniformBlock uniformBlock = { - 0, //< FIXME - "Light", - std::move(lightDataVariables) + bindingIndex, + "LightData", + std::move(variables), + shaderStages }; return uniformBlock; diff --git a/src/Nazara/Graphics/Resources/Shaders/basic_material.nzsl b/src/Nazara/Graphics/Resources/Shaders/basic_material.nzsl index c7311494e..114956a74 100644 --- a/src/Nazara/Graphics/Resources/Shaders/basic_material.nzsl +++ b/src/Nazara/Graphics/Resources/Shaders/basic_material.nzsl @@ -2,16 +2,23 @@ option HasDiffuseTexture: bool = false; option HasAlphaTexture: bool = false; option AlphaTest: bool = false; +// Billboard related options +option Billboard: bool = false; +option BillboardCenterLocation: i32 = -1; +option BillboardColorLocation: i32 = -1; +option BillboardSizeRotLocation: i32 = -1; + // Vertex declaration related options -option PosLocation: i32 = -1; option ColorLocation: i32 = -1; +option PosLocation: i32 = -1; option UvLocation: i32 = -1; const HasVertexColor = (ColorLocation >= 0); +const HasColor = (HasVertexColor || Billboard); const HasUV = (UvLocation >= 0); [layout(std140)] -struct BasicSettings +struct MaterialSettings { AlphaThreshold: f32, DiffuseColor: vec4 @@ -40,7 +47,7 @@ struct ViewerData external { - [binding(0)] settings: uniform, + [binding(0)] settings: uniform, [binding(1)] MaterialDiffuseMap: sampler2D, [binding(2)] MaterialAlphaMap: sampler2D, [binding(3)] TextureOverlay: sampler2D, @@ -52,7 +59,7 @@ external struct FragIn { [location(0), cond(HasUV)] uv: vec2, - [location(1), cond(HasVertexColor)] color: vec4 + [location(1), cond(HasColor)] color: vec4 } struct FragOut @@ -68,7 +75,7 @@ fn main(input: FragIn) -> FragOut const if (HasUV) diffuseColor *= TextureOverlay.Sample(input.uv); - const if (HasVertexColor) + const if (HasColor) diffuseColor *= input.color; const if (HasDiffuseTexture) @@ -91,25 +98,70 @@ fn main(input: FragIn) -> FragOut // Vertex stage struct VertIn { - [location(PosLocation)] pos: vec3, - [location(ColorLocation), cond(HasVertexColor)] color: vec4, - [location(UvLocation), cond(HasUV)] uv: vec2 + [location(PosLocation)] + pos: vec3, + + [cond(HasVertexColor), location(ColorLocation)] + color: vec4, + + [cond(HasUV), location(UvLocation)] + uv: vec2, + + [cond(Billboard), location(BillboardCenterLocation)] + billboardCenter: vec3, + + [cond(Billboard), location(BillboardSizeRotLocation)] + billboardSizeRot: vec4, //< width,height,sin,cos + + [cond(Billboard), location(BillboardColorLocation)] + billboardColor: vec4 } struct VertOut { [location(0), cond(HasUV)] uv: vec2, - [location(1), cond(HasVertexColor)] color: vec4, + [location(1), cond(HasColor)] color: vec4, [builtin(position)] position: vec4 } -[entry(vert)] +[entry(vert), cond(Billboard)] +fn billboardMain(input: VertIn) -> VertOut +{ + let size = input.billboardSizeRot.xy; + let sinCos = input.billboardSizeRot.zw; + + let rotatedPosition = vec2( + input.pos.x * sinCos.y - input.pos.y * sinCos.x, + input.pos.y * sinCos.y + input.pos.x * sinCos.x + ); + rotatedPosition *= size; + + let cameraRight = vec3(viewerData.viewMatrix[0][0], viewerData.viewMatrix[1][0], viewerData.viewMatrix[2][0]); + let cameraUp = vec3(viewerData.viewMatrix[0][1], viewerData.viewMatrix[1][1], viewerData.viewMatrix[2][1]); + + let vertexPos = input.billboardCenter; + vertexPos += cameraRight * rotatedPosition.x; + vertexPos += cameraUp * rotatedPosition.y; + + let output: VertOut; + output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4(vertexPos, 1.0); + + const if (HasColor) + output.color = input.billboardColor; + + const if (HasUV) + output.uv = input.pos.xy + vec2(0.5, 0.5); + + return output; +} + +[entry(vert), cond(!Billboard)] fn main(input: VertIn) -> VertOut { let output: VertOut; output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4(input.pos, 1.0); - const if (HasVertexColor) + const if (HasColor) output.color = input.color; const if (HasUV) diff --git a/src/Nazara/Graphics/Resources/Shaders/phong_material.nzsl b/src/Nazara/Graphics/Resources/Shaders/phong_material.nzsl new file mode 100644 index 000000000..9a03855a8 --- /dev/null +++ b/src/Nazara/Graphics/Resources/Shaders/phong_material.nzsl @@ -0,0 +1,286 @@ +// Basic material options +option HasDiffuseTexture: bool = false; +option HasAlphaTexture: bool = false; +option AlphaTest: bool = false; + +// Phong material options +option HasEmissiveTexture: bool = false; +option HasHeightTexture: bool = false; +option HasNormalTexture: bool = false; +option HasSpecularTexture: bool = false; + +option MaxLightCount: u32 = u32(3); //< FIXME: Fix integral value types + +// Billboard related options +option Billboard: bool = false; +option BillboardCenterLocation: i32 = -1; +option BillboardColorLocation: i32 = -1; +option BillboardSizeRotLocation: i32 = -1; + +// Vertex declaration related options +option ColorLocation: i32 = -1; +option NormalLocation: i32 = -1; +option PosLocation: i32 = -1; +option UvLocation: i32 = -1; + +const HasNormal = (NormalLocation >= 0); +const HasVertexColor = (ColorLocation >= 0); +const HasColor = (HasVertexColor || Billboard); +const HasUV = (UvLocation >= 0); + +[layout(std140)] +struct MaterialSettings +{ + // BasicSettings + AlphaThreshold: f32, + DiffuseColor: vec4, + + // PhongSettings + AmbientColor: vec3, + SpecularColor: vec3, + Shininess: f32, +} + +[layout(std140)] +struct InstanceData +{ + worldMatrix: mat4, + invWorldMatrix: mat4 +} + +// TODO: Add enums +const DirectionalLight = 0; +const PointLight = 1; +const SpotLight = 2; + +[layout(std140)] +struct Light +{ + type: i32, + color: vec4, + factor: vec2, + parameter1: vec4, + parameter2: vec4, + parameter3: vec4, + hasShadowMapping: bool +} + +[layout(std140)] +struct LightData +{ + lights: [Light; MaxLightCount], + lightCount: u32, +} + +[layout(std140)] +struct ViewerData +{ + projectionMatrix: mat4, + invProjectionMatrix: mat4, + viewMatrix: mat4, + invViewMatrix: mat4, + viewProjMatrix: mat4, + invViewProjMatrix: mat4, + renderTargetSize: vec2, + invRenderTargetSize: vec2, + eyePosition: vec3 +} + +external +{ + [binding(0)] settings: uniform, + [binding(1)] MaterialDiffuseMap: sampler2D, + [binding(2)] MaterialAlphaMap: sampler2D, + [binding(3)] TextureOverlay: sampler2D, + [binding(4)] instanceData: uniform, + [binding(5)] viewerData: uniform, + [binding(6)] lightData: uniform, + [binding(7)] MaterialEmissiveMap: sampler2D, + [binding(8)] MaterialHeightMap: sampler2D, + [binding(9)] MaterialNormalMap: sampler2D, + [binding(10)] MaterialSpecularMap: sampler2D, +} + +// Fragment stage +struct FragIn +{ + [location(0)] worldPos: vec3, + [location(1), cond(HasUV)] uv: vec2, + [location(2), cond(HasColor)] color: vec4, + [location(3), cond(HasNormal)] normal: vec3, +} + +struct FragOut +{ + [location(0)] RenderTarget0: vec4 +} + +[entry(frag)] +fn main(input: FragIn) -> FragOut +{ + let diffuseColor = settings.DiffuseColor; + + const if (HasUV) + diffuseColor *= TextureOverlay.Sample(input.uv); + + const if (HasColor) + diffuseColor *= input.color; + + const if (HasDiffuseTexture) + diffuseColor *= MaterialDiffuseMap.Sample(input.uv); + + const if (HasAlphaTexture) + diffuseColor.w *= MaterialAlphaMap.Sample(input.uv).x; + + const if (AlphaTest) + { + if (diffuseColor.w < settings.AlphaThreshold) + discard; + } + + const if (HasNormal) + { + let lightAmbient = vec3(0.0, 0.0, 0.0); + let lightDiffuse = vec3(0.0, 0.0, 0.0); + let lightSpecular = vec3(0.0, 0.0, 0.0); + + let eyeVec = normalize(viewerData.eyePosition - input.worldPos); + + for i in 0 -> lightData.lightCount + { + let light = lightData.lights[i]; + + let lightAmbientFactor = light.factor.x; + let lightDiffuseFactor = light.factor.y; + + // TODO: Add switch instruction + if (light.type == DirectionalLight) + { + let lightDir = -(light.parameter1.xyz); //< FIXME + + lightAmbient += light.color.rgb * lightAmbientFactor * settings.AmbientColor; + + let lambert = max(dot(input.normal, lightDir), 0.0); + + lightDiffuse += lambert * light.color.rgb * lightDiffuseFactor; + + let reflection = reflect(-lightDir, input.normal); + let specFactor = max(dot(reflection, eyeVec), 0.0); + specFactor = pow(specFactor, settings.Shininess); + + lightSpecular += specFactor * light.color.rgb; + } + else if (light.type == PointLight) + { + + } + else if (light.type == SpotLight) + { + + } + } + + lightSpecular *= settings.SpecularColor; + + const if (HasSpecularTexture) + lightSpecular *= MaterialSpecularMap.Sample(input.uv).rgb; + + let lightColor = lightAmbient + lightDiffuse + lightSpecular; + + let output: FragOut; + output.RenderTarget0 = vec4(lightColor, 1.0) * diffuseColor; + return output; + } + else + { + let output: FragOut; + output.RenderTarget0 = diffuseColor.w; + return output; + } +} + +// Vertex stage +struct VertIn +{ + [location(PosLocation)] + pos: vec3, + + [cond(HasVertexColor), location(ColorLocation)] + color: vec4, + + [cond(HasUV), location(UvLocation)] + uv: vec2, + + [cond(HasNormal), location(NormalLocation)] + normal: vec3, + + [cond(Billboard), location(BillboardCenterLocation)] + billboardCenter: vec3, + + [cond(Billboard), location(BillboardSizeRotLocation)] + billboardSizeRot: vec4, //< width,height,sin,cos + + [cond(Billboard), location(BillboardColorLocation)] + billboardColor: vec4 +} + +struct VertOut +{ + [location(0)] worldPos: vec3, + [location(1), cond(HasUV)] uv: vec2, + [location(2), cond(HasColor)] color: vec4, + [location(3), cond(HasNormal)] normal: vec3, + [builtin(position)] position: vec4, +} + +[entry(vert), cond(Billboard)] +fn billboardMain(input: VertIn) -> VertOut +{ + let size = input.billboardSizeRot.xy; + let sinCos = input.billboardSizeRot.zw; + + let rotatedPosition = vec2( + input.pos.x * sinCos.y - input.pos.y * sinCos.x, + input.pos.y * sinCos.y + input.pos.x * sinCos.x + ); + rotatedPosition *= size; + + let cameraRight = vec3(viewerData.viewMatrix[0][0], viewerData.viewMatrix[1][0], viewerData.viewMatrix[2][0]); + let cameraUp = vec3(viewerData.viewMatrix[0][1], viewerData.viewMatrix[1][1], viewerData.viewMatrix[2][1]); + + let vertexPos = input.billboardCenter; + vertexPos += cameraRight * rotatedPosition.x; + vertexPos += cameraUp * rotatedPosition.y; + + let output: VertOut; + output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4(vertexPos, 1.0); + + const if (HasColor) + output.color = input.billboardColor; + + const if (HasUV) + output.uv = input.pos.xy + vec2(0.5, 0.5); + + return output; +} + +[entry(vert), cond(!Billboard)] +fn main(input: VertIn) -> VertOut +{ + let worldPosition = instanceData.worldMatrix * vec4(input.pos, 1.0); + + let output: VertOut; + output.worldPos = worldPosition.xyz; + output.position = viewerData.viewProjMatrix * worldPosition; + + const if (HasColor) + output.color = input.color; + + const if (HasNormal) + output.normal = input.normal; + + const if (HasUV) + output.uv = input.uv; + + return output; +} diff --git a/src/Nazara/Graphics/SpriteChainRenderer.cpp b/src/Nazara/Graphics/SpriteChainRenderer.cpp index 954ae062e..c3e7f3903 100644 --- a/src/Nazara/Graphics/SpriteChainRenderer.cpp +++ b/src/Nazara/Graphics/SpriteChainRenderer.cpp @@ -53,7 +53,7 @@ namespace Nz return std::make_unique(); } - void SpriteChainRenderer::Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, const Pointer* elements, std::size_t elementCount) + void SpriteChainRenderer::Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, const RenderStates& renderStates, const Pointer* elements, std::size_t elementCount) { Graphics* graphics = Graphics::Instance(); @@ -210,6 +210,16 @@ namespace Nz }; } + if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::LightDataUbo); bindingIndex != MaterialSettings::InvalidIndex) + { + auto& bindingEntry = m_bindingCache.emplace_back(); + bindingEntry.bindingIndex = bindingIndex; + bindingEntry.content = ShaderBinding::UniformBufferBinding{ + renderStates.lightData.get(), + 0, renderStates.lightData->GetSize() + }; + } + if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::ViewerDataUbo); bindingIndex != MaterialSettings::InvalidIndex) { const auto& viewerBuffer = viewerInstance.GetViewerBuffer(); diff --git a/src/Nazara/Graphics/SubmeshRenderer.cpp b/src/Nazara/Graphics/SubmeshRenderer.cpp index 8fbb5ef9a..5e16ddcaa 100644 --- a/src/Nazara/Graphics/SubmeshRenderer.cpp +++ b/src/Nazara/Graphics/SubmeshRenderer.cpp @@ -12,16 +12,12 @@ namespace Nz { - SubmeshRenderer::SubmeshRenderer() - { - } - std::unique_ptr SubmeshRenderer::InstanciateData() { return std::make_unique(); } - void SubmeshRenderer::Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& /*currentFrame*/, const Pointer* elements, std::size_t elementCount) + void SubmeshRenderer::Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& /*currentFrame*/, const RenderStates& renderStates, const Pointer* elements, std::size_t elementCount) { Graphics* graphics = Graphics::Instance(); @@ -118,6 +114,16 @@ namespace Nz }; } + if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::LightDataUbo); bindingIndex != MaterialSettings::InvalidIndex) + { + auto& bindingEntry = m_bindingCache.emplace_back(); + bindingEntry.bindingIndex = bindingIndex; + bindingEntry.content = ShaderBinding::UniformBufferBinding{ + renderStates.lightData.get(), + 0, renderStates.lightData->GetSize() + }; + } + if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::ViewerDataUbo); bindingIndex != MaterialSettings::InvalidIndex) { const auto& viewerBuffer = viewerInstance.GetViewerBuffer(); diff --git a/src/Nazara/Graphics/Systems/RenderSystem.cpp b/src/Nazara/Graphics/Systems/RenderSystem.cpp index 3756f4cec..ecbaee8cf 100644 --- a/src/Nazara/Graphics/Systems/RenderSystem.cpp +++ b/src/Nazara/Graphics/Systems/RenderSystem.cpp @@ -156,8 +156,11 @@ namespace Nz const NodeComponent& entityNode = registry.get(entity); CameraComponent& entityCamera = registry.get(entity); + Vector3f cameraPosition = entityNode.GetPosition(CoordSys::Global); + ViewerInstance& viewerInstance = entityCamera.GetViewerInstance(); - viewerInstance.UpdateViewMatrix(Nz::Matrix4f::ViewMatrix(entityNode.GetPosition(CoordSys::Global), entityNode.GetRotation(CoordSys::Global))); + viewerInstance.UpdateEyePosition(cameraPosition); + viewerInstance.UpdateViewMatrix(Nz::Matrix4f::ViewMatrix(cameraPosition, entityNode.GetRotation(CoordSys::Global))); m_pipeline->InvalidateViewer(&entityCamera); } diff --git a/src/Nazara/Graphics/ViewerInstance.cpp b/src/Nazara/Graphics/ViewerInstance.cpp index e7fb3d114..8f7f28840 100644 --- a/src/Nazara/Graphics/ViewerInstance.cpp +++ b/src/Nazara/Graphics/ViewerInstance.cpp @@ -20,7 +20,8 @@ namespace Nz m_projectionMatrix(Matrix4f::Identity()), m_viewProjMatrix(Matrix4f::Identity()), m_viewMatrix(Matrix4f::Identity()), - m_targetSize(Vector2f(0.f, 0.f)), + m_targetSize(Vector2f::Zero()), + m_eyePosition(Vector3f::Zero()), m_dataInvalided(true) { PredefinedViewerData viewerUboOffsets = PredefinedViewerData::GetOffsets(); @@ -37,7 +38,7 @@ namespace Nz PredefinedViewerData viewerDataOffsets = PredefinedViewerData::GetOffsets(); auto& allocation = uploadPool.Allocate(viewerDataOffsets.totalSize); - AccessByOffset(allocation.mappedPtr, viewerDataOffsets.eyePositionOffset) = m_viewMatrix.GetTranslation(); + AccessByOffset(allocation.mappedPtr, viewerDataOffsets.eyePositionOffset) = m_eyePosition; AccessByOffset(allocation.mappedPtr, viewerDataOffsets.invTargetSizeOffset) = 1.f / m_targetSize; AccessByOffset(allocation.mappedPtr, viewerDataOffsets.targetSizeOffset) = m_targetSize; diff --git a/src/Nazara/Shader/Ast/SanitizeVisitor.cpp b/src/Nazara/Shader/Ast/SanitizeVisitor.cpp index 31d8b9ff5..5e1449f11 100644 --- a/src/Nazara/Shader/Ast/SanitizeVisitor.cpp +++ b/src/Nazara/Shader/Ast/SanitizeVisitor.cpp @@ -74,7 +74,9 @@ namespace Nz::ShaderAst RegisterIntrinsic("length", IntrinsicType::Length); RegisterIntrinsic("max", IntrinsicType::Max); RegisterIntrinsic("min", IntrinsicType::Min); + RegisterIntrinsic("normalize", IntrinsicType::Normalize); RegisterIntrinsic("pow", IntrinsicType::Pow); + RegisterIntrinsic("reflect", IntrinsicType::Reflect); // Collect function name and their types if (statement.GetType() == NodeType::MultiStatement) @@ -152,7 +154,7 @@ namespace Nz::ShaderAst ExpressionPtr SanitizeVisitor::Clone(AccessIdentifierExpression& node) { if (node.identifiers.empty()) - throw AstError{ "accessIdentifierExpression must have at least one identifier" }; + throw AstError{ "AccessIdentifierExpression must have at least one identifier" }; ExpressionPtr indexedExpr = CloneExpression(MandatoryExpr(node.expr)); for (const std::string& identifier : node.identifiers) @@ -202,7 +204,7 @@ namespace Nz::ShaderAst else accessIdentifierPtr = static_cast(indexedExpr.get()); - accessIdentifierPtr->identifiers.push_back(s->members[fieldIndex].name); + accessIdentifierPtr->identifiers.push_back(fieldPtr->name); accessIdentifierPtr->cachedExpressionType = ResolveType(fieldPtr->type); } else @@ -602,6 +604,9 @@ namespace Nz::ShaderAst clone->constIndex = RegisterConstant(clone->name, value); + if (m_context->options.removeConstDeclaration) + return ShaderBuilder::NoOp(); + return clone; } @@ -1775,6 +1780,7 @@ namespace Nz::ShaderAst case IntrinsicType::Max: case IntrinsicType::Min: case IntrinsicType::Pow: + case IntrinsicType::Reflect: { if (node.parameters.size() != 2) throw AstError { "Expected two parameters" }; @@ -1803,6 +1809,7 @@ namespace Nz::ShaderAst } case IntrinsicType::Length: + case IntrinsicType::Normalize: { if (node.parameters.size() != 1) throw AstError{ "Expected only one parameters" }; @@ -1850,12 +1857,23 @@ namespace Nz::ShaderAst { const ExpressionType& type = GetExpressionType(*node.parameters.front()); if (!IsVectorType(type)) - throw AstError{ "DotProduct expects vector types" }; + throw AstError{ "DotProduct expects vector types" }; //< FIXME node.cachedExpressionType = std::get(type).type; break; } + case IntrinsicType::Normalize: + case IntrinsicType::Reflect: + { + const ExpressionType& type = GetExpressionType(*node.parameters.front()); + if (!IsVectorType(type)) + throw AstError{ "DotProduct expects vector types" }; //< FIXME + + node.cachedExpressionType = type; + break; + } + case IntrinsicType::Max: case IntrinsicType::Min: { @@ -1998,17 +2016,18 @@ namespace Nz::ShaderAst case BinaryType::CompGt: case BinaryType::CompLe: case BinaryType::CompLt: - { if (leftType == PrimitiveType::Boolean) throw AstError{ "this operation is not supported for booleans" }; + [[fallthrough]]; + case BinaryType::CompEq: + case BinaryType::CompNe: + { TypeMustMatch(leftExpr, rightExpr); return PrimitiveType::Boolean; } case BinaryType::Add: - case BinaryType::CompEq: - case BinaryType::CompNe: case BinaryType::Subtract: TypeMustMatch(leftExpr, rightExpr); return leftExprType; diff --git a/src/Nazara/Shader/GlslWriter.cpp b/src/Nazara/Shader/GlslWriter.cpp index 766a79ff4..b7207e80d 100644 --- a/src/Nazara/Shader/GlslWriter.cpp +++ b/src/Nazara/Shader/GlslWriter.cpp @@ -209,6 +209,7 @@ namespace Nz options.makeVariableNameUnique = true; options.reduceLoopsToWhile = true; options.removeCompoundAssignments = false; + options.removeConstDeclaration = true; options.removeOptionDeclaration = true; options.removeScalarSwizzling = true; options.reservedIdentifiers = { @@ -489,7 +490,10 @@ namespace Nz bool first = true; for (const ShaderAst::StatementPtr& statement : statements) { - if (!first && statement->GetType() != ShaderAst::NodeType::NoOpStatement) + if (statement->GetType() == ShaderAst::NodeType::NoOpStatement) + continue; + + if (!first) AppendLine(); statement->Visit(*this); @@ -863,10 +867,18 @@ namespace Nz Append("min"); break; + case ShaderAst::IntrinsicType::Normalize: + Append("normalize"); + break; + case ShaderAst::IntrinsicType::Pow: Append("pow"); break; + case ShaderAst::IntrinsicType::Reflect: + Append("reflect"); + break; + case ShaderAst::IntrinsicType::SampleTexture: Append("texture"); break; @@ -1118,6 +1130,9 @@ namespace Nz bool first = true; for (const auto& member : node.description.members) { + if (member.cond.HasValue() && !member.cond.GetResultingValue()) + continue; + if (!first) AppendLine(); diff --git a/src/Nazara/Shader/LangWriter.cpp b/src/Nazara/Shader/LangWriter.cpp index e6a486637..65cb60bd5 100644 --- a/src/Nazara/Shader/LangWriter.cpp +++ b/src/Nazara/Shader/LangWriter.cpp @@ -945,10 +945,18 @@ namespace Nz Append("min"); break; + case ShaderAst::IntrinsicType::Normalize: + Append("normalize"); + break; + case ShaderAst::IntrinsicType::Pow: Append("pow"); break; + case ShaderAst::IntrinsicType::Reflect: + Append("reflect"); + break; + case ShaderAst::IntrinsicType::SampleTexture: assert(!node.parameters.empty()); Visit(node.parameters.front(), true); diff --git a/src/Nazara/Shader/SpirvAstVisitor.cpp b/src/Nazara/Shader/SpirvAstVisitor.cpp index bc7fdaa95..3a187f1fb 100644 --- a/src/Nazara/Shader/SpirvAstVisitor.cpp +++ b/src/Nazara/Shader/SpirvAstVisitor.cpp @@ -801,6 +801,25 @@ namespace Nz break; } + case ShaderAst::IntrinsicType::Normalize: + { + UInt32 glslInstructionSet = m_writer.GetExtendedInstructionSet("GLSL.std.450"); + + const ShaderAst::ExpressionType& vecExprType = GetExpressionType(*node.parameters[0]); + assert(IsVectorType(vecExprType)); + + const ShaderAst::VectorType& vecType = std::get(vecExprType); + UInt32 typeId = m_writer.GetTypeId(vecType); + + UInt32 vec = EvaluateExpression(node.parameters[0]); + + UInt32 resultId = m_writer.AllocateResultId(); + + m_currentBlock->Append(SpirvOp::OpExtInst, typeId, resultId, glslInstructionSet, GLSLstd450Normalize, vec); + PushResultId(resultId); + break; + } + case ShaderAst::IntrinsicType::Pow: { UInt32 glslInstructionSet = m_writer.GetExtendedInstructionSet("GLSL.std.450"); @@ -818,6 +837,23 @@ namespace Nz break; } + case ShaderAst::IntrinsicType::Reflect: + { + UInt32 glslInstructionSet = m_writer.GetExtendedInstructionSet("GLSL.std.450"); + + const ShaderAst::ExpressionType& parameterType = GetExpressionType(*node.parameters[0]); + assert(IsVectorType(parameterType)); + UInt32 typeId = m_writer.GetTypeId(parameterType); + + UInt32 firstParam = EvaluateExpression(node.parameters[0]); + UInt32 secondParam = EvaluateExpression(node.parameters[1]); + UInt32 resultId = m_writer.AllocateResultId(); + + m_currentBlock->Append(SpirvOp::OpExtInst, typeId, resultId, glslInstructionSet, GLSLstd450Reflect, firstParam, secondParam); + PushResultId(resultId); + break; + } + case ShaderAst::IntrinsicType::SampleTexture: { UInt32 typeId = m_writer.GetTypeId(ShaderAst::VectorType{4, ShaderAst::PrimitiveType::Float32}); diff --git a/src/Nazara/Shader/SpirvWriter.cpp b/src/Nazara/Shader/SpirvWriter.cpp index e16ecfa88..13a314b1f 100644 --- a/src/Nazara/Shader/SpirvWriter.cpp +++ b/src/Nazara/Shader/SpirvWriter.cpp @@ -356,7 +356,9 @@ namespace Nz case ShaderAst::IntrinsicType::Length: case ShaderAst::IntrinsicType::Max: case ShaderAst::IntrinsicType::Min: + case ShaderAst::IntrinsicType::Normalize: case ShaderAst::IntrinsicType::Pow: + case ShaderAst::IntrinsicType::Reflect: extInsts.emplace("GLSL.std.450"); break; From 7976ea27b93a9a70c371944a5c32e1e3df5f7643 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 18 Jan 2022 06:01:15 +0100 Subject: [PATCH 02/14] Add initial support for normal mapping and other light types --- examples/GraphicsTest/main.cpp | 17 ++- src/Nazara/Graphics/ForwardFramePipeline.cpp | 21 +++- src/Nazara/Graphics/PhongLightingMaterial.cpp | 29 ++++- .../Resources/Shaders/phong_material.nzsl | 102 ++++++++++++++---- 4 files changed, 144 insertions(+), 25 deletions(-) diff --git a/examples/GraphicsTest/main.cpp b/examples/GraphicsTest/main.cpp index 00c76499e..7d37b372e 100644 --- a/examples/GraphicsTest/main.cpp +++ b/examples/GraphicsTest/main.cpp @@ -30,7 +30,7 @@ int main() meshParams.center = true; meshParams.storage = Nz::DataStorage::Software; meshParams.matrix = Nz::Matrix4f::Rotate(Nz::EulerAnglesf(0.f, -90.f, 0.f)) * Nz::Matrix4f::Scale(Nz::Vector3f(0.002f)); - meshParams.vertexDeclaration = Nz::VertexDeclaration::Get(Nz::VertexLayout::XYZ_Normal_UV); + meshParams.vertexDeclaration = Nz::VertexDeclaration::Get(Nz::VertexLayout::XYZ_Normal_UV_Tangent); std::shared_ptr device = Nz::Graphics::Instance()->GetRenderDevice(); @@ -70,10 +70,13 @@ int main() material->AddPass("ForwardPass", materialPass); + std::shared_ptr normalMap = Nz::Texture::LoadFromFile(resourceDir / "Spaceship/Texture/normal.png", texParams); + Nz::PhongLightingMaterial phongMat(*materialPass); phongMat.EnableAlphaTest(false); phongMat.SetAlphaMap(Nz::Texture::LoadFromFile(resourceDir / "alphatile.png", texParams)); phongMat.SetDiffuseMap(Nz::Texture::LoadFromFile(resourceDir / "Spaceship/Texture/diffuse.png", texParams)); + phongMat.SetNormalMap(Nz::Texture::LoadFromFile(resourceDir / "Spaceship/Texture/normal.png", texParams)); Nz::Model model(std::move(gfxMesh), spaceshipMesh->GetAABB()); for (std::size_t i = 0; i < model.GetSubMeshCount(); ++i) @@ -127,6 +130,18 @@ int main() case Nz::WindowEventType::KeyPressed: if (event.key.virtualKey == Nz::Keyboard::VKey::A) phongMat.EnableAlphaTest(!phongMat.IsAlphaTestEnabled()); + else if (event.key.virtualKey == Nz::Keyboard::VKey::N) + { + if (phongMat.GetNormalMap()) + phongMat.SetNormalMap({}); + else + phongMat.SetNormalMap(normalMap); + } + else if (event.key.virtualKey == Nz::Keyboard::VKey::Space) + { + modelInstance->UpdateWorldMatrix(Nz::Matrix4f::Translate(viewerPos)); + framePipeline.InvalidateWorldInstance(modelInstance.get()); + } break; diff --git a/src/Nazara/Graphics/ForwardFramePipeline.cpp b/src/Nazara/Graphics/ForwardFramePipeline.cpp index ad0eff987..9bac97537 100644 --- a/src/Nazara/Graphics/ForwardFramePipeline.cpp +++ b/src/Nazara/Graphics/ForwardFramePipeline.cpp @@ -9,12 +9,13 @@ #include #include #include -#include #include +#include #include #include #include #include +#include #include #include #include @@ -44,13 +45,29 @@ namespace Nz throw std::runtime_error("failed to create light data buffer"); std::vector staticLightData(lightOffset.totalSize); - AccessByOffset(staticLightData.data(), lightOffset.lightCountOffset) = 1; + /*AccessByOffset(staticLightData.data(), lightOffset.lightCountOffset) = 1; AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.type) = 0; AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.color) = Vector4f(1.f, 1.f, 1.f, 1.f); AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.factor) = Vector2f(0.2f, 1.f); AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.parameter1) = Vector4f(0.f, 0.f, -1.f, 1.f); + AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.shadowMappingFlag) = 0;*/ + + AccessByOffset(staticLightData.data(), lightOffset.lightCountOffset) = 1; + AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.type) = 1; + AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.color) = Vector4f(1.f, 1.f, 1.f, 1.f); + AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.factor) = Vector2f(0.2f, 1.f); + AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.parameter1) = Vector4f(0.f, 0.f, 0.f, 1.f / 3.f); AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.shadowMappingFlag) = 0; + /*AccessByOffset(staticLightData.data(), lightOffset.lightCountOffset) = 1; + AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.type) = 2; + AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.color) = Vector4f(1.f, 1.f, 1.f, 1.f); + AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.factor) = Vector2f(0.2f, 1.f); + AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.parameter1) = Vector4f(0.f, 0.f, 0.f, 1.f / 3.f); + AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.parameter2) = Vector4f(0.f, 0.f, -1.f, 0.f); + AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.parameter3) = Vector4f(DegreeAnglef(15.f).GetCos(), DegreeAnglef(20.f).GetCos(), 0.f, 0.f); + AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.shadowMappingFlag) = 0;*/ + if (!m_lightDataBuffer->Fill(staticLightData.data(), 0, staticLightData.size())) throw std::runtime_error("failed to fill light data buffer"); } diff --git a/src/Nazara/Graphics/PhongLightingMaterial.cpp b/src/Nazara/Graphics/PhongLightingMaterial.cpp index 663184e72..0c6cb5a61 100644 --- a/src/Nazara/Graphics/PhongLightingMaterial.cpp +++ b/src/Nazara/Graphics/PhongLightingMaterial.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include namespace Nz @@ -259,6 +260,7 @@ namespace Nz std::size_t positionLocationIndex = FetchLocationOption("PosLocation"); std::size_t colorLocationIndex = FetchLocationOption("ColorLocation"); std::size_t normalLocationIndex = FetchLocationOption("NormalLocation"); + std::size_t tangentLocationIndex = FetchLocationOption("TangentLocation"); std::size_t uvLocationIndex = FetchLocationOption("UvLocation"); uberShader->UpdateConfigCallback([=](UberShader::Config& config, const std::vector& vertexBuffers) @@ -292,6 +294,12 @@ namespace Nz break; + case VertexComponent::Tangent: + if (tangentLocationIndex != InvalidOption) + config.optionValues[tangentLocationIndex] = static_cast(locationIndex); + + break; + case VertexComponent::TexCoord: if (uvLocationIndex != InvalidOption) config.optionValues[uvLocationIndex] = static_cast(locationIndex); @@ -339,7 +347,26 @@ namespace Nz std::vector> PhongLightingMaterial::BuildShaders() { - ShaderAst::StatementPtr shaderAst = ShaderLang::Parse(std::string_view(reinterpret_cast(r_shader), sizeof(r_shader))); + ShaderAst::StatementPtr shaderAst; + +#ifdef NAZARA_DEBUG + std::filesystem::path shaderPath = "../../src/Nazara/Graphics/Resources/Shaders/phong_material.nzsl"; + if (std::filesystem::exists(shaderPath)) + { + try + { + shaderAst = ShaderLang::ParseFromFile(shaderPath); + } + catch (const std::exception& e) + { + NazaraError(std::string("failed to load shader from engine folder: ") + e.what()); + } + } +#endif + + if (!shaderAst) + shaderAst = ShaderLang::Parse(std::string_view(reinterpret_cast(r_shader), sizeof(r_shader))); + auto shader = std::make_shared(ShaderStageType::Fragment | ShaderStageType::Vertex, shaderAst); return { std::move(shader) }; diff --git a/src/Nazara/Graphics/Resources/Shaders/phong_material.nzsl b/src/Nazara/Graphics/Resources/Shaders/phong_material.nzsl index 9a03855a8..6328ec0f9 100644 --- a/src/Nazara/Graphics/Resources/Shaders/phong_material.nzsl +++ b/src/Nazara/Graphics/Resources/Shaders/phong_material.nzsl @@ -21,12 +21,15 @@ option BillboardSizeRotLocation: i32 = -1; option ColorLocation: i32 = -1; option NormalLocation: i32 = -1; option PosLocation: i32 = -1; +option TangentLocation: i32 = -1; option UvLocation: i32 = -1; const HasNormal = (NormalLocation >= 0); const HasVertexColor = (ColorLocation >= 0); const HasColor = (HasVertexColor || Billboard); +const HasTangent = (TangentLocation >= 0); const HasUV = (UvLocation >= 0); +const HasNormalMapping = HasNormalTexture && HasNormal && HasTangent; [layout(std140)] struct MaterialSettings @@ -101,22 +104,24 @@ external [binding(10)] MaterialSpecularMap: sampler2D, } -// Fragment stage -struct FragIn +struct VertToFrag { [location(0)] worldPos: vec3, [location(1), cond(HasUV)] uv: vec2, [location(2), cond(HasColor)] color: vec4, [location(3), cond(HasNormal)] normal: vec3, + [location(4), cond(HasNormalMapping)] tbnMatrix: mat3, + [builtin(position)] position: vec4, } +// Fragment stage struct FragOut { [location(0)] RenderTarget0: vec4 } [entry(frag)] -fn main(input: FragIn) -> FragOut +fn main(input: VertToFrag) -> FragOut { let diffuseColor = settings.DiffuseColor; @@ -146,6 +151,12 @@ fn main(input: FragIn) -> FragOut let eyeVec = normalize(viewerData.eyePosition - input.worldPos); + let normal: vec3; + const if (HasNormalMapping) + normal = normalize(input.tbnMatrix * (MaterialNormalMap.Sample(input.uv).xyz * 2.0 - vec3(1.0, 1.0, 1.0))); + else + normal = normalize(input.normal); + for i in 0 -> lightData.lightCount { let light = lightData.lights[i]; @@ -156,15 +167,15 @@ fn main(input: FragIn) -> FragOut // TODO: Add switch instruction if (light.type == DirectionalLight) { - let lightDir = -(light.parameter1.xyz); //< FIXME + let lightDir = light.parameter1.xyz; lightAmbient += light.color.rgb * lightAmbientFactor * settings.AmbientColor; - let lambert = max(dot(input.normal, lightDir), 0.0); + let lambert = max(dot(normal, -lightDir), 0.0); lightDiffuse += lambert * light.color.rgb * lightDiffuseFactor; - let reflection = reflect(-lightDir, input.normal); + let reflection = reflect(lightDir, normal); let specFactor = max(dot(reflection, eyeVec), 0.0); specFactor = pow(specFactor, settings.Shininess); @@ -172,11 +183,56 @@ fn main(input: FragIn) -> FragOut } else if (light.type == PointLight) { - + let lightPos = light.parameter1.xyz; + let lightInvRadius = light.parameter1.w; + + let lightToPos = input.worldPos - lightPos; + let dist = length(lightToPos); + let lightToPosNorm = lightToPos / max(dist, 0.0001); + + let attenuationFactor = max(1.0 - dist * lightInvRadius, 0.0); + + lightAmbient += attenuationFactor * light.color.rgb * lightAmbientFactor * settings.AmbientColor; + + let lambert = max(dot(normal, -lightToPosNorm), 0.0); + + lightDiffuse += attenuationFactor * lambert * light.color.rgb * lightDiffuseFactor; + + let reflection = reflect(lightToPosNorm, normal); + let specFactor = max(dot(reflection, eyeVec), 0.0); + specFactor = pow(specFactor, settings.Shininess); + + lightSpecular += attenuationFactor * specFactor * light.color.rgb; } else if (light.type == SpotLight) { - + let lightPos = light.parameter1.xyz; + let lightDir = light.parameter2.xyz; + let lightInvRadius = light.parameter1.w; + let lightInnerAngle = light.parameter3.x; + let lightOuterAngle = light.parameter3.y; + + let lightToPos = input.worldPos - lightPos; + let dist = length(lightToPos); + let lightToPosNorm = lightToPos / max(dist, 0.0001); + + let curAngle = dot(lightDir, lightToPosNorm); + let innerMinusOuterAngle = lightInnerAngle - lightOuterAngle; + + let attenuationFactor = max(1.0 - dist * lightInvRadius, 0.0); + attenuationFactor *= max((curAngle - lightOuterAngle) / innerMinusOuterAngle, 0.0); + + lightAmbient += attenuationFactor * light.color.rgb * lightAmbientFactor * settings.AmbientColor; + + let lambert = max(dot(normal, -lightToPosNorm), 0.0); + + lightDiffuse += attenuationFactor * lambert * light.color.rgb * lightDiffuseFactor; + + let reflection = reflect(lightToPosNorm, normal); + let specFactor = max(dot(reflection, eyeVec), 0.0); + specFactor = pow(specFactor, settings.Shininess); + + lightSpecular += attenuationFactor * specFactor * light.color.rgb; } } @@ -214,6 +270,9 @@ struct VertIn [cond(HasNormal), location(NormalLocation)] normal: vec3, + [cond(HasTangent), location(TangentLocation)] + tangent: vec3, + [cond(Billboard), location(BillboardCenterLocation)] billboardCenter: vec3, @@ -224,15 +283,6 @@ struct VertIn billboardColor: vec4 } -struct VertOut -{ - [location(0)] worldPos: vec3, - [location(1), cond(HasUV)] uv: vec2, - [location(2), cond(HasColor)] color: vec4, - [location(3), cond(HasNormal)] normal: vec3, - [builtin(position)] position: vec4, -} - [entry(vert), cond(Billboard)] fn billboardMain(input: VertIn) -> VertOut { @@ -252,7 +302,7 @@ fn billboardMain(input: VertIn) -> VertOut vertexPos += cameraRight * rotatedPosition.x; vertexPos += cameraUp * rotatedPosition.y; - let output: VertOut; + let output: VertToFrag; output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4(vertexPos, 1.0); const if (HasColor) @@ -265,22 +315,32 @@ fn billboardMain(input: VertIn) -> VertOut } [entry(vert), cond(!Billboard)] -fn main(input: VertIn) -> VertOut +fn main(input: VertIn) -> VertToFrag { let worldPosition = instanceData.worldMatrix * vec4(input.pos, 1.0); - let output: VertOut; + let output: VertToFrag; output.worldPos = worldPosition.xyz; output.position = viewerData.viewProjMatrix * worldPosition; + let rotationMatrix = mat3(instanceData.worldMatrix); + const if (HasColor) output.color = input.color; const if (HasNormal) - output.normal = input.normal; + output.normal = rotationMatrix * input.normal; const if (HasUV) output.uv = input.uv; + const if (HasNormalMapping) + { + let binormal = cross(input.normal, input.tangent); + output.tbnMatrix[0] = normalize(rotationMatrix * input.tangent); + output.tbnMatrix[1] = normalize(rotationMatrix * binormal); + output.tbnMatrix[2] = normalize(rotationMatrix * input.normal); + } + return output; } From b442af513ce4a81cc49ac17f96aa5a71a7eea327 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Fri, 21 Jan 2022 21:33:43 +0100 Subject: [PATCH 03/14] Fix compilation --- examples/DeferredShading/main.cpp | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/examples/DeferredShading/main.cpp b/examples/DeferredShading/main.cpp index 86a74fcc1..7534b60e9 100644 --- a/examples/DeferredShading/main.cpp +++ b/examples/DeferredShading/main.cpp @@ -131,7 +131,11 @@ int main() std::shared_ptr cubeMeshGfx = std::make_shared(*cubeMesh); Nz::RenderPipelineLayoutInfo skyboxPipelineLayoutInfo; - Nz::Graphics::FillViewerPipelineLayout(skyboxPipelineLayoutInfo, 0); + skyboxPipelineLayoutInfo.bindings.push_back({ + 0, 0, + Nz::ShaderBindingType::UniformBuffer, + Nz::ShaderStageType_All + }); auto& textureBinding = skyboxPipelineLayoutInfo.bindings.emplace_back(); textureBinding.setIndex = 0; @@ -260,7 +264,11 @@ int main() Nz::RenderPipelineLayoutInfo lightingPipelineLayoutInfo; - Nz::Graphics::FillViewerPipelineLayout(lightingPipelineLayoutInfo, 0); + lightingPipelineLayoutInfo.bindings.push_back({ + 0, 0, + Nz::ShaderBindingType::UniformBuffer, + Nz::ShaderStageType_All + }); for (unsigned int i = 0; i < 3; ++i) { @@ -356,7 +364,11 @@ int main() // Bloom data Nz::RenderPipelineLayoutInfo fullscreenPipelineLayoutInfoViewer; - Nz::Graphics::FillViewerPipelineLayout(fullscreenPipelineLayoutInfoViewer, 0); + fullscreenPipelineLayoutInfoViewer.bindings.push_back({ + 0, 0, + Nz::ShaderBindingType::UniformBuffer, + Nz::ShaderStageType_All + }); fullscreenPipelineLayoutInfoViewer.bindings.push_back({ 0, 1, @@ -443,7 +455,11 @@ int main() std::shared_ptr bloomBlitBinding; Nz::RenderPipelineLayoutInfo bloomBlendPipelineLayoutInfo; - Nz::Graphics::FillViewerPipelineLayout(bloomBlendPipelineLayoutInfo, 0); + bloomBlendPipelineLayoutInfo.bindings.push_back({ + 0, 0, + Nz::ShaderBindingType::UniformBuffer, + Nz::ShaderStageType_All + }); /*bloomBlendPipelineLayoutInfo.bindings.push_back({ 0, 1, @@ -860,7 +876,7 @@ int main() for (const auto& element : elements) elementPointers.emplace_back(element.get()); - submeshRenderer.Prepare(viewerInstance, *submeshRendererData, *currentFrame, elementPointers.data(), elementPointers.size()); + submeshRenderer.Prepare(viewerInstance, *submeshRendererData, *currentFrame, {}, elementPointers.data(), elementPointers.size()); submeshRenderer.Render(viewerInstance, *submeshRendererData, builder, elementPointers.data(), elementPointers.size()); }); @@ -924,7 +940,7 @@ int main() for (const auto& element : elements) elementPointers.emplace_back(element.get()); - spritechainRenderer.Prepare(viewerInstance, *spriteRendererData, *currentFrame, elementPointers.data(), elementPointers.size()); + spritechainRenderer.Prepare(viewerInstance, *spriteRendererData, *currentFrame, {}, elementPointers.data(), elementPointers.size()); spritechainRenderer.Render(viewerInstance, *spriteRendererData, builder, elementPointers.data(), elementPointers.size()); }); forwardPass.SetExecutionCallback([&] @@ -952,7 +968,7 @@ int main() for (const auto& element : elements) elementPointers.emplace_back(element.get()); - spritechainRenderer.Prepare(viewerInstance, *spriteRendererData, *currentFrame, elementPointers.data(), elementPointers.size()); + spritechainRenderer.Prepare(viewerInstance, *spriteRendererData, *currentFrame, {}, elementPointers.data(), elementPointers.size()); spritechainRenderer.Render(viewerInstance, *spriteRendererData, builder, elementPointers.data(), elementPointers.size()); }); From 89e9e41357ecf73419fa382fe94b8c90d7d3f15e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sun, 23 Jan 2022 13:27:39 +0100 Subject: [PATCH 04/14] Core/SparsePtr: Use template type for +/- and +=/-= --- include/Nazara/Core/SparsePtr.hpp | 16 ++++---- include/Nazara/Core/SparsePtr.inl | 58 ++++++++++------------------- tests/Engine/Core/SparsePtrTest.cpp | 6 +-- 3 files changed, 29 insertions(+), 51 deletions(-) diff --git a/include/Nazara/Core/SparsePtr.hpp b/include/Nazara/Core/SparsePtr.hpp index 737a2f1fe..2977cd9bc 100644 --- a/include/Nazara/Core/SparsePtr.hpp +++ b/include/Nazara/Core/SparsePtr.hpp @@ -19,8 +19,8 @@ namespace Nz class SparsePtr { public: - using BytePtr = typename std::conditional::value, const UInt8*, UInt8*>::type; - using VoidPtr = typename std::conditional::value, const void*, void*>::type; + using BytePtr = std::conditional_t::value, const UInt8*, UInt8*>; + using VoidPtr = std::conditional_t::value, const void*, void*>; SparsePtr(); SparsePtr(T* ptr); @@ -46,18 +46,16 @@ namespace Nz explicit operator T*() const; T& operator*() const; T* operator->() const; - T& operator[](std::size_t index) const; + template T& operator[](U index) const; SparsePtr& operator=(const SparsePtr& ptr) = default; - SparsePtr operator+(Int64 count) const; - SparsePtr operator+(UInt64 count) const; - SparsePtr operator-(Int64 count) const; - SparsePtr operator-(UInt64 count) const; + template SparsePtr operator+(U count) const; + template SparsePtr operator-(U count) const; std::ptrdiff_t operator-(const SparsePtr& ptr) const; - SparsePtr& operator+=(Int64 count); - SparsePtr& operator-=(Int64 count); + template SparsePtr& operator+=(U count); + template SparsePtr& operator-=(U count); SparsePtr& operator++(); SparsePtr operator++(int); diff --git a/include/Nazara/Core/SparsePtr.inl b/include/Nazara/Core/SparsePtr.inl index a429da527..aab212438 100644 --- a/include/Nazara/Core/SparsePtr.inl +++ b/include/Nazara/Core/SparsePtr.inl @@ -247,8 +247,11 @@ namespace Nz */ template - T& SparsePtr::operator[](std::size_t index) const + template + T& SparsePtr::operator[](U index) const { + static_assert(std::is_integral_v, "index must be an integral type"); + return *reinterpret_cast(m_ptr + index * m_stride); } @@ -260,8 +263,11 @@ namespace Nz */ template - SparsePtr SparsePtr::operator+(Int64 count) const + template + SparsePtr SparsePtr::operator+(U count) const { + static_assert(std::is_integral_v, "count must be an integral type"); + return SparsePtr(m_ptr + count * m_stride, m_stride); } @@ -273,34 +279,11 @@ namespace Nz */ template - SparsePtr SparsePtr::operator+(UInt64 count) const + template + SparsePtr SparsePtr::operator-(U count) const { - return SparsePtr(m_ptr + count * m_stride, m_stride); - } + static_assert(std::is_integral_v, "count must be an integral type"); - /*! - * \brief Gets the SparsePtr with an offset - * \return A SparsePtr with the new stride - * - * \param count Number of stride to do - */ - - template - SparsePtr SparsePtr::operator-(Int64 count) const - { - return SparsePtr(m_ptr - count * m_stride, m_stride); - } - - /*! - * \brief Gets the SparsePtr with an offset - * \return A SparsePtr with the new stride - * - * \param count Number of stride to do - */ - - template - SparsePtr SparsePtr::operator-(UInt64 count) const - { return SparsePtr(m_ptr - count * m_stride, m_stride); } @@ -325,25 +308,22 @@ namespace Nz */ template - SparsePtr& SparsePtr::operator+=(Int64 count) + template + SparsePtr& SparsePtr::operator+=(U count) { - m_ptr += count * m_stride; + static_assert(std::is_integral_v, "count must be an integral type"); + m_ptr += count * m_stride; return *this; } - /*! - * \brief Gets the SparsePtr with an offset - * \return A reference to this pointer with the new stride - * - * \param count Number of stride to do - */ - template - SparsePtr& SparsePtr::operator-=(Int64 count) + template + SparsePtr& SparsePtr::operator-=(U count) { - m_ptr -= count * m_stride; + static_assert(std::is_integral_v, "count must be an integral type"); + m_ptr -= count * m_stride; return *this; } diff --git a/tests/Engine/Core/SparsePtrTest.cpp b/tests/Engine/Core/SparsePtrTest.cpp index 2e8c19844..d3c832a71 100644 --- a/tests/Engine/Core/SparsePtrTest.cpp +++ b/tests/Engine/Core/SparsePtrTest.cpp @@ -34,13 +34,13 @@ SCENARIO("SparsePtr", "[CORE][SPARSEPTR]") THEN("Operator+ and operator-") { - auto offsetTwo = sparsePtr + 2ull; + auto offsetTwo = sparsePtr + 2; CHECK(4 == *offsetTwo); - auto offsetZero = offsetTwo - 2ull; + auto offsetZero = offsetTwo - 2; CHECK(0 == *offsetZero); - CHECK((offsetTwo - offsetZero) == 2ull); + CHECK((offsetTwo - offsetZero) == 2); } } } From 64efd81bf8bfccd6a03caa4815fddaacff630fda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sun, 23 Jan 2022 19:58:04 +0100 Subject: [PATCH 05/14] Shader: Handle matrix cast properly --- include/Nazara/Shader/Ast/SanitizeVisitor.hpp | 3 +- include/Nazara/Shader/ShaderBuilder.hpp | 2 + include/Nazara/Shader/ShaderBuilder.inl | 26 ++++ src/Nazara/Shader/Ast/SanitizeVisitor.cpp | 139 ++++++++++++++++-- src/Nazara/Shader/ShaderLangParser.cpp | 14 ++ src/Nazara/Shader/SpirvWriter.cpp | 3 +- tests/Engine/Shader/Sanitizations.cpp | 129 ++++++++++++++++ 7 files changed, 305 insertions(+), 11 deletions(-) diff --git a/include/Nazara/Shader/Ast/SanitizeVisitor.hpp b/include/Nazara/Shader/Ast/SanitizeVisitor.hpp index 7274b399a..4d878668b 100644 --- a/include/Nazara/Shader/Ast/SanitizeVisitor.hpp +++ b/include/Nazara/Shader/Ast/SanitizeVisitor.hpp @@ -40,9 +40,10 @@ namespace Nz::ShaderAst std::unordered_set reservedIdentifiers; std::unordered_map optionValues; bool makeVariableNameUnique = false; - bool removeConstDeclaration = false; bool reduceLoopsToWhile = false; + bool removeConstDeclaration = false; bool removeCompoundAssignments = false; + bool removeMatrixCast = false; bool removeOptionDeclaration = false; bool removeScalarSwizzling = false; bool splitMultipleBranches = false; diff --git a/include/Nazara/Shader/ShaderBuilder.hpp b/include/Nazara/Shader/ShaderBuilder.hpp index 84b121a95..5783e8b22 100644 --- a/include/Nazara/Shader/ShaderBuilder.hpp +++ b/include/Nazara/Shader/ShaderBuilder.hpp @@ -54,6 +54,7 @@ namespace Nz::ShaderBuilder struct Cast { + inline std::unique_ptr operator()(ShaderAst::ExpressionType targetType, ShaderAst::ExpressionPtr expression) const; inline std::unique_ptr operator()(ShaderAst::ExpressionType targetType, std::array expressions) const; inline std::unique_ptr operator()(ShaderAst::ExpressionType targetType, std::vector expressions) const; }; @@ -71,6 +72,7 @@ namespace Nz::ShaderBuilder struct Constant { inline std::unique_ptr operator()(ShaderAst::ConstantValue value) const; + template std::unique_ptr operator()(ShaderAst::ExpressionType type, T value) const; }; struct DeclareConst diff --git a/include/Nazara/Shader/ShaderBuilder.inl b/include/Nazara/Shader/ShaderBuilder.inl index 0bfc90187..83a2423ab 100644 --- a/include/Nazara/Shader/ShaderBuilder.inl +++ b/include/Nazara/Shader/ShaderBuilder.inl @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include namespace Nz::ShaderBuilder @@ -110,6 +111,15 @@ namespace Nz::ShaderBuilder return callFunctionExpression; } + inline std::unique_ptr Impl::Cast::operator()(ShaderAst::ExpressionType targetType, ShaderAst::ExpressionPtr expression) const + { + auto castNode = std::make_unique(); + castNode->targetType = std::move(targetType); + castNode->expressions[0] = std::move(expression); + + return castNode; + } + inline std::unique_ptr Impl::Cast::operator()(ShaderAst::ExpressionType targetType, std::array expressions) const { auto castNode = std::make_unique(); @@ -159,6 +169,22 @@ namespace Nz::ShaderBuilder return constantNode; } + template + std::unique_ptr Impl::Constant::operator()(ShaderAst::ExpressionType type, T value) const + { + assert(IsPrimitiveType(type)); + + switch (std::get(type)) + { + case ShaderAst::PrimitiveType::Boolean: return ShaderBuilder::Constant(value != T(0)); + case ShaderAst::PrimitiveType::Float32: return ShaderBuilder::Constant(SafeCast(value)); + case ShaderAst::PrimitiveType::Int32: return ShaderBuilder::Constant(SafeCast(value)); + case ShaderAst::PrimitiveType::UInt32: return ShaderBuilder::Constant(SafeCast(value)); + } + + throw std::runtime_error("unexpected primitive type"); + } + inline std::unique_ptr Impl::DeclareConst::operator()(std::string name, ShaderAst::ExpressionPtr initialValue) const { auto declareConstNode = std::make_unique(); diff --git a/src/Nazara/Shader/Ast/SanitizeVisitor.cpp b/src/Nazara/Shader/Ast/SanitizeVisitor.cpp index 5e1449f11..448075fb5 100644 --- a/src/Nazara/Shader/Ast/SanitizeVisitor.cpp +++ b/src/Nazara/Shader/Ast/SanitizeVisitor.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -386,6 +387,88 @@ namespace Nz::ShaderAst auto clone = static_unique_pointer_cast(AstCloner::Clone(node)); Validate(*clone); + if (m_context->options.removeMatrixCast && IsMatrixType(clone->targetType)) + { + const MatrixType& targetMatrixType = std::get(clone->targetType); + + const ShaderAst::ExpressionType& frontExprType = GetExpressionType(*clone->expressions.front()); + bool isMatrixCast = IsMatrixType(frontExprType); + if (isMatrixCast && std::get(frontExprType) == targetMatrixType) + { + // Nothing to do + return std::move(clone->expressions.front()); + } + + auto variableDeclaration = ShaderBuilder::DeclareVariable("temp", clone->targetType); //< Validation will prevent name-clash if required + Validate(*variableDeclaration); + + std::size_t variableIndex = *variableDeclaration->varIndex; + + m_context->currentStatementList->emplace_back(std::move(variableDeclaration)); + + for (std::size_t i = 0; i < targetMatrixType.columnCount; ++i) + { + // temp[i] + auto columnExpr = ShaderBuilder::AccessIndex(ShaderBuilder::Variable(variableIndex, clone->targetType), ShaderBuilder::Constant(UInt32(i))); + Validate(*columnExpr); + + // vector expression + ExpressionPtr vectorExpr; + std::size_t vectorComponentCount; + if (isMatrixCast) + { + // fromMatrix[i] + auto matrixColumnExpr = ShaderBuilder::AccessIndex(CloneExpression(clone->expressions.front()), ShaderBuilder::Constant(UInt32(i))); + Validate(*matrixColumnExpr); + + vectorExpr = std::move(matrixColumnExpr); + vectorComponentCount = std::get(frontExprType).rowCount; + } + else + { + // parameter #i + vectorExpr = std::move(clone->expressions[i]); + vectorComponentCount = std::get(GetExpressionType(*vectorExpr)).componentCount; + } + + // cast expression (turn fromMatrix[i] to vec3(fromMatrix[i])) + ExpressionPtr castExpr; + if (vectorComponentCount != targetMatrixType.rowCount) + { + CastExpressionPtr vecCast; + if (vectorComponentCount < targetMatrixType.rowCount) + { + std::array expressions; + expressions[0] = std::move(vectorExpr); + for (std::size_t j = 0; j < targetMatrixType.rowCount - vectorComponentCount; ++j) + expressions[j + 1] = ShaderBuilder::Constant(targetMatrixType.type, (i == j + vectorComponentCount) ? 1 : 0); //< set 1 to diagonal + + vecCast = ShaderBuilder::Cast(VectorType{ targetMatrixType.rowCount, targetMatrixType.type }, std::move(expressions)); + Validate(*vecCast); + + castExpr = std::move(vecCast); + } + else + { + std::array swizzleComponents; + std::iota(swizzleComponents.begin(), swizzleComponents.begin() + targetMatrixType.rowCount, 0); + + auto swizzleExpr = ShaderBuilder::Swizzle(std::move(vectorExpr), swizzleComponents, targetMatrixType.rowCount); + Validate(*swizzleExpr); + + castExpr = std::move(swizzleExpr); + } + } + else + castExpr = std::move(vectorExpr); + + // temp[i] = castExpr + m_context->currentStatementList->emplace_back(ShaderBuilder::ExpressionStatement(ShaderBuilder::Assign(AssignType::Simple, std::move(columnExpr), std::move(castExpr)))); + } + + return ShaderBuilder::Variable(variableIndex, clone->targetType); + } + return clone; } @@ -653,7 +736,7 @@ namespace Nz::ShaderAst else if (IsSamplerType(extVar.type)) varType = extVar.type; else - throw AstError{ "External variable " + extVar.name + " is of wrong type: only uniform and sampler are allowed in external blocks" }; + throw AstError{ "external variable " + extVar.name + " is of wrong type: only uniform and sampler are allowed in external blocks" }; std::size_t varIndex = RegisterVariable(extVar.name, std::move(varType)); if (!clone->varIndex) @@ -820,6 +903,18 @@ namespace Nz::ShaderAst declaredMembers.insert(member.name); member.type = ResolveType(member.type); + if (clone->description.layout.HasValue() && clone->description.layout.GetResultingValue() == StructLayout::Std140) + { + if (IsPrimitiveType(member.type) && std::get(member.type) == PrimitiveType::Boolean) + throw AstError{ "boolean type is not allowed in std140 layout" }; + else if (IsStructType(member.type)) + { + std::size_t structIndex = std::get(member.type).structIndex; + const StructDescription* desc = m_context->structs[structIndex]; + if (!desc->layout.HasValue() || desc->layout.GetResultingValue() != clone->description.layout.GetResultingValue()) + throw AstError{ "inner struct layout mismatch" }; + } + } } clone->structIndex = RegisterStruct(clone->description.name, &clone->description); @@ -1695,18 +1790,44 @@ namespace Nz::ShaderAst void SanitizeVisitor::Validate(CastExpression& node) { - node.cachedExpressionType = node.targetType; node.targetType = ResolveType(node.targetType); + node.cachedExpressionType = node.targetType; - // Allow casting a matrix to itself (wtf?) - // FIXME: Make proper rules - if (IsMatrixType(node.targetType) && node.expressions.front()) + const auto& firstExprPtr = node.expressions.front(); + if (!firstExprPtr) + throw AstError{ "expected at least one expression" }; + + if (IsMatrixType(node.targetType)) { - const ExpressionType& exprType = GetExpressionType(*node.expressions.front()); - if (IsMatrixType(exprType) && !node.expressions[1]) + const MatrixType& targetMatrixType = std::get(node.targetType); + + const ExpressionType& firstExprType = GetExpressionType(*firstExprPtr); + if (IsMatrixType(firstExprType)) { + if (node.expressions[1]) + throw AstError{ "too many expressions" }; + + // Matrix to matrix cast: always valid return; } + else + { + assert(targetMatrixType.columnCount <= 4); + for (std::size_t i = 0; i < targetMatrixType.columnCount; ++i) + { + const auto& exprPtr = node.expressions[i]; + if (!exprPtr) + throw AstError{ "component count doesn't match required component count" }; + + const ExpressionType& exprType = GetExpressionType(*exprPtr); + if (!IsVectorType(exprType)) + throw AstError{ "expected vector type" }; + + const VectorType& vecType = std::get(exprType); + if (vecType.componentCount != targetMatrixType.rowCount) + throw AstError{ "vector component count must match target matrix row count" }; + } + } } auto GetComponentCount = [](const ExpressionType& exprType) -> std::size_t @@ -1936,9 +2057,9 @@ namespace Nz::ShaderAst if (node.componentCount > 4) throw AstError{ "cannot swizzle more than four elements" }; - for (UInt32 swizzleIndex : node.components) + for (std::size_t i = 0; i < node.componentCount; ++i) { - if (swizzleIndex >= componentCount) + if (node.components[i] >= componentCount) throw AstError{ "invalid swizzle" }; } diff --git a/src/Nazara/Shader/ShaderLangParser.cpp b/src/Nazara/Shader/ShaderLangParser.cpp index 210d20c01..f08ad1ca4 100644 --- a/src/Nazara/Shader/ShaderLangParser.cpp +++ b/src/Nazara/Shader/ShaderLangParser.cpp @@ -235,6 +235,20 @@ namespace Nz::ShaderLang return matrixType; } + else if (identifier == "mat2") + { + Consume(); + + ShaderAst::MatrixType matrixType; + matrixType.columnCount = 2; + matrixType.rowCount = 2; + + Expect(Advance(), TokenType::LessThan); //< '<' + matrixType.type = ParsePrimitiveType(); + Expect(Advance(), TokenType::GreaterThan); //< '>' + + return matrixType; + } else if (identifier == "sampler2D") { Consume(); diff --git a/src/Nazara/Shader/SpirvWriter.cpp b/src/Nazara/Shader/SpirvWriter.cpp index 13a314b1f..a4ecc52d5 100644 --- a/src/Nazara/Shader/SpirvWriter.cpp +++ b/src/Nazara/Shader/SpirvWriter.cpp @@ -491,7 +491,8 @@ namespace Nz options.optionValues = states.optionValues; options.reduceLoopsToWhile = true; options.removeCompoundAssignments = true; - options.removeOptionDeclaration = true; + options.removeMatrixCast = true; + options.removeOptionDeclaration = true; options.splitMultipleBranches = true; options.useIdentifierAccessesForStructs = false; diff --git a/tests/Engine/Shader/Sanitizations.cpp b/tests/Engine/Shader/Sanitizations.cpp index e28256adb..76025fee9 100644 --- a/tests/Engine/Shader/Sanitizations.cpp +++ b/tests/Engine/Shader/Sanitizations.cpp @@ -124,6 +124,135 @@ fn main() } } +)"); + + } + + WHEN("removing matrix casts") + { + std::string_view nzslSource = R"( +fn testMat2ToMat2(input: mat2) -> mat2 +{ + return mat2(input); +} + +fn testMat2ToMat3(input: mat2) -> mat3 +{ + return mat3(input); +} + +fn testMat2ToMat4(input: mat2) -> mat4 +{ + return mat4(input); +} + +fn testMat3ToMat2(input: mat3) -> mat2 +{ + return mat2(input); +} + +fn testMat3ToMat3(input: mat3) -> mat3 +{ + return mat3(input); +} + +fn testMat3ToMat4(input: mat3) -> mat4 +{ + return mat4(input); +} + +fn testMat4ToMat2(input: mat4) -> mat2 +{ + return mat2(input); +} + +fn testMat4ToMat3(input: mat4) -> mat3 +{ + return mat3(input); +} + +fn testMat4ToMat4(input: mat4) -> mat4 +{ + return mat4(input); +} +)"; + + Nz::ShaderAst::StatementPtr shader = Nz::ShaderLang::Parse(nzslSource); + + Nz::ShaderAst::SanitizeVisitor::Options options; + options.removeMatrixCast = true; + + REQUIRE_NOTHROW(shader = Nz::ShaderAst::Sanitize(*shader, options)); + + ExpectNZSL(*shader, R"( +fn testMat2ToMat2(input: mat2) -> mat2 +{ + return input; +} + +fn testMat2ToMat3(input: mat2) -> mat3 +{ + let temp: mat3; + temp[0] = vec3(input[0], 0.000000); + temp[1] = vec3(input[1], 0.000000); + temp[2] = vec3(input[2], 1.000000); + return temp; +} + +fn testMat2ToMat4(input: mat2) -> mat4 +{ + let temp: mat4; + temp[0] = vec4(input[0], 0.000000, 0.000000); + temp[1] = vec4(input[1], 0.000000, 0.000000); + temp[2] = vec4(input[2], 1.000000, 0.000000); + temp[3] = vec4(input[3], 0.000000, 1.000000); + return temp; +} + +fn testMat3ToMat2(input: mat3) -> mat2 +{ + let temp: mat2; + temp[0] = input[0].xy; + temp[1] = input[1].xy; + return temp; +} + +fn testMat3ToMat3(input: mat3) -> mat3 +{ + return input; +} + +fn testMat3ToMat4(input: mat3) -> mat4 +{ + let temp: mat4; + temp[0] = vec4(input[0], 0.000000); + temp[1] = vec4(input[1], 0.000000); + temp[2] = vec4(input[2], 0.000000); + temp[3] = vec4(input[3], 1.000000); + return temp; +} + +fn testMat4ToMat2(input: mat4) -> mat2 +{ + let temp: mat2; + temp[0] = input[0].xy; + temp[1] = input[1].xy; + return temp; +} + +fn testMat4ToMat3(input: mat4) -> mat3 +{ + let temp: mat3; + temp[0] = input[0].xyz; + temp[1] = input[1].xyz; + temp[2] = input[2].xyz; + return temp; +} + +fn testMat4ToMat4(input: mat4) -> mat4 +{ + return input; +} )"); } From 2463e471cc6235b8eeb447353c2f936b5700d283 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sun, 23 Jan 2022 19:59:10 +0100 Subject: [PATCH 06/14] Shader/SPIRV: Fix issues with loops containing branches and cross product --- include/Nazara/Shader/SpirvAstVisitor.hpp | 2 +- src/Nazara/Shader/SpirvAstVisitor.cpp | 81 +++++++++++++++-------- 2 files changed, 53 insertions(+), 30 deletions(-) diff --git a/include/Nazara/Shader/SpirvAstVisitor.hpp b/include/Nazara/Shader/SpirvAstVisitor.hpp index 297160404..28e98b157 100644 --- a/include/Nazara/Shader/SpirvAstVisitor.hpp +++ b/include/Nazara/Shader/SpirvAstVisitor.hpp @@ -152,7 +152,7 @@ namespace Nz std::unordered_map m_structs; std::unordered_map m_variables; std::vector m_scopeSizes; - std::vector m_functionBlocks; + std::vector> m_functionBlocks; std::vector m_resultIds; SpirvBlock* m_currentBlock; SpirvSection& m_instructions; diff --git a/src/Nazara/Shader/SpirvAstVisitor.cpp b/src/Nazara/Shader/SpirvAstVisitor.cpp index 3a187f1fb..224b223d7 100644 --- a/src/Nazara/Shader/SpirvAstVisitor.cpp +++ b/src/Nazara/Shader/SpirvAstVisitor.cpp @@ -368,34 +368,34 @@ namespace Nz assert(node.condStatements.size() == 1); //< sanitization splits multiple branches auto& condStatement = node.condStatements.front(); - SpirvBlock mergeBlock(m_writer); - SpirvBlock contentBlock(m_writer); - SpirvBlock elseBlock(m_writer); + auto mergeBlock = std::make_unique(m_writer); + auto contentBlock = std::make_unique(m_writer); + auto elseBlock = std::make_unique(m_writer); UInt32 conditionId = EvaluateExpression(condStatement.condition); - m_currentBlock->Append(SpirvOp::OpSelectionMerge, mergeBlock.GetLabelId(), SpirvSelectionControl::None); + m_currentBlock->Append(SpirvOp::OpSelectionMerge, mergeBlock->GetLabelId(), SpirvSelectionControl::None); // FIXME: Can we use merge block directly in OpBranchConditional if no else statement? - m_currentBlock->Append(SpirvOp::OpBranchConditional, conditionId, contentBlock.GetLabelId(), elseBlock.GetLabelId()); + m_currentBlock->Append(SpirvOp::OpBranchConditional, conditionId, contentBlock->GetLabelId(), elseBlock->GetLabelId()); m_functionBlocks.emplace_back(std::move(contentBlock)); - m_currentBlock = &m_functionBlocks.back(); + m_currentBlock = m_functionBlocks.back().get(); condStatement.statement->Visit(*this); if (!m_currentBlock->IsTerminated()) - m_currentBlock->Append(SpirvOp::OpBranch, mergeBlock.GetLabelId()); + m_currentBlock->Append(SpirvOp::OpBranch, mergeBlock->GetLabelId()); m_functionBlocks.emplace_back(std::move(elseBlock)); - m_currentBlock = &m_functionBlocks.back(); + m_currentBlock = m_functionBlocks.back().get(); if (node.elseStatement) node.elseStatement->Visit(*this); if (!m_currentBlock->IsTerminated()) - m_currentBlock->Append(SpirvOp::OpBranch, mergeBlock.GetLabelId()); + m_currentBlock->Append(SpirvOp::OpBranch, mergeBlock->GetLabelId()); m_functionBlocks.emplace_back(std::move(mergeBlock)); - m_currentBlock = &m_functionBlocks.back(); + m_currentBlock = m_functionBlocks.back().get(); } void SpirvAstVisitor::Visit(ShaderAst::CallFunctionExpression& node) @@ -609,9 +609,12 @@ namespace Nz } } - m_functionBlocks.clear(); + auto contentBlock = std::make_unique(m_writer); + m_currentBlock = contentBlock.get(); + + m_functionBlocks.clear(); + m_functionBlocks.emplace_back(std::move(contentBlock)); - m_currentBlock = &m_functionBlocks.emplace_back(m_writer); CallOnExit resetCurrentBlock([&] { m_currentBlock = nullptr; }); for (auto& var : func.variables) @@ -647,11 +650,11 @@ namespace Nz statementPtr->Visit(*this); // Add implicit return - if (!m_functionBlocks.back().IsTerminated()) - m_functionBlocks.back().Append(SpirvOp::OpReturn); + if (!m_functionBlocks.back()->IsTerminated()) + m_functionBlocks.back()->Append(SpirvOp::OpReturn); - for (SpirvBlock& block : m_functionBlocks) - m_instructions.AppendSection(block); + for (std::unique_ptr& block : m_functionBlocks) + m_instructions.AppendSection(*block); m_instructions.Append(SpirvOp::OpFunctionEnd); } @@ -702,6 +705,23 @@ namespace Nz { switch (node.intrinsic) { + case ShaderAst::IntrinsicType::CrossProduct: + { + UInt32 glslInstructionSet = m_writer.GetExtendedInstructionSet("GLSL.std.450"); + + const ShaderAst::ExpressionType& parameterType = GetExpressionType(*node.parameters[0]); + assert(IsVectorType(parameterType)); + UInt32 typeId = m_writer.GetTypeId(parameterType); + + UInt32 firstParam = EvaluateExpression(node.parameters[0]); + UInt32 secondParam = EvaluateExpression(node.parameters[1]); + UInt32 resultId = m_writer.AllocateResultId(); + + m_currentBlock->Append(SpirvOp::OpExtInst, typeId, resultId, glslInstructionSet, GLSLstd450Cross, firstParam, secondParam); + PushResultId(resultId); + break; + } + case ShaderAst::IntrinsicType::DotProduct: { const ShaderAst::ExpressionType& vecExprType = GetExpressionType(*node.parameters[0]); @@ -867,7 +887,6 @@ namespace Nz break; } - case ShaderAst::IntrinsicType::CrossProduct: default: throw std::runtime_error("not yet implemented"); } @@ -1057,12 +1076,12 @@ namespace Nz assert(node.condition); assert(node.body); - SpirvBlock headerBlock(m_writer); - SpirvBlock bodyBlock(m_writer); - SpirvBlock mergeBlock(m_writer); + auto headerBlock = std::make_unique(m_writer); + auto bodyBlock = std::make_unique(m_writer); + auto mergeBlock = std::make_unique(m_writer); - m_currentBlock->Append(SpirvOp::OpBranch, headerBlock.GetLabelId()); - m_currentBlock = &headerBlock; + m_currentBlock->Append(SpirvOp::OpBranch, headerBlock->GetLabelId()); + m_currentBlock = headerBlock.get(); UInt32 expressionId = EvaluateExpression(node.condition); @@ -1087,18 +1106,22 @@ namespace Nz else loopControl = SpirvLoopControl::None; - m_currentBlock->Append(SpirvOp::OpLoopMerge, mergeBlock.GetLabelId(), bodyBlock.GetLabelId(), loopControl); - m_currentBlock->Append(SpirvOp::OpBranchConditional, expressionId, bodyBlock.GetLabelId(), mergeBlock.GetLabelId()); + m_currentBlock->Append(SpirvOp::OpLoopMerge, mergeBlock->GetLabelId(), bodyBlock->GetLabelId(), loopControl); + m_currentBlock->Append(SpirvOp::OpBranchConditional, expressionId, bodyBlock->GetLabelId(), mergeBlock->GetLabelId()); - m_currentBlock = &bodyBlock; - node.body->Visit(*this); - - m_currentBlock->Append(SpirvOp::OpBranch, headerBlock.GetLabelId()); + UInt32 headerLabelId = headerBlock->GetLabelId(); + m_currentBlock = bodyBlock.get(); m_functionBlocks.emplace_back(std::move(headerBlock)); m_functionBlocks.emplace_back(std::move(bodyBlock)); + + node.body->Visit(*this); + + // Jump back to header block to test condition + m_currentBlock->Append(SpirvOp::OpBranch, headerLabelId); + m_functionBlocks.emplace_back(std::move(mergeBlock)); - m_currentBlock = &m_functionBlocks.back(); + m_currentBlock = m_functionBlocks.back().get(); } void SpirvAstVisitor::PushResultId(UInt32 value) From b8a52b93e8abdf268af09710377cf22d3fe7150d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sun, 23 Jan 2022 19:59:26 +0100 Subject: [PATCH 07/14] Shader/SPIRV: Handle arrays properly --- include/Nazara/Shader/SpirvConstantCache.hpp | 17 + src/Nazara/Shader/SpirvConstantCache.cpp | 334 +++++++++++++------ 2 files changed, 243 insertions(+), 108 deletions(-) diff --git a/include/Nazara/Shader/SpirvConstantCache.hpp b/include/Nazara/Shader/SpirvConstantCache.hpp index a22da4a9a..ad1924956 100644 --- a/include/Nazara/Shader/SpirvConstantCache.hpp +++ b/include/Nazara/Shader/SpirvConstantCache.hpp @@ -20,6 +20,7 @@ namespace Nz { + class FieldOffsets; class SpirvSection; class NAZARA_SHADER_API SpirvConstantCache @@ -108,6 +109,7 @@ namespace Nz { std::string name; TypePtr type; + mutable std::optional offset; }; std::string name; @@ -171,6 +173,7 @@ namespace Nz }; ConstantPtr BuildConstant(const ShaderAst::ConstantValue& value) const; + FieldOffsets BuildFieldOffsets(const Structure& structData) const; TypePtr BuildFunctionType(const ShaderAst::ExpressionType& retType, const std::vector& parameters) const; TypePtr BuildPointerType(const ShaderAst::PrimitiveType& type, SpirvStorageClass storageClass) const; TypePtr BuildPointerType(const ShaderAst::ExpressionType& type, SpirvStorageClass storageClass) const; @@ -195,6 +198,20 @@ namespace Nz UInt32 Register(Type t); UInt32 Register(Variable v); + std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const Array& type, std::size_t arrayLength) const; + std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const Bool& type, std::size_t arrayLength) const; + std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const Float& type, std::size_t arrayLength) const; + std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const Function& type, std::size_t arrayLength) const; + std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const Image& type, std::size_t arrayLength) const; + std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const Integer& type, std::size_t arrayLength) const; + std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const Matrix& type, std::size_t arrayLength) const; + std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const Pointer& type, std::size_t arrayLength) const; + std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const SampledImage& type, std::size_t arrayLength) const; + std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const Structure& type, std::size_t arrayLength) const; + std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const Type& type, std::size_t arrayLength) const; + std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const Vector& type, std::size_t arrayLength) const; + std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const Void& type, std::size_t arrayLength) const; + void SetStructCallback(StructCallback callback); void Write(SpirvSection& annotations, SpirvSection& constants, SpirvSection& debugInfos); diff --git a/src/Nazara/Shader/SpirvConstantCache.cpp b/src/Nazara/Shader/SpirvConstantCache.cpp index d3b9eb027..2d65f26e1 100644 --- a/src/Nazara/Shader/SpirvConstantCache.cpp +++ b/src/Nazara/Shader/SpirvConstantCache.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -16,7 +17,27 @@ namespace Nz { template struct overloaded : Ts... { using Ts::operator()...; }; - template overloaded(Ts...)->overloaded; + template overloaded(Ts...) -> overloaded; + + StructFieldType TypeToStructFieldType(const SpirvConstantCache::AnyType& type) + { + if (std::holds_alternative(type)) + return StructFieldType::Bool1; + else if (std::holds_alternative(type)) + { + const auto& floatType = std::get(type); + assert(floatType.width == 32 || floatType.width == 64); + return (floatType.width == 32) ? StructFieldType::Float1 : StructFieldType::Double1; + } + else if (std::holds_alternative(type)) + { + const auto& intType = std::get(type); + assert(intType.width == 32); + return (intType.signedness) ? StructFieldType::Int1 : StructFieldType::UInt1; + } + + throw std::runtime_error("unexpected type"); + } } struct SpirvConstantCache::Eq @@ -278,6 +299,7 @@ namespace Nz void Register(const Structure& s) { Register(s.members); + cache.BuildFieldOffsets(s); } void Register(const SpirvConstantCache::Structure::Member& m) @@ -408,6 +430,12 @@ namespace Nz struct SpirvConstantCache::Internal { + struct StructOffsets + { + FieldOffsets fieldOffsets; + std::vector offsets; + }; + Internal(UInt32& resultId) : nextResultId(resultId) { @@ -415,7 +443,6 @@ namespace Nz tsl::ordered_map, UInt32 /*id*/, AnyHasher, Eq> ids; tsl::ordered_map variableIds; - tsl::ordered_map structureSizes; StructCallback structCallback; UInt32& nextResultId; bool isInBlockStruct = false; @@ -480,6 +507,106 @@ namespace Nz }, value)); } + FieldOffsets SpirvConstantCache::BuildFieldOffsets(const Structure& structData) const + { + FieldOffsets structOffsets(StructLayout::Std140); + + for (const Structure::Member& member : structData.members) + { + member.offset = std::visit([&](auto&& arg) -> std::size_t + { + using T = std::decay_t; + + if constexpr (std::is_same_v) + { + assert(std::holds_alternative(arg.length->constant)); + const auto& scalar = std::get(arg.length->constant); + assert(std::holds_alternative(scalar.value)); + std::size_t length = std::get(scalar.value); + + return RegisterArrayField(structOffsets, arg.elementType->type, length); + } + else if constexpr (std::is_same_v) + return structOffsets.AddField(StructFieldType::Bool1); + else if constexpr (std::is_same_v) + { + switch (arg.width) + { + case 32: return structOffsets.AddField(StructFieldType::Float1); + case 64: return structOffsets.AddField(StructFieldType::Double1); + default: throw std::runtime_error("unexpected float width " + std::to_string(arg.width)); + } + } + else if constexpr (std::is_same_v) + return structOffsets.AddField((arg.signedness) ? StructFieldType::Int1 : StructFieldType::UInt1); + else if constexpr (std::is_same_v) + { + assert(std::holds_alternative(arg.columnType->type)); + Vector& columnVec = std::get(arg.columnType->type); + + if (!std::holds_alternative(columnVec.componentType->type)) + throw std::runtime_error("unexpected vector type"); + + Float& vecType = std::get(columnVec.componentType->type); + + StructFieldType columnType; + switch (vecType.width) + { + case 32: columnType = StructFieldType::Float1; break; + case 64: columnType = StructFieldType::Double1; break; + default: throw std::runtime_error("unexpected float width " + std::to_string(vecType.width)); + } + + return structOffsets.AddMatrix(columnType, arg.columnCount, columnVec.componentCount, true); + } + else if constexpr (std::is_same_v) + throw std::runtime_error("unhandled pointer in struct"); + else if constexpr (std::is_same_v) + return structOffsets.AddStruct(BuildFieldOffsets(arg)); + else if constexpr (std::is_same_v) + { + if (std::holds_alternative(arg.componentType->type)) + return structOffsets.AddField(static_cast(UnderlyingCast(StructFieldType::Bool1) + arg.componentCount - 1)); + else if (std::holds_alternative(arg.componentType->type)) + { + Float& floatData = std::get(arg.componentType->type); + switch (floatData.width) + { + case 32: return structOffsets.AddField(static_cast(UnderlyingCast(StructFieldType::Float1) + arg.componentCount - 1)); + case 64: return structOffsets.AddField(static_cast(UnderlyingCast(StructFieldType::Double1) + arg.componentCount - 1)); + default: throw std::runtime_error("unexpected float width " + std::to_string(floatData.width)); + } + } + else if (std::holds_alternative(arg.componentType->type)) + { + Integer& intData = std::get(arg.componentType->type); + if (intData.width != 32) + throw std::runtime_error("unexpected integer width " + std::to_string(intData.width)); + + if (intData.signedness) + return structOffsets.AddField(static_cast(UnderlyingCast(StructFieldType::Int1) + arg.componentCount - 1)); + else + return structOffsets.AddField(static_cast(UnderlyingCast(StructFieldType::UInt1) + arg.componentCount - 1)); + } + else + throw std::runtime_error("unexpected type for vector"); + } + else if constexpr (std::is_same_v) + throw std::runtime_error("unexpected function as struct member"); + else if constexpr (std::is_same_v) + throw std::runtime_error("unexpected identifier"); + else if constexpr (std::is_same_v || std::is_same_v) + throw std::runtime_error("unexpected opaque type as struct member"); + else if constexpr (std::is_same_v) + throw std::runtime_error("unexpected void as struct member"); + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, member.type->type); + } + + return structOffsets; + } + auto SpirvConstantCache::BuildFunctionType(const ShaderAst::ExpressionType& retType, const std::vector& parameters) const -> TypePtr { std::vector parameterTypes; @@ -528,10 +655,24 @@ namespace Nz auto SpirvConstantCache::BuildType(const ShaderAst::ArrayType& type) const -> TypePtr { + const auto& containedType = type.containedType->type; + + TypePtr builtContainedType = BuildType(containedType); + + // ArrayStride + std::optional arrayStride; + if (m_internal->isInBlockStruct) + { + FieldOffsets fieldOffset(StructLayout::Std140); + RegisterArrayField(fieldOffset, builtContainedType->type, 1); + + arrayStride = SafeCast(fieldOffset.GetAlignedSize()); + } + return std::make_shared(Array{ - BuildType(type.containedType->type), + builtContainedType, BuildConstant(type.length.GetResultingValue()), - (m_internal->isInBlockStruct) ? std::make_optional(16) : std::nullopt + arrayStride }); } @@ -759,6 +900,83 @@ namespace Nz return it.value(); } + std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& fieldOffsets, const Array& type, std::size_t arrayLength) const + { + FieldOffsets dummyStruct(fieldOffsets.GetLayout()); + RegisterArrayField(dummyStruct, type.elementType->type, std::get(std::get(type.length->constant).value)); + + return fieldOffsets.AddStructArray(dummyStruct, arrayLength); + } + + std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& fieldOffsets, const Bool& type, std::size_t arrayLength) const + { + return fieldOffsets.AddFieldArray(TypeToStructFieldType(type), arrayLength); + } + + std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& fieldOffsets, const Float& type, std::size_t arrayLength) const + { + return fieldOffsets.AddFieldArray(TypeToStructFieldType(type), arrayLength); + } + + std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& fieldOffsets, const Function& type, std::size_t arrayLength) const + { + throw std::runtime_error("unexpected Function"); + } + + std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& fieldOffsets, const Image& type, std::size_t arrayLength) const + { + throw std::runtime_error("unexpected Image"); + } + + std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& fieldOffsets, const Integer& type, std::size_t arrayLength) const + { + return fieldOffsets.AddFieldArray(TypeToStructFieldType(type), arrayLength); + } + + std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& fieldOffsets, const Matrix& type, std::size_t arrayLength) const + { + if (!std::holds_alternative(type.columnType->type)) + throw std::runtime_error("unexpected column type"); + + const Vector& vecType = std::get(type.columnType->type); + return fieldOffsets.AddMatrixArray(TypeToStructFieldType(vecType.componentType->type), type.columnCount, vecType.componentCount, true, arrayLength); + } + + std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& /*fieldOffsets*/, const Pointer& /*type*/, std::size_t /*arrayLength*/) const + { + throw std::runtime_error("unexpected Pointer (not implemented)"); + } + + std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& /*fieldOffsets*/, const SampledImage& /*type*/, std::size_t /*arrayLength*/) const + { + throw std::runtime_error("unexpected SampledImage"); + } + + std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& fieldOffsets, const Structure& type, std::size_t arrayLength) const + { + auto innerFieldOffset = BuildFieldOffsets(type); + return fieldOffsets.AddStructArray(innerFieldOffset, arrayLength); + } + + std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& fieldOffsets, const Type& type, std::size_t arrayLength) const + { + return std::visit([&](auto&& arg) -> std::size_t + { + return RegisterArrayField(fieldOffsets, arg, arrayLength); + }, type.type); + } + + std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& fieldOffsets, const Vector& type, std::size_t arrayLength) const + { + assert(type.componentCount > 0 && type.componentCount <= 4); + return fieldOffsets.AddFieldArray(static_cast(UnderlyingCast(TypeToStructFieldType(type.componentType->type)) + type.componentCount), arrayLength); + } + + std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& fieldOffsets, const Void& type, std::size_t arrayLength) const + { + throw std::runtime_error("unexpected Void"); + } + void SpirvConstantCache::SetStructCallback(StructCallback callback) { m_internal->structCallback = std::move(callback); @@ -941,125 +1159,25 @@ namespace Nz for (SpirvDecoration decoration : structData.decorations) annotations.Append(SpirvOp::OpDecorate, resultId, decoration); - FieldOffsets structOffsets(StructLayout::Std140); - for (std::size_t memberIndex = 0; memberIndex < structData.members.size(); ++memberIndex) { const auto& member = structData.members[memberIndex]; debugInfos.Append(SpirvOp::OpMemberName, resultId, memberIndex, member.name); - std::size_t offset = std::visit([&](auto&& arg) -> std::size_t + UInt32 offset = member.offset.value(); + + std::visit([&](auto&& arg) { using T = std::decay_t; - if constexpr (std::is_same_v) + if constexpr (std::is_same_v) { - assert(std::holds_alternative(arg.length->constant)); - const auto& scalar = std::get(arg.length->constant); - assert(std::holds_alternative(scalar.value)); - std::size_t length = std::get(scalar.value); - - if (!std::holds_alternative(arg.elementType->type)) - throw std::runtime_error("todo"); - - // FIXME: Virer cette implémentation du ghetto - - const Float& fData = std::get(arg.elementType->type); - switch (fData.width) - { - case 32: return structOffsets.AddFieldArray(StructFieldType::Float1, length); - case 64: return structOffsets.AddFieldArray(StructFieldType::Double1, length); - default: throw std::runtime_error("unexpected float width " + std::to_string(fData.width)); - } - } - else if constexpr (std::is_same_v) - return structOffsets.AddField(StructFieldType::Bool1); - else if constexpr (std::is_same_v) - { - switch (arg.width) - { - case 32: return structOffsets.AddField(StructFieldType::Float1); - case 64: return structOffsets.AddField(StructFieldType::Double1); - default: throw std::runtime_error("unexpected float width " + std::to_string(arg.width)); - } - } - else if constexpr (std::is_same_v) - return structOffsets.AddField((arg.signedness) ? StructFieldType::Int1 : StructFieldType::UInt1); - else if constexpr (std::is_same_v) - { - assert(std::holds_alternative(arg.columnType->type)); - Vector& columnVec = std::get(arg.columnType->type); - - if (!std::holds_alternative(columnVec.componentType->type)) - throw std::runtime_error("unexpected vector type"); - - Float& vecType = std::get(columnVec.componentType->type); - - StructFieldType columnType; - switch (vecType.width) - { - case 32: columnType = StructFieldType::Float1; break; - case 64: columnType = StructFieldType::Double1; break; - default: throw std::runtime_error("unexpected float width " + std::to_string(vecType.width)); - } - annotations.Append(SpirvOp::OpMemberDecorate, resultId, memberIndex, SpirvDecoration::ColMajor); annotations.Append(SpirvOp::OpMemberDecorate, resultId, memberIndex, SpirvDecoration::MatrixStride, 16); - - return structOffsets.AddMatrix(columnType, arg.columnCount, columnVec.componentCount, true); } - else if constexpr (std::is_same_v) - throw std::runtime_error("unhandled pointer in struct"); - else if constexpr (std::is_same_v) - { - auto it = m_internal->structureSizes.find(arg); - assert(it != m_internal->structureSizes.end()); - - return structOffsets.AddStruct(it->second); - } - else if constexpr (std::is_same_v) - { - if (std::holds_alternative(arg.componentType->type)) - return structOffsets.AddField(static_cast(UnderlyingCast(StructFieldType::Bool1) + arg.componentCount - 1)); - else if (std::holds_alternative(arg.componentType->type)) - { - Float& floatData = std::get(arg.componentType->type); - switch (floatData.width) - { - case 32: return structOffsets.AddField(static_cast(UnderlyingCast(StructFieldType::Float1) + arg.componentCount - 1)); - case 64: return structOffsets.AddField(static_cast(UnderlyingCast(StructFieldType::Double1) + arg.componentCount - 1)); - default: throw std::runtime_error("unexpected float width " + std::to_string(floatData.width)); - } - } - else if (std::holds_alternative(arg.componentType->type)) - { - Integer& intData = std::get(arg.componentType->type); - if (intData.width != 32) - throw std::runtime_error("unexpected integer width " + std::to_string(intData.width)); - - if (intData.signedness) - return structOffsets.AddField(static_cast(UnderlyingCast(StructFieldType::Int1) + arg.componentCount - 1)); - else - return structOffsets.AddField(static_cast(UnderlyingCast(StructFieldType::UInt1) + arg.componentCount - 1)); - } - else - throw std::runtime_error("unexpected type for vector"); - } - else if constexpr (std::is_same_v) - throw std::runtime_error("unexpected function as struct member"); - else if constexpr (std::is_same_v) - throw std::runtime_error("unexpected identifier"); - else if constexpr (std::is_same_v || std::is_same_v) - throw std::runtime_error("unexpected opaque type as struct member"); - else if constexpr (std::is_same_v) - throw std::runtime_error("unexpected void as struct member"); - else - static_assert(AlwaysFalse::value, "non-exhaustive visitor"); }, member.type->type); annotations.Append(SpirvOp::OpMemberDecorate, resultId, memberIndex, SpirvDecoration::Offset, offset); } - - m_internal->structureSizes.emplace(structData, std::move(structOffsets)); } } From 97356349fe91361903067784b03d21b43da89099 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sun, 23 Jan 2022 19:59:44 +0100 Subject: [PATCH 08/14] Utility/FieldOffsets: Add GetLayout method --- include/Nazara/Utility/FieldOffsets.hpp | 1 + include/Nazara/Utility/FieldOffsets.inl | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/include/Nazara/Utility/FieldOffsets.hpp b/include/Nazara/Utility/FieldOffsets.hpp index 7517f62aa..e61ac974a 100644 --- a/include/Nazara/Utility/FieldOffsets.hpp +++ b/include/Nazara/Utility/FieldOffsets.hpp @@ -29,6 +29,7 @@ namespace Nz inline std::size_t GetAlignedSize() const; inline std::size_t GetLargestFieldAlignement() const; + inline StructLayout GetLayout() const; inline std::size_t GetSize() const; FieldOffsets& operator=(const FieldOffsets&) = default; diff --git a/include/Nazara/Utility/FieldOffsets.inl b/include/Nazara/Utility/FieldOffsets.inl index c5eccda0c..b4dec65a5 100644 --- a/include/Nazara/Utility/FieldOffsets.inl +++ b/include/Nazara/Utility/FieldOffsets.inl @@ -23,6 +23,11 @@ namespace Nz return m_largestFieldAlignment; } + inline StructLayout FieldOffsets::GetLayout() const + { + return m_layout; + } + inline std::size_t FieldOffsets::GetAlignedSize() const { if (m_layout == StructLayout::Std140) From 29a01e975c7e679859912252290419b1b54aa6fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sun, 23 Jan 2022 20:00:11 +0100 Subject: [PATCH 09/14] Merge fix --- include/Nazara/Graphics/ElementRenderer.hpp | 5 +++-- include/Nazara/Graphics/ForwardFramePipeline.hpp | 2 +- include/Nazara/Graphics/Graphics.hpp | 2 +- include/Nazara/Graphics/RenderQueueRegistry.hpp | 1 - include/Nazara/Graphics/RenderSpriteChain.hpp | 1 - include/Nazara/Graphics/RenderSubmesh.hpp | 1 - include/Nazara/Graphics/SpriteChainRenderer.hpp | 1 - include/Nazara/Graphics/SubmeshRenderer.hpp | 1 - include/Nazara/Graphics/ViewerInstance.hpp | 2 +- include/Nazara/Graphics/WorldInstance.hpp | 2 +- include/Nazara/Renderer/Renderer.hpp | 1 - src/Nazara/Graphics/ForwardFramePipeline.cpp | 4 +--- 12 files changed, 8 insertions(+), 15 deletions(-) diff --git a/include/Nazara/Graphics/ElementRenderer.hpp b/include/Nazara/Graphics/ElementRenderer.hpp index 6d76a83d7..d9e974f2d 100644 --- a/include/Nazara/Graphics/ElementRenderer.hpp +++ b/include/Nazara/Graphics/ElementRenderer.hpp @@ -12,12 +12,13 @@ #include #include #include +#include #include namespace Nz { - class AbstractBuffer; class CommandBufferBuilder; + class RenderBuffer; class RenderElement; class RenderFrame; class ViewerInstance; @@ -38,7 +39,7 @@ namespace Nz struct RenderStates { - std::shared_ptr lightData; + std::optional lightData; }; }; diff --git a/include/Nazara/Graphics/ForwardFramePipeline.hpp b/include/Nazara/Graphics/ForwardFramePipeline.hpp index 3c3ad6dfc..43399deda 100644 --- a/include/Nazara/Graphics/ForwardFramePipeline.hpp +++ b/include/Nazara/Graphics/ForwardFramePipeline.hpp @@ -108,7 +108,7 @@ namespace Nz std::size_t m_depthPassIndex; std::size_t m_forwardPassIndex; - std::shared_ptr m_lightDataBuffer; + std::shared_ptr m_lightDataBuffer; std::unordered_map m_viewers; std::unordered_map m_materials; std::unordered_map> m_renderables; diff --git a/include/Nazara/Graphics/Graphics.hpp b/include/Nazara/Graphics/Graphics.hpp index e91ca11e3..c021fd109 100644 --- a/include/Nazara/Graphics/Graphics.hpp +++ b/include/Nazara/Graphics/Graphics.hpp @@ -19,7 +19,7 @@ namespace Nz { - class AbstractBuffer; + class RenderBuffer; class NAZARA_GRAPHICS_API Graphics : public ModuleBase { diff --git a/include/Nazara/Graphics/RenderQueueRegistry.hpp b/include/Nazara/Graphics/RenderQueueRegistry.hpp index fe5a75c69..2e97f97c1 100644 --- a/include/Nazara/Graphics/RenderQueueRegistry.hpp +++ b/include/Nazara/Graphics/RenderQueueRegistry.hpp @@ -13,7 +13,6 @@ namespace Nz { - class AbstractBuffer; class MaterialPass; class RenderPipeline; class VertexDeclaration; diff --git a/include/Nazara/Graphics/RenderSpriteChain.hpp b/include/Nazara/Graphics/RenderSpriteChain.hpp index 4604456c1..ff61e01a1 100644 --- a/include/Nazara/Graphics/RenderSpriteChain.hpp +++ b/include/Nazara/Graphics/RenderSpriteChain.hpp @@ -16,7 +16,6 @@ namespace Nz { - class AbstractBuffer; class MaterialPass; class VertexDeclaration; class ViewerInstance; diff --git a/include/Nazara/Graphics/RenderSubmesh.hpp b/include/Nazara/Graphics/RenderSubmesh.hpp index 692e33917..00d80f1bc 100644 --- a/include/Nazara/Graphics/RenderSubmesh.hpp +++ b/include/Nazara/Graphics/RenderSubmesh.hpp @@ -16,7 +16,6 @@ namespace Nz { - class AbstractBuffer; class MaterialPass; class RenderPipeline; class ShaderBinding; diff --git a/include/Nazara/Graphics/SpriteChainRenderer.hpp b/include/Nazara/Graphics/SpriteChainRenderer.hpp index b88059a95..0c1f20b04 100644 --- a/include/Nazara/Graphics/SpriteChainRenderer.hpp +++ b/include/Nazara/Graphics/SpriteChainRenderer.hpp @@ -18,7 +18,6 @@ namespace Nz { - class AbstractBuffer; class RenderDevice; class RenderPipeline; class RenderSpriteChain; diff --git a/include/Nazara/Graphics/SubmeshRenderer.hpp b/include/Nazara/Graphics/SubmeshRenderer.hpp index 407c96004..fd124bc9c 100644 --- a/include/Nazara/Graphics/SubmeshRenderer.hpp +++ b/include/Nazara/Graphics/SubmeshRenderer.hpp @@ -14,7 +14,6 @@ namespace Nz { - class AbstractBuffer; class RenderPipeline; class ShaderBinding; diff --git a/include/Nazara/Graphics/ViewerInstance.hpp b/include/Nazara/Graphics/ViewerInstance.hpp index 8a18a17ae..0a82b709b 100644 --- a/include/Nazara/Graphics/ViewerInstance.hpp +++ b/include/Nazara/Graphics/ViewerInstance.hpp @@ -15,9 +15,9 @@ namespace Nz { - class AbstractBuffer; class CommandBufferBuilder; class MaterialSettings; + class RenderBuffer; class UploadPool; class NAZARA_GRAPHICS_API ViewerInstance diff --git a/include/Nazara/Graphics/WorldInstance.hpp b/include/Nazara/Graphics/WorldInstance.hpp index e43aa3f2b..d3356985e 100644 --- a/include/Nazara/Graphics/WorldInstance.hpp +++ b/include/Nazara/Graphics/WorldInstance.hpp @@ -15,9 +15,9 @@ namespace Nz { - class AbstractBuffer; class CommandBufferBuilder; class MaterialSettings; + class RenderBuffer; class UploadPool; class WorldInstance; diff --git a/include/Nazara/Renderer/Renderer.hpp b/include/Nazara/Renderer/Renderer.hpp index 588963e2c..d5c2628bd 100644 --- a/include/Nazara/Renderer/Renderer.hpp +++ b/include/Nazara/Renderer/Renderer.hpp @@ -17,7 +17,6 @@ namespace Nz { - class AbstractBuffer; class Buffer; class NAZARA_RENDERER_API Renderer : public ModuleBase diff --git a/src/Nazara/Graphics/ForwardFramePipeline.cpp b/src/Nazara/Graphics/ForwardFramePipeline.cpp index 9bac97537..bc187cdc8 100644 --- a/src/Nazara/Graphics/ForwardFramePipeline.cpp +++ b/src/Nazara/Graphics/ForwardFramePipeline.cpp @@ -40,9 +40,7 @@ namespace Nz auto lightOffset = PredefinedLightData::GetOffsets(); - m_lightDataBuffer = Graphics::Instance()->GetRenderDevice()->InstantiateBuffer(BufferType::Uniform); - if (!m_lightDataBuffer->Initialize(lightOffset.totalSize, BufferUsage::DeviceLocal)) - throw std::runtime_error("failed to create light data buffer"); + m_lightDataBuffer = Graphics::Instance()->GetRenderDevice()->InstantiateBuffer(BufferType::Uniform, lightOffset.totalSize, BufferUsage::DeviceLocal | BufferUsage::Write); std::vector staticLightData(lightOffset.totalSize); /*AccessByOffset(staticLightData.data(), lightOffset.lightCountOffset) = 1; From e6951d54a51b5b830f7a3982d38e9d836bcaedaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 26 Jan 2022 19:24:46 +0100 Subject: [PATCH 10/14] Shader: Switch type to type[subtype] --- bin/resources/bloom_bright.nzsl | 52 ++++---- bin/resources/bloom_final.nzsl | 38 +++--- bin/resources/deferred_frag.nzsl | 52 ++++---- bin/resources/deferred_vert.nzsl | 48 +++---- bin/resources/gamma.nzsl | 18 +-- bin/resources/gaussian_blur.nzsl | 42 +++--- bin/resources/god_rays.nzsl | 42 +++--- bin/resources/lighting.nzsl | 56 ++++---- bin/resources/skybox.nzsl | 34 ++--- bin/resources/tone_mapping.nzsl | 40 +++--- examples/DeferredShading/main.cpp | 16 +-- examples/RenderTest/main.cpp | 30 ++--- include/Nazara/Shader/ShaderLangParser.hpp | 1 - .../Resources/Shaders/basic_material.nzsl | 72 +++++------ .../Graphics/Resources/Shaders/blit.nzsl | 14 +- .../Resources/Shaders/depth_material.nzsl | 48 +++---- .../Resources/Shaders/phong_material.nzsl | 122 +++++++++--------- src/Nazara/Shader/Ast/SanitizeVisitor.cpp | 4 +- src/Nazara/Shader/LangWriter.cpp | 18 +-- src/Nazara/Shader/ShaderLangParser.cpp | 77 ++++++----- tests/Engine/Shader/AccessMemberTest.cpp | 4 +- tests/Engine/Shader/Branch.cpp | 6 +- tests/Engine/Shader/Const.cpp | 22 ++-- tests/Engine/Shader/Loops.cpp | 6 +- tests/Engine/Shader/Optimizations.cpp | 26 ++-- tests/Engine/Shader/Sanitizations.cpp | 94 +++++++------- tests/Engine/Shader/Swizzle.cpp | 34 ++--- 27 files changed, 506 insertions(+), 510 deletions(-) diff --git a/bin/resources/bloom_bright.nzsl b/bin/resources/bloom_bright.nzsl index 278ea186c..63aaea8d8 100644 --- a/bin/resources/bloom_bright.nzsl +++ b/bin/resources/bloom_bright.nzsl @@ -1,44 +1,44 @@ [layout(std140)] struct ViewerData { - projectionMatrix: mat4, - invProjectionMatrix: mat4, - viewMatrix: mat4, - invViewMatrix: mat4, - viewProjMatrix: mat4, - invViewProjMatrix: mat4, - renderTargetSize: vec2, - invRenderTargetSize: vec2, - eyePosition: vec3 + projectionMatrix: mat4[f32], + invProjectionMatrix: mat4[f32], + viewMatrix: mat4[f32], + invViewMatrix: mat4[f32], + viewProjMatrix: mat4[f32], + invViewProjMatrix: mat4[f32], + renderTargetSize: vec2[f32], + invRenderTargetSize: vec2[f32], + eyePosition: vec3[f32] } external { - [set(0), binding(0)] viewerData: uniform, - [set(0), binding(1)] colorTexture: sampler2D, + [set(0), binding(0)] viewerData: uniform[ViewerData], + [set(0), binding(1)] colorTexture: sampler2D[f32], } struct FragIn { - [builtin(fragcoord)] fragcoord: vec4, - [location(0)] uv: vec2 + [builtin(fragcoord)] fragcoord: vec4[f32], + [location(0)] uv: vec2[f32] } struct FragOut { - [location(0)] color: vec4 + [location(0)] color: vec4[f32] } struct VertIn { - [location(0)] pos: vec2, - [location(1)] uv: vec2 + [location(0)] pos: vec2[f32], + [location(1)] uv: vec2[f32] } struct VertOut { - [builtin(position)] position: vec4, - [location(0)] uv: vec2 + [builtin(position)] position: vec4[f32], + [location(0)] uv: vec2[f32] } [entry(frag)] @@ -50,19 +50,19 @@ fn main(input: FragIn) -> FragOut let color = colorTexture.Sample(input.uv).rgb; color *= BrightMiddleGrey / BrightLuminance; - color *= vec3(1.0, 1.0, 1.0) + (color / (BrightThreshold*BrightThreshold)); - color -= vec3(0.5, 0.5, 0.5); - color /= vec3(1.0, 1.0, 1.0) + color;*/ + color *= vec3[f32](1.0, 1.0, 1.0) + (color / (BrightThreshold*BrightThreshold)); + color -= vec3[f32](0.5, 0.5, 0.5); + color /= vec3[f32](1.0, 1.0, 1.0) + color;*/ let output: FragOut; - //output.color = vec4(max(color, vec3(0.0, 0.0, 0.0)), 1.0); + //output.color = vec4[f32](max(color, vec3[f32](0.0, 0.0, 0.0)), 1.0); let color = colorTexture.Sample(input.uv).rgb; - let brightness = dot(color, vec3(0.2126, 0.7152, 0.0722)); + let brightness = dot(color, vec3[f32](0.2126, 0.7152, 0.0722)); if (brightness > 1.0) - output.color = vec4(color, 1.0); + output.color = vec4[f32](color, 1.0); else - output.color = vec4(0.0, 0.0, 0.0, 1.0); + output.color = vec4[f32](0.0, 0.0, 0.0, 1.0); return output; } @@ -71,7 +71,7 @@ fn main(input: FragIn) -> FragOut fn main(input: VertIn) -> VertOut { let output: VertOut; - output.position = vec4(input.pos, 0.0, 1.0); + output.position = vec4[f32](input.pos, 0.0, 1.0); output.uv = input.uv; return output; diff --git a/bin/resources/bloom_final.nzsl b/bin/resources/bloom_final.nzsl index 544b5e14f..3b8da880c 100644 --- a/bin/resources/bloom_final.nzsl +++ b/bin/resources/bloom_final.nzsl @@ -1,44 +1,44 @@ [layout(std140)] struct ViewerData { - projectionMatrix: mat4, - invProjectionMatrix: mat4, - viewMatrix: mat4, - invViewMatrix: mat4, - viewProjMatrix: mat4, - invViewProjMatrix: mat4, - renderTargetSize: vec2, - invRenderTargetSize: vec2, - eyePosition: vec3 + projectionMatrix: mat4[f32], + invProjectionMatrix: mat4[f32], + viewMatrix: mat4[f32], + invViewMatrix: mat4[f32], + viewProjMatrix: mat4[f32], + invViewProjMatrix: mat4[f32], + renderTargetSize: vec2[f32], + invRenderTargetSize: vec2[f32], + eyePosition: vec3[f32] } external { - [set(0), binding(0)] viewerData: uniform, - //[set(0), binding(1)] colorTexture: sampler2D, - [set(0), binding(2)] bloomTexture: sampler2D, + [set(0), binding(0)] viewerData: uniform[ViewerData], + //[set(0), binding(1)] colorTexture: sampler2D[f32], + [set(0), binding(2)] bloomTexture: sampler2D[f32], } struct FragIn { - [location(0)] uv: vec2 + [location(0)] uv: vec2[f32] } struct FragOut { - [location(0)] color: vec4 + [location(0)] color: vec4[f32] } struct VertIn { - [location(0)] pos: vec2, - [location(1)] uv: vec2, + [location(0)] pos: vec2[f32], + [location(1)] uv: vec2[f32], } struct VertOut { - [location(0)] uv: vec2, - [builtin(position)] position: vec4 + [location(0)] uv: vec2[f32], + [builtin(position)] position: vec4[f32] } [entry(frag)] @@ -54,7 +54,7 @@ fn main(input: FragIn) -> FragOut fn main(input: VertIn) -> VertOut { let output: VertOut; - output.position = vec4(input.pos, 0.0, 1.0); + output.position = vec4[f32](input.pos, 0.0, 1.0); output.uv = input.uv; return output; diff --git a/bin/resources/deferred_frag.nzsl b/bin/resources/deferred_frag.nzsl index cc4b2f578..7a4e6b554 100644 --- a/bin/resources/deferred_frag.nzsl +++ b/bin/resources/deferred_frag.nzsl @@ -6,52 +6,52 @@ option AlphaTest: bool = false; struct BasicSettings { AlphaThreshold: f32, - DiffuseColor: vec4 + DiffuseColor: vec4[f32] } [layout(std140)] struct InstanceData { - worldMatrix: mat4, - invWorldMatrix: mat4 + worldMatrix: mat4[f32], + invWorldMatrix: mat4[f32] } [layout(std140)] struct ViewerData { - projectionMatrix: mat4, - invProjectionMatrix: mat4, - viewMatrix: mat4, - invViewMatrix: mat4, - viewProjMatrix: mat4, - invViewProjMatrix: mat4, - renderTargetSize: vec2, - invRenderTargetSize: vec2, - eyePosition: vec3 + projectionMatrix: mat4[f32], + invProjectionMatrix: mat4[f32], + viewMatrix: mat4[f32], + invViewMatrix: mat4[f32], + viewProjMatrix: mat4[f32], + invViewProjMatrix: mat4[f32], + renderTargetSize: vec2[f32], + invRenderTargetSize: vec2[f32], + eyePosition: vec3[f32] } external { - [binding(0)] settings: uniform, - [binding(1)] MaterialDiffuseMap: sampler2D, - [binding(2)] MaterialAlphaMap: sampler2D, - [binding(3)] TextureOverlay: sampler2D, - [binding(4)] instanceData: uniform, - [binding(5)] viewerData: uniform, + [binding(0)] settings: uniform[BasicSettings], + [binding(1)] MaterialDiffuseMap: sampler2D[f32], + [binding(2)] MaterialAlphaMap: sampler2D[f32], + [binding(3)] TextureOverlay: sampler2D[f32], + [binding(4)] instanceData: uniform[InstanceData], + [binding(5)] viewerData: uniform[ViewerData], } struct InputData { - [location(0)] normal: vec3, - [location(1)] uv: vec2, - [location(2)] pos: vec3 + [location(0)] normal: vec3[f32], + [location(1)] uv: vec2[f32], + [location(2)] pos: vec3[f32] } struct OutputData { - [location(0)] diffuseMap: vec4, - [location(1)] normalMap: vec4, - [location(2)] positionMap: vec4 + [location(0)] diffuseMap: vec4[f32], + [location(1)] normalMap: vec4[f32], + [location(2)] positionMap: vec4[f32] } [entry(frag)] @@ -72,7 +72,7 @@ fn main(input: InputData) -> OutputData let output: OutputData; output.diffuseMap = diffuseColor; - output.normalMap = vec4((vec3(1.0, 1.0, 1.0) + input.normal) * 0.5, 1.0); - output.positionMap = vec4(input.pos, 1.0); + output.normalMap = vec4[f32]((vec3[f32](1.0, 1.0, 1.0) + input.normal) * 0.5, 1.0); + output.positionMap = vec4[f32](input.pos, 1.0); return output; } diff --git a/bin/resources/deferred_vert.nzsl b/bin/resources/deferred_vert.nzsl index a5abeee63..5d61da5fb 100644 --- a/bin/resources/deferred_vert.nzsl +++ b/bin/resources/deferred_vert.nzsl @@ -2,61 +2,61 @@ struct BasicSettings { AlphaThreshold: f32, - DiffuseColor: vec4 + DiffuseColor: vec4[f32] } [layout(std140)] struct InstanceData { - worldMatrix: mat4, - invWorldMatrix: mat4 + worldMatrix: mat4[f32], + invWorldMatrix: mat4[f32] } [layout(std140)] struct ViewerData { - projectionMatrix: mat4, - invProjectionMatrix: mat4, - viewMatrix: mat4, - invViewMatrix: mat4, - viewProjMatrix: mat4, - invViewProjMatrix: mat4, - renderTargetSize: vec2, - invRenderTargetSize: vec2, - eyePosition: vec3 + projectionMatrix: mat4[f32], + invProjectionMatrix: mat4[f32], + viewMatrix: mat4[f32], + invViewMatrix: mat4[f32], + viewProjMatrix: mat4[f32], + invViewProjMatrix: mat4[f32], + renderTargetSize: vec2[f32], + invRenderTargetSize: vec2[f32], + eyePosition: vec3[f32] } external { - [binding(0)] settings: uniform, - [binding(4)] instanceData: uniform, - [binding(5)] viewerData: uniform, + [binding(0)] settings: uniform[BasicSettings], + [binding(4)] instanceData: uniform[InstanceData], + [binding(5)] viewerData: uniform[ViewerData], } struct InputData { - [location(0)] pos: vec3, - [location(1)] normal: vec3, - [location(2)] uv: vec2 + [location(0)] pos: vec3[f32], + [location(1)] normal: vec3[f32], + [location(2)] uv: vec2[f32] } struct OutputData { - [location(0)] normal: vec3, - [location(1)] uv: vec2, - [location(2)] pos: vec3, - [builtin(position)] position: vec4 + [location(0)] normal: vec3[f32], + [location(1)] uv: vec2[f32], + [location(2)] pos: vec3[f32], + [builtin(position)] position: vec4[f32] } [entry(vert)] fn main(input: InputData) -> OutputData { - let worldPos = instanceData.worldMatrix * vec4(input.pos, 1.0); + let worldPos = instanceData.worldMatrix * vec4[f32](input.pos, 1.0); let output: OutputData; output.uv = input.uv; output.normal = input.normal; output.pos = worldPos.xyz; - output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4(input.pos, 1.0); + output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4[f32](input.pos, 1.0); return output; } diff --git a/bin/resources/gamma.nzsl b/bin/resources/gamma.nzsl index 7db7e075b..ee34a66af 100644 --- a/bin/resources/gamma.nzsl +++ b/bin/resources/gamma.nzsl @@ -1,28 +1,28 @@ external { - [binding(0)] colorTexture: sampler2D + [binding(0)] colorTexture: sampler2D[f32] } struct FragIn { - [location(0)] uv: vec2 + [location(0)] uv: vec2[f32] } struct FragOut { - [location(0)] color: vec4 + [location(0)] color: vec4[f32] } struct VertIn { - [location(0)] pos: vec2, - [location(1)] uv: vec2 + [location(0)] pos: vec2[f32], + [location(1)] uv: vec2[f32] } struct VertOut { - [location(0)] vertUV: vec2, - [builtin(position)] position: vec4 + [location(0)] vertUV: vec2[f32], + [builtin(position)] position: vec4[f32] } [entry(frag)] @@ -32,7 +32,7 @@ fn main(input: FragIn) -> FragOut let output: FragOut; output.color = colorTexture.Sample(input.uv); - //output.color = pow(colorTexture.Sample(input.uv), vec4(1.0 / gamma, 1.0 / gamma, 1.0 / gamma, 1.0)); + //output.color = pow(colorTexture.Sample(input.uv), vec4[f32](1.0 / gamma, 1.0 / gamma, 1.0 / gamma, 1.0)); return output; } @@ -40,7 +40,7 @@ fn main(input: FragIn) -> FragOut fn main(input: VertIn) -> VertOut { let output: VertOut; - output.position = vec4(input.pos, 0.0, 1.0); + output.position = vec4[f32](input.pos, 0.0, 1.0); output.vertUV = input.uv; return output; } diff --git a/bin/resources/gaussian_blur.nzsl b/bin/resources/gaussian_blur.nzsl index 506249a01..4f8323cb5 100644 --- a/bin/resources/gaussian_blur.nzsl +++ b/bin/resources/gaussian_blur.nzsl @@ -1,51 +1,51 @@ [layout(std140)] struct ViewerData { - projectionMatrix: mat4, - invProjectionMatrix: mat4, - viewMatrix: mat4, - invViewMatrix: mat4, - viewProjMatrix: mat4, - invViewProjMatrix: mat4, - renderTargetSize: vec2, - invRenderTargetSize: vec2, - eyePosition: vec3 + projectionMatrix: mat4[f32], + invProjectionMatrix: mat4[f32], + viewMatrix: mat4[f32], + invViewMatrix: mat4[f32], + viewProjMatrix: mat4[f32], + invViewProjMatrix: mat4[f32], + renderTargetSize: vec2[f32], + invRenderTargetSize: vec2[f32], + eyePosition: vec3[f32] } [layout(std140)] struct BlurData { - direction: vec2, + direction: vec2[f32], sizeFactor: f32 } external { - [set(0), binding(0)] viewerData: uniform, - [set(0), binding(1)] colorTexture: sampler2D, - [set(0), binding(2)] blurData: uniform + [set(0), binding(0)] viewerData: uniform[ViewerData], + [set(0), binding(1)] colorTexture: sampler2D[f32], + [set(0), binding(2)] blurData: uniform[BlurData] } struct FragIn { - [location(0)] uv: vec2 + [location(0)] uv: vec2[f32] } struct FragOut { - [location(0)] color: vec4 + [location(0)] color: vec4[f32] } struct VertIn { - [location(0)] pos: vec2, - [location(1)] uv: vec2, + [location(0)] pos: vec2[f32], + [location(1)] uv: vec2[f32], } struct VertOut { - [location(0)] uv: vec2, - [builtin(position)] position: vec4 + [location(0)] uv: vec2[f32], + [builtin(position)] position: vec4[f32] } [entry(frag)] @@ -62,7 +62,7 @@ fn main(input: FragIn) -> FragOut color += colorTexture.Sample(input.uv - blurData.direction * 3.2307692308 * invTargetSize).rgb * 0.0702702703; let output: FragOut; - output.color = vec4(color, 1.0); + output.color = vec4[f32](color, 1.0); return output; } @@ -71,7 +71,7 @@ fn main(input: FragIn) -> FragOut fn main(input: VertIn) -> VertOut { let output: VertOut; - output.position = vec4(input.pos, 0.0, 1.0); + output.position = vec4[f32](input.pos, 0.0, 1.0); output.uv = input.uv; return output; diff --git a/bin/resources/god_rays.nzsl b/bin/resources/god_rays.nzsl index 9ec039bd2..8a88f4fcd 100644 --- a/bin/resources/god_rays.nzsl +++ b/bin/resources/god_rays.nzsl @@ -1,15 +1,15 @@ [layout(std140)] struct ViewerData { - projectionMatrix: mat4, - invProjectionMatrix: mat4, - viewMatrix: mat4, - invViewMatrix: mat4, - viewProjMatrix: mat4, - invViewProjMatrix: mat4, - renderTargetSize: vec2, - invRenderTargetSize: vec2, - eyePosition: vec3 + projectionMatrix: mat4[f32], + invProjectionMatrix: mat4[f32], + viewMatrix: mat4[f32], + invViewMatrix: mat4[f32], + viewProjMatrix: mat4[f32], + invViewProjMatrix: mat4[f32], + renderTargetSize: vec2[f32], + invRenderTargetSize: vec2[f32], + eyePosition: vec3[f32] } [layout(std140)] @@ -19,38 +19,38 @@ struct Settings decay: f32, density: f32, weight: f32, - lightPosition: vec2, //< TODO: Switch to world position + lightPosition: vec2[f32], //< TODO: Switch to world position } const SampleCount: i32 = 200; external { - [set(0), binding(0)] viewerData: uniform, - [set(0), binding(1)] settings: uniform, - [set(0), binding(2)] occluderTexture: sampler2D + [set(0), binding(0)] viewerData: uniform[ViewerData], + [set(0), binding(1)] settings: uniform[Settings], + [set(0), binding(2)] occluderTexture: sampler2D[f32] } struct FragIn { - [location(0)] uv: vec2 + [location(0)] uv: vec2[f32] } struct FragOut { - [location(0)] color: vec4 + [location(0)] color: vec4[f32] } struct VertIn { - [location(0)] pos: vec2, - [location(1)] uv: vec2 + [location(0)] pos: vec2[f32], + [location(1)] uv: vec2[f32] } struct VertOut { - [builtin(position)] position: vec4, - [location(0)] uv: vec2 + [builtin(position)] position: vec4[f32], + [location(0)] uv: vec2[f32] } [entry(frag)] @@ -62,7 +62,7 @@ fn main(input: FragIn) -> FragOut let uv = input.uv; - let outputColor = vec4(0.0, 0.0, 0.0, 1.0); + let outputColor = vec4[f32](0.0, 0.0, 0.0, 1.0); for i in 0 -> SampleCount { @@ -85,7 +85,7 @@ fn main(input: FragIn) -> FragOut fn main(input: VertIn) -> VertOut { let output: VertOut; - output.position = vec4(input.pos, 0.0, 1.0); + output.position = vec4[f32](input.pos, 0.0, 1.0); output.uv = input.uv; return output; diff --git a/bin/resources/lighting.nzsl b/bin/resources/lighting.nzsl index 74ee4da40..71c1c819d 100644 --- a/bin/resources/lighting.nzsl +++ b/bin/resources/lighting.nzsl @@ -1,8 +1,8 @@ [layout(std140)] struct PointLight { - color: vec3, - position: vec3, + color: vec3[f32], + position: vec3[f32], radius: f32, invRadius: f32, @@ -11,11 +11,11 @@ struct PointLight [layout(std140)] struct SpotLight { - transformMatrix: mat4, + transformMatrix: mat4[f32], - color: vec3, - position: vec3, - direction: vec3, + color: vec3[f32], + position: vec3[f32], + direction: vec3[f32], radius: f32, invRadius: f32, @@ -27,63 +27,63 @@ struct SpotLight [layout(std140)] struct ViewerData { - projectionMatrix: mat4, - invProjectionMatrix: mat4, - viewMatrix: mat4, - invViewMatrix: mat4, - viewProjMatrix: mat4, - invViewProjMatrix: mat4, - renderTargetSize: vec2, - invRenderTargetSize: vec2, - eyePosition: vec3 + projectionMatrix: mat4[f32], + invProjectionMatrix: mat4[f32], + viewMatrix: mat4[f32], + invViewMatrix: mat4[f32], + viewProjMatrix: mat4[f32], + invViewProjMatrix: mat4[f32], + renderTargetSize: vec2[f32], + invRenderTargetSize: vec2[f32], + eyePosition: vec3[f32] } [set(0)] external { - [binding(0)] viewerData: uniform, - [binding(1)] colorTexture: sampler2D, - [binding(2)] normalTexture: sampler2D, - [binding(3)] positionTexture: sampler2D, + [binding(0)] viewerData: uniform[ViewerData], + [binding(1)] colorTexture: sampler2D[f32], + [binding(2)] normalTexture: sampler2D[f32], + [binding(3)] positionTexture: sampler2D[f32], } [set(1)] external { - [binding(0)] lightParameters: uniform, + [binding(0)] lightParameters: uniform[SpotLight], } struct FragIn { - [builtin(fragcoord)] fragcoord: vec4 + [builtin(fragcoord)] fragcoord: vec4[f32] } struct FragOut { - [location(0)] color: vec4 + [location(0)] color: vec4[f32] } struct VertIn { - [location(0)] pos: vec3 + [location(0)] pos: vec3[f32] } struct VertOut { - [builtin(position)] position: vec4 + [builtin(position)] position: vec4[f32] } [entry(frag)] fn main(input: FragIn) -> FragOut { let fragcoord = input.fragcoord.xy * viewerData.invRenderTargetSize; - let normal = normalTexture.Sample(fragcoord).xyz * 2.0 - vec3(1.0, 1.0, 1.0); + let normal = normalTexture.Sample(fragcoord).xyz * 2.0 - vec3[f32](1.0, 1.0, 1.0); let position = positionTexture.Sample(fragcoord).xyz; let attenuation = compute_attenuation(position, normal); let output: FragOut; - output.color = vec4(lightParameters.color, 1.0) * attenuation * colorTexture.Sample(fragcoord); + output.color = vec4[f32](lightParameters.color, 1.0) * attenuation * colorTexture.Sample(fragcoord); return output; } @@ -92,12 +92,12 @@ fn main(input: FragIn) -> FragOut fn main(input: VertIn) -> VertOut { let output: VertOut; - output.position = viewerData.projectionMatrix * viewerData.viewMatrix * lightParameters.transformMatrix * vec4(input.pos, 1.0); + output.position = viewerData.projectionMatrix * viewerData.viewMatrix * lightParameters.transformMatrix * vec4[f32](input.pos, 1.0); return output; } -fn compute_attenuation(worldPos: vec3, normal: vec3) -> f32 +fn compute_attenuation(worldPos: vec3[f32], normal: vec3[f32]) -> f32 { let distance = length(lightParameters.position - worldPos); diff --git a/bin/resources/skybox.nzsl b/bin/resources/skybox.nzsl index 93dc98872..72acb51d0 100644 --- a/bin/resources/skybox.nzsl +++ b/bin/resources/skybox.nzsl @@ -1,32 +1,32 @@ [layout(std140)] struct ViewerData { - projectionMatrix: mat4, - invProjectionMatrix: mat4, - viewMatrix: mat4, - invViewMatrix: mat4, - viewProjMatrix: mat4, - invViewProjMatrix: mat4, - renderTargetSize: vec2, - invRenderTargetSize: vec2, - eyePosition: vec3 + projectionMatrix: mat4[f32], + invProjectionMatrix: mat4[f32], + viewMatrix: mat4[f32], + invViewMatrix: mat4[f32], + viewProjMatrix: mat4[f32], + invViewProjMatrix: mat4[f32], + renderTargetSize: vec2[f32], + invRenderTargetSize: vec2[f32], + eyePosition: vec3[f32] } external { - [binding(0)] viewerData: uniform, - [binding(1)] skybox: samplerCube + [binding(0)] viewerData: uniform[ViewerData], + [binding(1)] skybox: samplerCube[f32] } struct VertOut { - [location(0)] uvw: vec3, - [builtin(position)] position: vec4 + [location(0)] uvw: vec3[f32], + [builtin(position)] position: vec4[f32] } struct FragOut { - [location(0)] color: vec4, + [location(0)] color: vec4[f32], [builtin(fragdepth)] depth: f32 } @@ -43,7 +43,7 @@ fn main(input: VertOut) -> FragOut struct VertIn { - [location(0)] position: vec3 + [location(0)] position: vec3[f32] } [entry(vert)] @@ -51,10 +51,10 @@ fn main(input: VertIn) -> VertOut { // Set translation part to zero let rotationMat = viewerData.viewMatrix; - rotationMat[3].xyz = vec3(0.0, 0.0, 0.0); + rotationMat[3].xyz = vec3[f32](0.0, 0.0, 0.0); let output: VertOut; - output.position = viewerData.projectionMatrix * rotationMat * vec4(input.position, 1.0); + output.position = viewerData.projectionMatrix * rotationMat * vec4[f32](input.position, 1.0); output.uvw = input.position.xyz; return output; diff --git a/bin/resources/tone_mapping.nzsl b/bin/resources/tone_mapping.nzsl index ccb35c0fe..6f9aac1d1 100644 --- a/bin/resources/tone_mapping.nzsl +++ b/bin/resources/tone_mapping.nzsl @@ -1,43 +1,43 @@ [layout(std140)] struct ViewerData { - projectionMatrix: mat4, - invProjectionMatrix: mat4, - viewMatrix: mat4, - invViewMatrix: mat4, - viewProjMatrix: mat4, - invViewProjMatrix: mat4, - renderTargetSize: vec2, - invRenderTargetSize: vec2, - eyePosition: vec3 + projectionMatrix: mat4[f32], + invProjectionMatrix: mat4[f32], + viewMatrix: mat4[f32], + invViewMatrix: mat4[f32], + viewProjMatrix: mat4[f32], + invViewProjMatrix: mat4[f32], + renderTargetSize: vec2[f32], + invRenderTargetSize: vec2[f32], + eyePosition: vec3[f32] } external { - [set(0), binding(0)] viewerData: uniform, - [set(0), binding(1)] inputTexture: sampler2D + [set(0), binding(0)] viewerData: uniform[ViewerData], + [set(0), binding(1)] inputTexture: sampler2D[f32] } struct FragIn { - [location(0)] uv: vec2, + [location(0)] uv: vec2[f32], } struct FragOut { - [location(0)] color: vec4 + [location(0)] color: vec4[f32] } struct VertIn { - [location(0)] pos: vec2, - [location(1)] uv: vec2, + [location(0)] pos: vec2[f32], + [location(1)] uv: vec2[f32], } struct VertOut { - [location(0)] uv: vec2, - [builtin(position)] position: vec4 + [location(0)] uv: vec2[f32], + [builtin(position)] position: vec4[f32] } [entry(frag)] @@ -48,10 +48,10 @@ fn main(input: FragIn) -> FragOut let hdrColor = inputTexture.Sample(input.uv).rgb; // reinhard tone mapping - let mapped = vec3(1.0, 1.0, 1.0) - exp(-hdrColor * exposure); + let mapped = vec3[f32](1.0, 1.0, 1.0) - exp(-hdrColor * exposure); let output: FragOut; - output.color = vec4(mapped, 1.0); + output.color = vec4[f32](mapped, 1.0); return output; } @@ -60,7 +60,7 @@ fn main(input: FragIn) -> FragOut fn main(input: VertIn) -> VertOut { let output: VertOut; - output.position = vec4(input.pos, 0.0, 1.0); + output.position = vec4[f32](input.pos, 0.0, 1.0); output.uv = input.uv; return output; diff --git a/examples/DeferredShading/main.cpp b/examples/DeferredShading/main.cpp index e64af4b0d..8185568ab 100644 --- a/examples/DeferredShading/main.cpp +++ b/examples/DeferredShading/main.cpp @@ -17,8 +17,8 @@ constexpr std::size_t BloomSubdivisionCount = 5; [layout(std140)] struct PointLight { - color: vec3, - position: vec3, + color: vec3[f32], + position: vec3[f32], constant: f32, linear: f32, @@ -28,9 +28,9 @@ struct PointLight [layout(std140)] struct SpotLight { - color: vec3, - position: vec3, - direction: vec3, + color: vec3[f32], + position: vec3[f32], + direction: vec3[f32], constant: f32, linear: f32, @@ -299,9 +299,9 @@ int main() [layout(std140)] struct SpotLight { - color: vec3, - position: vec3, - direction: vec3, + color: vec3[f32], + position: vec3[f32], + direction: vec3[f32], constant: f32, linear: f32, diff --git a/examples/RenderTest/main.cpp b/examples/RenderTest/main.cpp index 8f3873bd5..594455d36 100644 --- a/examples/RenderTest/main.cpp +++ b/examples/RenderTest/main.cpp @@ -17,50 +17,50 @@ option red: bool = false; [layout(std140)] struct Data { - projectionMatrix: mat4, - worldMatrix: mat4, - viewMatrix: mat4 + projectionMatrix: mat4[f32], + worldMatrix: mat4[f32], + viewMatrix: mat4[f32] } [set(0)] external { - [binding(0)] viewerData: uniform, + [binding(0)] viewerData: uniform[Data], } [set(1)] external { - [binding(0)] tex: sampler2D + [binding(0)] tex: sampler2D[f32] } struct VertIn { - [location(0)] position: vec3, - [location(1)] normal: vec3, - [location(2)] uv: vec2 + [location(0)] position: vec3[f32], + [location(1)] normal: vec3[f32], + [location(2)] uv: vec2[f32] } struct VertOut { - [builtin(position)] position: vec4, - [location(0)] normal: vec3, - [location(1)] uv: vec2 + [builtin(position)] position: vec4[f32], + [location(0)] normal: vec3[f32], + [location(1)] uv: vec2[f32] } struct FragOut { - [location(0)] color: vec4 + [location(0)] color: vec4[f32] } [entry(frag)] fn main(fragIn: VertOut) -> FragOut { - let lightDir = vec3(0.0, 0.707, 0.707); + let lightDir = vec3[f32](0.0, 0.707, 0.707); let lightFactor = dot(fragIn.normal, lightDir); let fragOut: FragOut; - fragOut.color = lightFactor * tex.Sample(fragIn.uv) * const_select(red, vec4(1.0, 0.0, 0.0, 1.0), vec4(1.0, 1.0, 1.0, 1.0)); + fragOut.color = lightFactor * tex.Sample(fragIn.uv) * const_select(red, vec4[f32](1.0, 0.0, 0.0, 1.0), vec4[f32](1.0, 1.0, 1.0, 1.0)); return fragOut; } @@ -69,7 +69,7 @@ fn main(fragIn: VertOut) -> FragOut fn main(vertIn: VertIn) -> VertOut { let vertOut: VertOut; - vertOut.position = viewerData.projectionMatrix * viewerData.viewMatrix * viewerData.worldMatrix * vec4(vertIn.position, 1.0); + vertOut.position = viewerData.projectionMatrix * viewerData.viewMatrix * viewerData.worldMatrix * vec4[f32](vertIn.position, 1.0); vertOut.normal = vertIn.normal; vertOut.uv = vertIn.uv; diff --git a/include/Nazara/Shader/ShaderLangParser.hpp b/include/Nazara/Shader/ShaderLangParser.hpp index 0133967bc..c69c505fa 100644 --- a/include/Nazara/Shader/ShaderLangParser.hpp +++ b/include/Nazara/Shader/ShaderLangParser.hpp @@ -113,7 +113,6 @@ namespace Nz::ShaderLang ShaderAst::ExpressionPtr ParsePrimaryExpression(); ShaderAst::ExpressionPtr ParseVariableAssignation(); - ShaderAst::ExpressionType ParseArrayType(); ShaderAst::AttributeType ParseIdentifierAsAttributeType(); const std::string& ParseIdentifierAsName(); ShaderAst::PrimitiveType ParsePrimitiveType(); diff --git a/src/Nazara/Graphics/Resources/Shaders/basic_material.nzsl b/src/Nazara/Graphics/Resources/Shaders/basic_material.nzsl index 114956a74..a26d2358a 100644 --- a/src/Nazara/Graphics/Resources/Shaders/basic_material.nzsl +++ b/src/Nazara/Graphics/Resources/Shaders/basic_material.nzsl @@ -21,50 +21,50 @@ const HasUV = (UvLocation >= 0); struct MaterialSettings { AlphaThreshold: f32, - DiffuseColor: vec4 + DiffuseColor: vec4[f32] } [layout(std140)] struct InstanceData { - worldMatrix: mat4, - invWorldMatrix: mat4 + worldMatrix: mat4[f32], + invWorldMatrix: mat4[f32] } [layout(std140)] struct ViewerData { - projectionMatrix: mat4, - invProjectionMatrix: mat4, - viewMatrix: mat4, - invViewMatrix: mat4, - viewProjMatrix: mat4, - invViewProjMatrix: mat4, - renderTargetSize: vec2, - invRenderTargetSize: vec2, - eyePosition: vec3 + projectionMatrix: mat4[f32], + invProjectionMatrix: mat4[f32], + viewMatrix: mat4[f32], + invViewMatrix: mat4[f32], + viewProjMatrix: mat4[f32], + invViewProjMatrix: mat4[f32], + renderTargetSize: vec2[f32], + invRenderTargetSize: vec2[f32], + eyePosition: vec3[f32] } external { - [binding(0)] settings: uniform, - [binding(1)] MaterialDiffuseMap: sampler2D, - [binding(2)] MaterialAlphaMap: sampler2D, - [binding(3)] TextureOverlay: sampler2D, - [binding(4)] instanceData: uniform, - [binding(5)] viewerData: uniform, + [binding(0)] settings: uniform[MaterialSettings], + [binding(1)] MaterialDiffuseMap: sampler2D[f32], + [binding(2)] MaterialAlphaMap: sampler2D[f32], + [binding(3)] TextureOverlay: sampler2D[f32], + [binding(4)] instanceData: uniform[InstanceData], + [binding(5)] viewerData: uniform[ViewerData], } // Fragment stage struct FragIn { - [location(0), cond(HasUV)] uv: vec2, - [location(1), cond(HasColor)] color: vec4 + [location(0), cond(HasUV)] uv: vec2[f32], + [location(1), cond(HasColor)] color: vec4[f32] } struct FragOut { - [location(0)] RenderTarget0: vec4 + [location(0)] RenderTarget0: vec4[f32] } [entry(frag)] @@ -99,29 +99,29 @@ fn main(input: FragIn) -> FragOut struct VertIn { [location(PosLocation)] - pos: vec3, + pos: vec3[f32], [cond(HasVertexColor), location(ColorLocation)] - color: vec4, + color: vec4[f32], [cond(HasUV), location(UvLocation)] - uv: vec2, + uv: vec2[f32], [cond(Billboard), location(BillboardCenterLocation)] - billboardCenter: vec3, + billboardCenter: vec3[f32], [cond(Billboard), location(BillboardSizeRotLocation)] - billboardSizeRot: vec4, //< width,height,sin,cos + billboardSizeRot: vec4[f32], //< width,height,sin,cos [cond(Billboard), location(BillboardColorLocation)] - billboardColor: vec4 + billboardColor: vec4[f32] } struct VertOut { - [location(0), cond(HasUV)] uv: vec2, - [location(1), cond(HasColor)] color: vec4, - [builtin(position)] position: vec4 + [location(0), cond(HasUV)] uv: vec2[f32], + [location(1), cond(HasColor)] color: vec4[f32], + [builtin(position)] position: vec4[f32] } [entry(vert), cond(Billboard)] @@ -130,27 +130,27 @@ fn billboardMain(input: VertIn) -> VertOut let size = input.billboardSizeRot.xy; let sinCos = input.billboardSizeRot.zw; - let rotatedPosition = vec2( + let rotatedPosition = vec2[f32]( input.pos.x * sinCos.y - input.pos.y * sinCos.x, input.pos.y * sinCos.y + input.pos.x * sinCos.x ); rotatedPosition *= size; - let cameraRight = vec3(viewerData.viewMatrix[0][0], viewerData.viewMatrix[1][0], viewerData.viewMatrix[2][0]); - let cameraUp = vec3(viewerData.viewMatrix[0][1], viewerData.viewMatrix[1][1], viewerData.viewMatrix[2][1]); + let cameraRight = vec3[f32](viewerData.viewMatrix[0][0], viewerData.viewMatrix[1][0], viewerData.viewMatrix[2][0]); + let cameraUp = vec3[f32](viewerData.viewMatrix[0][1], viewerData.viewMatrix[1][1], viewerData.viewMatrix[2][1]); let vertexPos = input.billboardCenter; vertexPos += cameraRight * rotatedPosition.x; vertexPos += cameraUp * rotatedPosition.y; let output: VertOut; - output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4(vertexPos, 1.0); + output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4[f32](vertexPos, 1.0); const if (HasColor) output.color = input.billboardColor; const if (HasUV) - output.uv = input.pos.xy + vec2(0.5, 0.5); + output.uv = input.pos.xy + vec2[f32](0.5, 0.5); return output; } @@ -159,7 +159,7 @@ fn billboardMain(input: VertIn) -> VertOut fn main(input: VertIn) -> VertOut { let output: VertOut; - output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4(input.pos, 1.0); + output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4[f32](input.pos, 1.0); const if (HasColor) output.color = input.color; diff --git a/src/Nazara/Graphics/Resources/Shaders/blit.nzsl b/src/Nazara/Graphics/Resources/Shaders/blit.nzsl index 4b14dbd9d..c934a5728 100644 --- a/src/Nazara/Graphics/Resources/Shaders/blit.nzsl +++ b/src/Nazara/Graphics/Resources/Shaders/blit.nzsl @@ -1,25 +1,25 @@ external { - [binding(0)] texture: sampler2D + [binding(0)] texture: sampler2D[f32] } struct VertIn { - [location(0)] position: vec2, - [location(1)] uv: vec2 + [location(0)] position: vec2[f32], + [location(1)] uv: vec2[f32] } struct VertOut { - [builtin(position)] position: vec4, - [location(0)] uv: vec2 + [builtin(position)] position: vec4[f32], + [location(0)] uv: vec2[f32] } [entry(vert)] fn main(vertIn: VertIn) -> VertOut { let output: VertOut; - output.position = vec4(vertIn.position, 0.0, 1.0); + output.position = vec4[f32](vertIn.position, 0.0, 1.0); output.uv = vertIn.uv; return output; @@ -27,7 +27,7 @@ fn main(vertIn: VertIn) -> VertOut struct FragOut { - [location(0)] color: vec4 + [location(0)] color: vec4[f32] } [entry(frag)] diff --git a/src/Nazara/Graphics/Resources/Shaders/depth_material.nzsl b/src/Nazara/Graphics/Resources/Shaders/depth_material.nzsl index 9d2ed0a30..7cbb80bef 100644 --- a/src/Nazara/Graphics/Resources/Shaders/depth_material.nzsl +++ b/src/Nazara/Graphics/Resources/Shaders/depth_material.nzsl @@ -8,44 +8,44 @@ const HasUV = AlphaTest && (HasDiffuseTexture || HasAlphaTexture); struct BasicSettings { AlphaThreshold: f32, - DiffuseColor: vec4 + DiffuseColor: vec4[f32] } [layout(std140)] struct InstanceData { - worldMatrix: mat4, - invWorldMatrix: mat4 + worldMatrix: mat4[f32], + invWorldMatrix: mat4[f32] } [layout(std140)] struct ViewerData { - projectionMatrix: mat4, - invProjectionMatrix: mat4, - viewMatrix: mat4, - invViewMatrix: mat4, - viewProjMatrix: mat4, - invViewProjMatrix: mat4, - renderTargetSize: vec2, - invRenderTargetSize: vec2, - eyePosition: vec3 + projectionMatrix: mat4[f32], + invProjectionMatrix: mat4[f32], + viewMatrix: mat4[f32], + invViewMatrix: mat4[f32], + viewProjMatrix: mat4[f32], + invViewProjMatrix: mat4[f32], + renderTargetSize: vec2[f32], + invRenderTargetSize: vec2[f32], + eyePosition: vec3[f32] } external { - [binding(0)] settings: uniform, - [binding(1)] MaterialDiffuseMap: sampler2D, - [binding(2)] MaterialAlphaMap: sampler2D, - [binding(3)] TextureOverlay: sampler2D, - [binding(4)] instanceData: uniform, - [binding(5)] viewerData: uniform, + [binding(0)] settings: uniform[BasicSettings], + [binding(1)] MaterialDiffuseMap: sampler2D[f32], + [binding(2)] MaterialAlphaMap: sampler2D[f32], + [binding(3)] TextureOverlay: sampler2D[f32], + [binding(4)] instanceData: uniform[InstanceData], + [binding(5)] viewerData: uniform[ViewerData], } // Fragment stage struct FragIn { - [location(0), cond(HasUV)] uv: vec2 + [location(0), cond(HasUV)] uv: vec2[f32] } [entry(frag), cond(AlphaTest)] @@ -73,21 +73,21 @@ fn main() {} // Vertex stage struct VertIn { - [location(0)] pos: vec3, - [location(1), cond(HasUV)] uv: vec2 + [location(0)] pos: vec3[f32], + [location(1), cond(HasUV)] uv: vec2[f32] } struct VertOut { - [location(0), cond(HasUV)] uv: vec2, - [builtin(position)] position: vec4 + [location(0), cond(HasUV)] uv: vec2[f32], + [builtin(position)] position: vec4[f32] } [entry(vert)] fn main(input: VertIn) -> VertOut { let output: VertOut; - output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4(input.pos, 1.0); + output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4[f32](input.pos, 1.0); const if (HasUV) output.uv = input.uv; diff --git a/src/Nazara/Graphics/Resources/Shaders/phong_material.nzsl b/src/Nazara/Graphics/Resources/Shaders/phong_material.nzsl index 6328ec0f9..ce623ab78 100644 --- a/src/Nazara/Graphics/Resources/Shaders/phong_material.nzsl +++ b/src/Nazara/Graphics/Resources/Shaders/phong_material.nzsl @@ -36,19 +36,19 @@ struct MaterialSettings { // BasicSettings AlphaThreshold: f32, - DiffuseColor: vec4, + DiffuseColor: vec4[f32], // PhongSettings - AmbientColor: vec3, - SpecularColor: vec3, + AmbientColor: vec3[f32], + SpecularColor: vec3[f32], Shininess: f32, } [layout(std140)] struct InstanceData { - worldMatrix: mat4, - invWorldMatrix: mat4 + worldMatrix: mat4[f32], + invWorldMatrix: mat4[f32] } // TODO: Add enums @@ -60,64 +60,64 @@ const SpotLight = 2; struct Light { type: i32, - color: vec4, - factor: vec2, - parameter1: vec4, - parameter2: vec4, - parameter3: vec4, - hasShadowMapping: bool + color: vec4[f32], + factor: vec2[f32], + parameter1: vec4[f32], + parameter2: vec4[f32], + parameter3: vec4[f32], + hasShadowMapping: u32 } [layout(std140)] struct LightData { - lights: [Light; MaxLightCount], - lightCount: u32, + lights: array[Light, MaxLightCount], + lightCount: u32 } [layout(std140)] struct ViewerData { - projectionMatrix: mat4, - invProjectionMatrix: mat4, - viewMatrix: mat4, - invViewMatrix: mat4, - viewProjMatrix: mat4, - invViewProjMatrix: mat4, - renderTargetSize: vec2, - invRenderTargetSize: vec2, - eyePosition: vec3 + projectionMatrix: mat4[f32], + invProjectionMatrix: mat4[f32], + viewMatrix: mat4[f32], + invViewMatrix: mat4[f32], + viewProjMatrix: mat4[f32], + invViewProjMatrix: mat4[f32], + renderTargetSize: vec2[f32], + invRenderTargetSize: vec2[f32], + eyePosition: vec3[f32] } external { - [binding(0)] settings: uniform, - [binding(1)] MaterialDiffuseMap: sampler2D, - [binding(2)] MaterialAlphaMap: sampler2D, - [binding(3)] TextureOverlay: sampler2D, - [binding(4)] instanceData: uniform, - [binding(5)] viewerData: uniform, - [binding(6)] lightData: uniform, - [binding(7)] MaterialEmissiveMap: sampler2D, - [binding(8)] MaterialHeightMap: sampler2D, - [binding(9)] MaterialNormalMap: sampler2D, - [binding(10)] MaterialSpecularMap: sampler2D, + [binding(0)] settings: uniform[MaterialSettings], + [binding(1)] MaterialDiffuseMap: sampler2D[f32], + [binding(2)] MaterialAlphaMap: sampler2D[f32], + [binding(3)] TextureOverlay: sampler2D[f32], + [binding(4)] instanceData: uniform[InstanceData], + [binding(5)] viewerData: uniform[ViewerData], + [binding(6)] lightData: uniform[LightData], + [binding(7)] MaterialEmissiveMap: sampler2D[f32], + [binding(8)] MaterialHeightMap: sampler2D[f32], + [binding(9)] MaterialNormalMap: sampler2D[f32], + [binding(10)] MaterialSpecularMap: sampler2D[f32], } struct VertToFrag { - [location(0)] worldPos: vec3, - [location(1), cond(HasUV)] uv: vec2, - [location(2), cond(HasColor)] color: vec4, - [location(3), cond(HasNormal)] normal: vec3, - [location(4), cond(HasNormalMapping)] tbnMatrix: mat3, - [builtin(position)] position: vec4, + [location(0)] worldPos: vec3[f32], + [location(1), cond(HasUV)] uv: vec2[f32], + [location(2), cond(HasColor)] color: vec4[f32], + [location(3), cond(HasNormal)] normal: vec3[f32], + [location(4), cond(HasNormalMapping)] tbnMatrix: mat3[f32], + [builtin(position)] position: vec4[f32], } // Fragment stage struct FragOut { - [location(0)] RenderTarget0: vec4 + [location(0)] RenderTarget0: vec4[f32] } [entry(frag)] @@ -145,15 +145,15 @@ fn main(input: VertToFrag) -> FragOut const if (HasNormal) { - let lightAmbient = vec3(0.0, 0.0, 0.0); - let lightDiffuse = vec3(0.0, 0.0, 0.0); - let lightSpecular = vec3(0.0, 0.0, 0.0); + let lightAmbient = vec3[f32](0.0, 0.0, 0.0); + let lightDiffuse = vec3[f32](0.0, 0.0, 0.0); + let lightSpecular = vec3[f32](0.0, 0.0, 0.0); let eyeVec = normalize(viewerData.eyePosition - input.worldPos); - let normal: vec3; + let normal: vec3[f32]; const if (HasNormalMapping) - normal = normalize(input.tbnMatrix * (MaterialNormalMap.Sample(input.uv).xyz * 2.0 - vec3(1.0, 1.0, 1.0))); + normal = normalize(input.tbnMatrix * (MaterialNormalMap.Sample(input.uv).xyz * 2.0 - vec3[f32](1.0, 1.0, 1.0))); else normal = normalize(input.normal); @@ -244,7 +244,7 @@ fn main(input: VertToFrag) -> FragOut let lightColor = lightAmbient + lightDiffuse + lightSpecular; let output: FragOut; - output.RenderTarget0 = vec4(lightColor, 1.0) * diffuseColor; + output.RenderTarget0 = vec4[f32](lightColor, 1.0) * diffuseColor; return output; } else @@ -259,28 +259,28 @@ fn main(input: VertToFrag) -> FragOut struct VertIn { [location(PosLocation)] - pos: vec3, + pos: vec3[f32], [cond(HasVertexColor), location(ColorLocation)] - color: vec4, + color: vec4[f32], [cond(HasUV), location(UvLocation)] - uv: vec2, + uv: vec2[f32], [cond(HasNormal), location(NormalLocation)] - normal: vec3, + normal: vec3[f32], [cond(HasTangent), location(TangentLocation)] - tangent: vec3, + tangent: vec3[f32], [cond(Billboard), location(BillboardCenterLocation)] - billboardCenter: vec3, + billboardCenter: vec3[f32], [cond(Billboard), location(BillboardSizeRotLocation)] - billboardSizeRot: vec4, //< width,height,sin,cos + billboardSizeRot: vec4[f32], //< width,height,sin,cos [cond(Billboard), location(BillboardColorLocation)] - billboardColor: vec4 + billboardColor: vec4[f32] } [entry(vert), cond(Billboard)] @@ -289,27 +289,27 @@ fn billboardMain(input: VertIn) -> VertOut let size = input.billboardSizeRot.xy; let sinCos = input.billboardSizeRot.zw; - let rotatedPosition = vec2( + let rotatedPosition = vec2[f32]( input.pos.x * sinCos.y - input.pos.y * sinCos.x, input.pos.y * sinCos.y + input.pos.x * sinCos.x ); rotatedPosition *= size; - let cameraRight = vec3(viewerData.viewMatrix[0][0], viewerData.viewMatrix[1][0], viewerData.viewMatrix[2][0]); - let cameraUp = vec3(viewerData.viewMatrix[0][1], viewerData.viewMatrix[1][1], viewerData.viewMatrix[2][1]); + let cameraRight = vec3[f32](viewerData.viewMatrix[0][0], viewerData.viewMatrix[1][0], viewerData.viewMatrix[2][0]); + let cameraUp = vec3[f32](viewerData.viewMatrix[0][1], viewerData.viewMatrix[1][1], viewerData.viewMatrix[2][1]); let vertexPos = input.billboardCenter; vertexPos += cameraRight * rotatedPosition.x; vertexPos += cameraUp * rotatedPosition.y; let output: VertToFrag; - output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4(vertexPos, 1.0); + output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4[f32](vertexPos, 1.0); const if (HasColor) output.color = input.billboardColor; const if (HasUV) - output.uv = input.pos.xy + vec2(0.5, 0.5); + output.uv = input.pos.xy + vec2[f32](0.5, 0.5); return output; } @@ -317,13 +317,13 @@ fn billboardMain(input: VertIn) -> VertOut [entry(vert), cond(!Billboard)] fn main(input: VertIn) -> VertToFrag { - let worldPosition = instanceData.worldMatrix * vec4(input.pos, 1.0); + let worldPosition = instanceData.worldMatrix * vec4[f32](input.pos, 1.0); let output: VertToFrag; output.worldPos = worldPosition.xyz; output.position = viewerData.viewProjMatrix * worldPosition; - let rotationMatrix = mat3(instanceData.worldMatrix); + let rotationMatrix = mat3[f32](instanceData.worldMatrix); const if (HasColor) output.color = input.color; diff --git a/src/Nazara/Shader/Ast/SanitizeVisitor.cpp b/src/Nazara/Shader/Ast/SanitizeVisitor.cpp index 448075fb5..c4dd366f7 100644 --- a/src/Nazara/Shader/Ast/SanitizeVisitor.cpp +++ b/src/Nazara/Shader/Ast/SanitizeVisitor.cpp @@ -431,7 +431,7 @@ namespace Nz::ShaderAst vectorComponentCount = std::get(GetExpressionType(*vectorExpr)).componentCount; } - // cast expression (turn fromMatrix[i] to vec3(fromMatrix[i])) + // cast expression (turn fromMatrix[i] to vec3[f32](fromMatrix[i])) ExpressionPtr castExpr; if (vectorComponentCount != targetMatrixType.rowCount) { @@ -1967,7 +1967,7 @@ namespace Nz::ShaderAst { const ExpressionType& type = GetExpressionType(*node.parameters.front()); if (type != ExpressionType{ VectorType{ 3, PrimitiveType::Float32 } }) - throw AstError{ "CrossProduct only works with vec3 expressions" }; + throw AstError{ "CrossProduct only works with vec3[f32] expressions" }; node.cachedExpressionType = type; break; diff --git a/src/Nazara/Shader/LangWriter.cpp b/src/Nazara/Shader/LangWriter.cpp index 65cb60bd5..4646bc6ad 100644 --- a/src/Nazara/Shader/LangWriter.cpp +++ b/src/Nazara/Shader/LangWriter.cpp @@ -126,7 +126,7 @@ namespace Nz void LangWriter::Append(const ShaderAst::ArrayType& type) { - Append("[", type.containedType->type, "; "); + Append("array[", type.containedType->type, ", "); if (type.length.IsResultingValue()) Append(type.length.GetResultingValue()); @@ -164,7 +164,7 @@ namespace Nz Append(matrixType.rowCount); } - Append("<", matrixType.type, ">"); + Append("[", matrixType.type, "]"); } void LangWriter::Append(ShaderAst::PrimitiveType type) @@ -192,7 +192,7 @@ namespace Nz case ImageType::Cubemap: Append("Cube"); break; } - Append("<", samplerType.sampledType, ">"); + Append("[", samplerType.sampledType, "]"); } void LangWriter::Append(const ShaderAst::StructType& structType) @@ -203,17 +203,17 @@ namespace Nz void LangWriter::Append(const ShaderAst::UniformType& uniformType) { - Append("uniform<"); + Append("uniform["); std::visit([&](auto&& arg) { Append(arg); }, uniformType.containedType); - Append(">"); + Append("]"); } void LangWriter::Append(const ShaderAst::VectorType& vecType) { - Append("vec", vecType.componentCount, "<", vecType.type, ">"); + Append("vec", vecType.componentCount, "[", vecType.type, "]"); } void LangWriter::Append(ShaderAst::NoType) @@ -732,15 +732,15 @@ namespace Nz else if constexpr (std::is_same_v || std::is_same_v || std::is_same_v) Append(std::to_string(arg)); else if constexpr (std::is_same_v) - Append("vec2(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ")"); + Append("vec2[f32](" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ")"); else if constexpr (std::is_same_v) Append("vec2(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ")"); else if constexpr (std::is_same_v) - Append("vec3(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ", " + std::to_string(arg.z) + ")"); + Append("vec3[f32](" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ", " + std::to_string(arg.z) + ")"); else if constexpr (std::is_same_v) Append("vec3(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ", " + std::to_string(arg.z) + ")"); else if constexpr (std::is_same_v) - Append("vec4(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ", " + std::to_string(arg.z) + ", " + std::to_string(arg.w) + ")"); + Append("vec4[f32](" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ", " + std::to_string(arg.z) + ", " + std::to_string(arg.w) + ")"); else if constexpr (std::is_same_v) Append("vec4(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ", " + std::to_string(arg.z) + ", " + std::to_string(arg.w) + ")"); else diff --git a/src/Nazara/Shader/ShaderLangParser.cpp b/src/Nazara/Shader/ShaderLangParser.cpp index f08ad1ca4..d73865aa0 100644 --- a/src/Nazara/Shader/ShaderLangParser.cpp +++ b/src/Nazara/Shader/ShaderLangParser.cpp @@ -207,7 +207,25 @@ namespace Nz::ShaderLang } //FIXME: Handle this better - if (identifier == "mat4") + if (identifier == "array") + { + Consume(); + + Expect(Advance(), TokenType::OpenSquareBracket); //< [ + + ShaderAst::ArrayType arrayType; + arrayType.containedType = std::make_unique(); + arrayType.containedType->type = ParseType(); + + Expect(Advance(), TokenType::Comma); //< , + + arrayType.length = ParseExpression(); + + Expect(Advance(), TokenType::ClosingSquareBracket); //< ] + + return arrayType; + } + else if (identifier == "mat4") { Consume(); @@ -215,9 +233,9 @@ namespace Nz::ShaderLang matrixType.columnCount = 4; matrixType.rowCount = 4; - Expect(Advance(), TokenType::LessThan); //< '<' + Expect(Advance(), TokenType::OpenSquareBracket); //< [ matrixType.type = ParsePrimitiveType(); - Expect(Advance(), TokenType::GreaterThan); //< '>' + Expect(Advance(), TokenType::ClosingSquareBracket); //< ] return matrixType; } @@ -229,9 +247,9 @@ namespace Nz::ShaderLang matrixType.columnCount = 3; matrixType.rowCount = 3; - Expect(Advance(), TokenType::LessThan); //< '<' + Expect(Advance(), TokenType::OpenSquareBracket); //< [ matrixType.type = ParsePrimitiveType(); - Expect(Advance(), TokenType::GreaterThan); //< '>' + Expect(Advance(), TokenType::ClosingSquareBracket); //< ] return matrixType; } @@ -243,9 +261,9 @@ namespace Nz::ShaderLang matrixType.columnCount = 2; matrixType.rowCount = 2; - Expect(Advance(), TokenType::LessThan); //< '<' + Expect(Advance(), TokenType::OpenSquareBracket); //< [ matrixType.type = ParsePrimitiveType(); - Expect(Advance(), TokenType::GreaterThan); //< '>' + Expect(Advance(), TokenType::ClosingSquareBracket); //< ] return matrixType; } @@ -256,9 +274,9 @@ namespace Nz::ShaderLang ShaderAst::SamplerType samplerType; samplerType.dim = ImageType::E2D; - Expect(Advance(), TokenType::LessThan); //< '<' + Expect(Advance(), TokenType::OpenSquareBracket); //< [ samplerType.sampledType = ParsePrimitiveType(); - Expect(Advance(), TokenType::GreaterThan); //< '>' + Expect(Advance(), TokenType::ClosingSquareBracket); //< ] return samplerType; } @@ -269,9 +287,9 @@ namespace Nz::ShaderLang ShaderAst::SamplerType samplerType; samplerType.dim = ImageType::Cubemap; - Expect(Advance(), TokenType::LessThan); //< '<' + Expect(Advance(), TokenType::OpenSquareBracket); //< [ samplerType.sampledType = ParsePrimitiveType(); - Expect(Advance(), TokenType::GreaterThan); //< '>' + Expect(Advance(), TokenType::ClosingSquareBracket); //< ] return samplerType; } @@ -281,9 +299,9 @@ namespace Nz::ShaderLang ShaderAst::UniformType uniformType; - Expect(Advance(), TokenType::LessThan); //< '<' + Expect(Advance(), TokenType::OpenSquareBracket); //< [ uniformType.containedType = ShaderAst::IdentifierType{ ParseIdentifierAsName() }; - Expect(Advance(), TokenType::GreaterThan); //< '>' + Expect(Advance(), TokenType::ClosingSquareBracket); //< ] return uniformType; } @@ -294,9 +312,9 @@ namespace Nz::ShaderLang ShaderAst::VectorType vectorType; vectorType.componentCount = 2; - Expect(Advance(), TokenType::LessThan); //< '<' + Expect(Advance(), TokenType::OpenSquareBracket); //< [ vectorType.type = ParsePrimitiveType(); - Expect(Advance(), TokenType::GreaterThan); //< '>' + Expect(Advance(), TokenType::ClosingSquareBracket); //< ] return vectorType; } @@ -307,9 +325,9 @@ namespace Nz::ShaderLang ShaderAst::VectorType vectorType; vectorType.componentCount = 3; - Expect(Advance(), TokenType::LessThan); //< '<' + Expect(Advance(), TokenType::OpenSquareBracket); //< [ vectorType.type = ParsePrimitiveType(); - Expect(Advance(), TokenType::GreaterThan); //< '>' + Expect(Advance(), TokenType::ClosingSquareBracket); //< ] return vectorType; } @@ -320,9 +338,9 @@ namespace Nz::ShaderLang ShaderAst::VectorType vectorType; vectorType.componentCount = 4; - Expect(Advance(), TokenType::LessThan); //< '<' + Expect(Advance(), TokenType::OpenSquareBracket); //< [ vectorType.type = ParsePrimitiveType(); - Expect(Advance(), TokenType::GreaterThan); //< '>' + Expect(Advance(), TokenType::ClosingSquareBracket); //< ] return vectorType; } @@ -1337,24 +1355,6 @@ namespace Nz::ShaderLang } } - ShaderAst::ExpressionType Parser::ParseArrayType() - { - ShaderAst::ArrayType arrayType; - - Expect(Advance(), TokenType::OpenSquareBracket); - - arrayType.containedType = std::make_unique(); - arrayType.containedType->type = ParseType(); - - Expect(Advance(), TokenType::Semicolon); - - arrayType.length = ParseExpression(); - - Expect(Advance(), TokenType::ClosingSquareBracket); - - return arrayType; - } - ShaderAst::AttributeType Parser::ParseIdentifierAsAttributeType() { const Token& identifierToken = Expect(Advance(), TokenType::Identifier); @@ -1402,9 +1402,6 @@ namespace Nz::ShaderLang return ShaderAst::NoType{}; } - if (Peek().type == TokenType::OpenSquareBracket) - return ParseArrayType(); - const Token& identifierToken = Expect(Peek(), TokenType::Identifier); const std::string& identifier = std::get(identifierToken.data); diff --git a/tests/Engine/Shader/AccessMemberTest.cpp b/tests/Engine/Shader/AccessMemberTest.cpp index f53823db1..ac389c868 100644 --- a/tests/Engine/Shader/AccessMemberTest.cpp +++ b/tests/Engine/Shader/AccessMemberTest.cpp @@ -13,7 +13,7 @@ TEST_CASE("structure member access", "[Shader]") std::string_view nzslSource = R"( struct innerStruct { - field: vec3 + field: vec3[f32] } struct outerStruct @@ -23,7 +23,7 @@ struct outerStruct external { - [set(0), binding(0)] ubo: uniform + [set(0), binding(0)] ubo: uniform[outerStruct] } )"; diff --git a/tests/Engine/Shader/Branch.cpp b/tests/Engine/Shader/Branch.cpp index 85044c8c3..cab7aa33e 100644 --- a/tests/Engine/Shader/Branch.cpp +++ b/tests/Engine/Shader/Branch.cpp @@ -18,7 +18,7 @@ struct inputStruct external { - [set(0), binding(0)] data: uniform + [set(0), binding(0)] data: uniform[inputStruct] } [entry(frag)] @@ -97,7 +97,7 @@ struct inputStruct external { - [set(0), binding(0)] data: uniform + [set(0), binding(0)] data: uniform[inputStruct] } [entry(frag)] @@ -161,7 +161,7 @@ struct inputStruct external { - [set(0), binding(0)] data: uniform + [set(0), binding(0)] data: uniform[inputStruct] } [entry(frag)] diff --git a/tests/Engine/Shader/Const.cpp b/tests/Engine/Shader/Const.cpp index 7bb3634cf..4bee938d3 100644 --- a/tests/Engine/Shader/Const.cpp +++ b/tests/Engine/Shader/Const.cpp @@ -37,7 +37,7 @@ struct inputStruct external { - [set(0), binding(0)] data: uniform + [set(0), binding(0)] data: uniform[inputStruct] } [entry(frag)] @@ -73,7 +73,7 @@ struct inputStruct external { - [set(0), binding(0)] data: uniform + [set(0), binding(0)] data: uniform[inputStruct] } [entry(frag)] @@ -97,7 +97,7 @@ struct inputStruct external { - [set(0), binding(0)] data: uniform + [set(0), binding(0)] data: uniform[inputStruct] } [entry(frag)] @@ -118,18 +118,18 @@ const LightCount = 3; [layout(std140)] struct Light { - color: vec4 + color: vec4[f32] } [layout(std140)] struct LightData { - lights: [Light; LightCount] + lights: array[Light, LightCount] } external { - [set(0), binding(0)] data: uniform + [set(0), binding(0)] data: uniform[LightData] } [entry(frag)] @@ -152,7 +152,7 @@ fn main() [entry(frag)] fn main() { - let color: vec4 = (0.000000).xxxx; + let color: vec4[f32] = (0.000000).xxxx; let i: i32 = 0; color += data.lights[i].color; let i: i32 = 2; @@ -175,18 +175,18 @@ const LightCount = 3; [layout(std140)] struct Light { - color: vec4 + color: vec4[f32] } [layout(std140)] struct LightData { - lights: [Light; LightCount] + lights: array[Light, LightCount] } external { - [set(0), binding(0)] data: uniform + [set(0), binding(0)] data: uniform[LightData] } [entry(frag)] @@ -209,7 +209,7 @@ fn main() [entry(frag)] fn main() { - let color: vec4 = (0.000000).xxxx; + let color: vec4[f32] = (0.000000).xxxx; let light: Light = data.lights[0]; color += light.color; let light: Light = data.lights[1]; diff --git a/tests/Engine/Shader/Loops.cpp b/tests/Engine/Shader/Loops.cpp index 182e21873..dbab1022f 100644 --- a/tests/Engine/Shader/Loops.cpp +++ b/tests/Engine/Shader/Loops.cpp @@ -18,7 +18,7 @@ struct inputStruct external { - [set(0), binding(0)] data: uniform + [set(0), binding(0)] data: uniform[inputStruct] } [entry(frag)] @@ -250,12 +250,12 @@ OpFunctionEnd)"); std::string_view nzslSource = R"( struct inputStruct { - value: [f32; 10] + value: array[f32, 10] } external { - [set(0), binding(0)] data: uniform + [set(0), binding(0)] data: uniform[inputStruct] } [entry(frag)] diff --git a/tests/Engine/Shader/Optimizations.cpp b/tests/Engine/Shader/Optimizations.cpp index e23d1484f..edf34e8d5 100644 --- a/tests/Engine/Shader/Optimizations.cpp +++ b/tests/Engine/Shader/Optimizations.cpp @@ -42,13 +42,13 @@ fn main() [entry(frag)] fn main() { - let output = vec4(8.0, 2.0, -7.0, 0.0) * (7.0 + 5.0) * 2.0 / 4.0; + let output = vec4[f32](8.0, 2.0, -7.0, 0.0) * (7.0 + 5.0) * 2.0 / 4.0; } )", R"( [entry(frag)] fn main() { - let output: vec4 = vec4(48.000000, 12.000000, -42.000000, 0.000000); + let output: vec4[f32] = vec4[f32](48.000000, 12.000000, -42.000000, 0.000000); )"); } @@ -149,7 +149,7 @@ fn main() [entry(frag)] fn main() { - let value = vec3(3.0, 0.0, 1.0).z; + let value = vec3[f32](3.0, 0.0, 1.0).z; } )", R"( [entry(frag)] @@ -172,7 +172,7 @@ fn main() [entry(frag)] fn main() { - let value: vec4 = vec4(42.000000, 42.000000, 42.000000, 42.000000); + let value: vec4[f32] = vec4[f32](42.000000, 42.000000, 42.000000, 42.000000); } )"); } @@ -183,13 +183,13 @@ fn main() [entry(frag)] fn main() { - let value = vec4(3.0, 0.0, 1.0, 2.0).yzwx; + let value = vec4[f32](3.0, 0.0, 1.0, 2.0).yzwx; } )", R"( [entry(frag)] fn main() { - let value: vec4 = vec4(0.000000, 1.000000, 2.000000, 3.000000); + let value: vec4[f32] = vec4[f32](0.000000, 1.000000, 2.000000, 3.000000); } )"); } @@ -200,13 +200,13 @@ fn main() [entry(frag)] fn main() { - let value = vec4(3.0, 0.0, 1.0, 2.0).zzxx; + let value = vec4[f32](3.0, 0.0, 1.0, 2.0).zzxx; } )", R"( [entry(frag)] fn main() { - let value: vec4 = vec4(1.000000, 1.000000, 3.000000, 3.000000); + let value: vec4[f32] = vec4[f32](1.000000, 1.000000, 3.000000, 3.000000); } )"); } @@ -217,13 +217,13 @@ fn main() [entry(frag)] fn main() { - let value = vec4(0.0, 1.0, 2.0, 3.0).xyz.yz.y.x.xxxx; + let value = vec4[f32](0.0, 1.0, 2.0, 3.0).xyz.yz.y.x.xxxx; } )", R"( [entry(frag)] fn main() { - let value: vec4 = vec4(2.000000, 2.000000, 2.000000, 2.000000); + let value: vec4[f32] = vec4[f32](2.000000, 2.000000, 2.000000, 2.000000); } )"); } @@ -233,12 +233,12 @@ fn main() ExpectOptimization(R"( struct inputStruct { - value: vec4 + value: vec4[f32] } external { - [set(0), binding(0)] data: uniform + [set(0), binding(0)] data: uniform[inputStruct] } [entry(frag)] @@ -250,7 +250,7 @@ fn main() [entry(frag)] fn main() { - let value: vec4 = data.value.zzzz; + let value: vec4[f32] = data.value.zzzz; } )"); } diff --git a/tests/Engine/Shader/Sanitizations.cpp b/tests/Engine/Shader/Sanitizations.cpp index 76025fee9..e0e565500 100644 --- a/tests/Engine/Shader/Sanitizations.cpp +++ b/tests/Engine/Shader/Sanitizations.cpp @@ -19,7 +19,7 @@ struct inputStruct external { - [set(0), binding(0)] data: uniform + [set(0), binding(0)] data: uniform[inputStruct] } [entry(frag)] @@ -84,12 +84,12 @@ fn main() std::string_view nzslSource = R"( struct inputStruct { - value: [f32; 10] + value: array[f32, 10] } external { - [set(0), binding(0)] data: uniform + [set(0), binding(0)] data: uniform[inputStruct] } [entry(frag)] @@ -131,49 +131,49 @@ fn main() WHEN("removing matrix casts") { std::string_view nzslSource = R"( -fn testMat2ToMat2(input: mat2) -> mat2 +fn testMat2ToMat2(input: mat2[f32]) -> mat2[f32] { - return mat2(input); + return mat2[f32](input); } -fn testMat2ToMat3(input: mat2) -> mat3 +fn testMat2ToMat3(input: mat2[f32]) -> mat3[f32] { - return mat3(input); + return mat3[f32](input); } -fn testMat2ToMat4(input: mat2) -> mat4 +fn testMat2ToMat4(input: mat2[f32]) -> mat4[f32] { - return mat4(input); + return mat4[f32](input); } -fn testMat3ToMat2(input: mat3) -> mat2 +fn testMat3ToMat2(input: mat3[f32]) -> mat2[f32] { - return mat2(input); + return mat2[f32](input); } -fn testMat3ToMat3(input: mat3) -> mat3 +fn testMat3ToMat3(input: mat3[f32]) -> mat3[f32] { - return mat3(input); + return mat3[f32](input); } -fn testMat3ToMat4(input: mat3) -> mat4 +fn testMat3ToMat4(input: mat3[f32]) -> mat4[f32] { - return mat4(input); + return mat4[f32](input); } -fn testMat4ToMat2(input: mat4) -> mat2 +fn testMat4ToMat2(input: mat4[f32]) -> mat2[f32] { - return mat2(input); + return mat2[f32](input); } -fn testMat4ToMat3(input: mat4) -> mat3 +fn testMat4ToMat3(input: mat4[f32]) -> mat3[f32] { - return mat3(input); + return mat3[f32](input); } -fn testMat4ToMat4(input: mat4) -> mat4 +fn testMat4ToMat4(input: mat4[f32]) -> mat4[f32] { - return mat4(input); + return mat4[f32](input); } )"; @@ -185,71 +185,71 @@ fn testMat4ToMat4(input: mat4) -> mat4 REQUIRE_NOTHROW(shader = Nz::ShaderAst::Sanitize(*shader, options)); ExpectNZSL(*shader, R"( -fn testMat2ToMat2(input: mat2) -> mat2 +fn testMat2ToMat2(input: mat2[f32]) -> mat2[f32] { return input; } -fn testMat2ToMat3(input: mat2) -> mat3 +fn testMat2ToMat3(input: mat2[f32]) -> mat3[f32] { - let temp: mat3; - temp[0] = vec3(input[0], 0.000000); - temp[1] = vec3(input[1], 0.000000); - temp[2] = vec3(input[2], 1.000000); + let temp: mat3[f32]; + temp[0] = vec3[f32](input[0], 0.000000); + temp[1] = vec3[f32](input[1], 0.000000); + temp[2] = vec3[f32](input[2], 1.000000); return temp; } -fn testMat2ToMat4(input: mat2) -> mat4 +fn testMat2ToMat4(input: mat2[f32]) -> mat4[f32] { - let temp: mat4; - temp[0] = vec4(input[0], 0.000000, 0.000000); - temp[1] = vec4(input[1], 0.000000, 0.000000); - temp[2] = vec4(input[2], 1.000000, 0.000000); - temp[3] = vec4(input[3], 0.000000, 1.000000); + let temp: mat4[f32]; + temp[0] = vec4[f32](input[0], 0.000000, 0.000000); + temp[1] = vec4[f32](input[1], 0.000000, 0.000000); + temp[2] = vec4[f32](input[2], 1.000000, 0.000000); + temp[3] = vec4[f32](input[3], 0.000000, 1.000000); return temp; } -fn testMat3ToMat2(input: mat3) -> mat2 +fn testMat3ToMat2(input: mat3[f32]) -> mat2[f32] { - let temp: mat2; + let temp: mat2[f32]; temp[0] = input[0].xy; temp[1] = input[1].xy; return temp; } -fn testMat3ToMat3(input: mat3) -> mat3 +fn testMat3ToMat3(input: mat3[f32]) -> mat3[f32] { return input; } -fn testMat3ToMat4(input: mat3) -> mat4 +fn testMat3ToMat4(input: mat3[f32]) -> mat4[f32] { - let temp: mat4; - temp[0] = vec4(input[0], 0.000000); - temp[1] = vec4(input[1], 0.000000); - temp[2] = vec4(input[2], 0.000000); - temp[3] = vec4(input[3], 1.000000); + let temp: mat4[f32]; + temp[0] = vec4[f32](input[0], 0.000000); + temp[1] = vec4[f32](input[1], 0.000000); + temp[2] = vec4[f32](input[2], 0.000000); + temp[3] = vec4[f32](input[3], 1.000000); return temp; } -fn testMat4ToMat2(input: mat4) -> mat2 +fn testMat4ToMat2(input: mat4[f32]) -> mat2[f32] { - let temp: mat2; + let temp: mat2[f32]; temp[0] = input[0].xy; temp[1] = input[1].xy; return temp; } -fn testMat4ToMat3(input: mat4) -> mat3 +fn testMat4ToMat3(input: mat4[f32]) -> mat3[f32] { - let temp: mat3; + let temp: mat3[f32]; temp[0] = input[0].xyz; temp[1] = input[1].xyz; temp[2] = input[2].xyz; return temp; } -fn testMat4ToMat4(input: mat4) -> mat4 +fn testMat4ToMat4(input: mat4[f32]) -> mat4[f32] { return input; } diff --git a/tests/Engine/Shader/Swizzle.cpp b/tests/Engine/Shader/Swizzle.cpp index e5d4bf22a..9ffeac2ab 100644 --- a/tests/Engine/Shader/Swizzle.cpp +++ b/tests/Engine/Shader/Swizzle.cpp @@ -16,7 +16,7 @@ TEST_CASE("swizzle", "[Shader]") [entry(frag)] fn main() { - let vec = vec4(0.0, 1.0, 2.0, 3.0); + let vec = vec4[f32](0.0, 1.0, 2.0, 3.0); let value = vec.xyz; } )"; @@ -35,8 +35,8 @@ void main() [entry(frag)] fn main() { - let vec: vec4 = vec4(0.000000, 1.000000, 2.000000, 3.000000); - let value: vec3 = vec.xyz; + let vec: vec4[f32] = vec4[f32](0.000000, 1.000000, 2.000000, 3.000000); + let value: vec3[f32] = vec.xyz; } )"); @@ -60,8 +60,8 @@ OpFunctionEnd)"); [entry(frag)] fn main() { - let vec = vec4(0.0, 0.0, 0.0, 0.0); - vec.yzw = vec3(1.0, 2.0, 3.0); + let vec = vec4[f32](0.0, 0.0, 0.0, 0.0); + vec.yzw = vec3[f32](1.0, 2.0, 3.0); } )"; @@ -79,8 +79,8 @@ void main() [entry(frag)] fn main() { - let vec: vec4 = vec4(0.000000, 0.000000, 0.000000, 0.000000); - vec.yzw = vec3(1.000000, 2.000000, 3.000000); + let vec: vec4[f32] = vec4[f32](0.000000, 0.000000, 0.000000, 0.000000); + vec.yzw = vec3[f32](1.000000, 2.000000, 3.000000); } )"); @@ -127,7 +127,7 @@ void main() fn main() { let value: f32 = 42.000000; - let vec: vec3 = value.xxx; + let vec: vec3[f32] = value.xxx; } )"); @@ -171,8 +171,8 @@ void main() [entry(frag)] fn main() { - let vec: vec3 = (max(2.000000, 1.000000)).xxx; - let vec2: vec3 = (min(2.000000, 1.000000)).xxx; + let vec: vec3[f32] = (max(2.000000, 1.000000)).xxx; + let vec2: vec3[f32] = (min(2.000000, 1.000000)).xxx; } )"); @@ -200,7 +200,7 @@ OpFunctionEnd)"); [entry(frag)] fn main() { - let vec = vec4(0.0, 1.0, 2.0, 3.0); + let vec = vec4[f32](0.0, 1.0, 2.0, 3.0); let value = vec.xyz.yz.y.x.xxxx; } )"; @@ -219,8 +219,8 @@ void main() [entry(frag)] fn main() { - let vec: vec4 = vec4(0.000000, 1.000000, 2.000000, 3.000000); - let value: vec4 = vec.xyz.yz.y.x.xxxx; + let vec: vec4[f32] = vec4[f32](0.000000, 1.000000, 2.000000, 3.000000); + let value: vec4[f32] = vec.xyz.yz.y.x.xxxx; } )"); @@ -247,9 +247,9 @@ OpFunctionEnd)"); [entry(frag)] fn main() { - let vec = vec4(0.0, 1.0, 2.0, 3.0); + let vec = vec4[f32](0.0, 1.0, 2.0, 3.0); vec.wyxz.bra.ts.x = 0.0; - vec.zyxw.ar.xy.yx = vec2(1.0, 0.0); + vec.zyxw.ar.xy.yx = vec2[f32](1.0, 0.0); } )"; @@ -268,9 +268,9 @@ void main() [entry(frag)] fn main() { - let vec: vec4 = vec4(0.000000, 1.000000, 2.000000, 3.000000); + let vec: vec4[f32] = vec4[f32](0.000000, 1.000000, 2.000000, 3.000000); vec.wyxz.zxw.yx.x = 0.000000; - vec.zyxw.wx.xy.yx = vec2(1.000000, 0.000000); + vec.zyxw.wx.xy.yx = vec2[f32](1.000000, 0.000000); } )"); From 8a3a8547dc981fc85fdcfee659f3c201c45cc48f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 2 Feb 2022 12:55:39 +0100 Subject: [PATCH 11/14] Add light support (WIP) --- examples/DeferredShading/main.cpp | 19 +- examples/PhysicsDemo/main.cpp | 39 +--- examples/WidgetDemo/main.cpp | 172 ++++++++++++++ examples/WidgetDemo/xmake.lua | 6 + include/Nazara/Graphics.hpp | 4 + include/Nazara/Graphics/Components.hpp | 1 + .../Graphics/Components/LightComponent.hpp | 64 ++++++ .../Graphics/Components/LightComponent.inl | 68 ++++++ include/Nazara/Graphics/DirectionalLight.hpp | 61 +++++ include/Nazara/Graphics/DirectionalLight.inl | 85 +++++++ include/Nazara/Graphics/ElementRenderer.hpp | 9 +- .../Nazara/Graphics/ForwardFramePipeline.hpp | 36 ++- .../Nazara/Graphics/ForwardFramePipeline.inl | 15 ++ include/Nazara/Graphics/FramePipeline.hpp | 3 + include/Nazara/Graphics/Light.hpp | 55 +++++ include/Nazara/Graphics/Light.inl | 29 +++ include/Nazara/Graphics/PointLight.hpp | 61 +++++ include/Nazara/Graphics/PointLight.inl | 91 ++++++++ include/Nazara/Graphics/RenderElement.hpp | 2 +- include/Nazara/Graphics/SpotLight.hpp | 77 +++++++ include/Nazara/Graphics/SpotLight.inl | 161 +++++++++++++ .../Nazara/Graphics/SpriteChainRenderer.hpp | 95 +++++--- include/Nazara/Graphics/SubmeshRenderer.hpp | 13 +- .../Nazara/Graphics/Systems/RenderSystem.hpp | 22 +- include/Nazara/Math/BoundingVolume.hpp | 2 + include/Nazara/Math/BoundingVolume.inl | 19 +- include/Nazara/Math/Box.inl | 9 +- include/Nazara/Renderer/RenderBufferView.hpp | 6 + include/Nazara/Renderer/RenderBufferView.inl | 22 ++ include/Nazara/Utility/Algorithm.hpp | 2 +- src/Nazara/Audio/Formats/libflacLoader.cpp | 2 +- .../Graphics/Components/LightComponent.cpp | 10 + src/Nazara/Graphics/DirectionalLight.cpp | 36 +++ src/Nazara/Graphics/ElementRenderer.cpp | 6 +- src/Nazara/Graphics/ForwardFramePipeline.cpp | 215 ++++++++++++++---- src/Nazara/Graphics/Light.cpp | 11 + src/Nazara/Graphics/PointLight.cpp | 36 +++ .../Resources/Shaders/phong_material.nzsl | 4 +- src/Nazara/Graphics/SpotLight.cpp | 39 ++++ src/Nazara/Graphics/SpriteChainRenderer.cpp | 176 +++++++------- src/Nazara/Graphics/SubmeshRenderer.cpp | 39 +++- src/Nazara/Graphics/Systems/RenderSystem.cpp | 127 +++++++++-- src/Nazara/Network/Win32/SocketImpl.cpp | 2 +- src/Nazara/Utility/AlgorithmUtility.cpp | 2 +- 44 files changed, 1700 insertions(+), 253 deletions(-) create mode 100644 examples/WidgetDemo/main.cpp create mode 100644 examples/WidgetDemo/xmake.lua create mode 100644 include/Nazara/Graphics/Components/LightComponent.hpp create mode 100644 include/Nazara/Graphics/Components/LightComponent.inl create mode 100644 include/Nazara/Graphics/DirectionalLight.hpp create mode 100644 include/Nazara/Graphics/DirectionalLight.inl create mode 100644 include/Nazara/Graphics/Light.hpp create mode 100644 include/Nazara/Graphics/Light.inl create mode 100644 include/Nazara/Graphics/PointLight.hpp create mode 100644 include/Nazara/Graphics/PointLight.inl create mode 100644 include/Nazara/Graphics/SpotLight.hpp create mode 100644 include/Nazara/Graphics/SpotLight.inl create mode 100644 src/Nazara/Graphics/Components/LightComponent.cpp create mode 100644 src/Nazara/Graphics/DirectionalLight.cpp create mode 100644 src/Nazara/Graphics/Light.cpp create mode 100644 src/Nazara/Graphics/PointLight.cpp create mode 100644 src/Nazara/Graphics/SpotLight.cpp diff --git a/examples/DeferredShading/main.cpp b/examples/DeferredShading/main.cpp index 8185568ab..8da726eda 100644 --- a/examples/DeferredShading/main.cpp +++ b/examples/DeferredShading/main.cpp @@ -854,12 +854,14 @@ int main() planeModel.BuildElement(forwardPassIndex, planeInstance, elements); std::vector> elementPointers; + std::vector renderStates(elements.size()); elementPointers.reserve(elements.size()); for (const auto& element : elements) elementPointers.emplace_back(element.get()); - submeshRenderer.Prepare(viewerInstance, *submeshRendererData, *currentFrame, {}, elementPointers.data(), elementPointers.size()); - submeshRenderer.Render(viewerInstance, *submeshRendererData, builder, elementPointers.data(), elementPointers.size()); + submeshRenderer.Prepare(viewerInstance, *submeshRendererData, *currentFrame, elementPointers.size(), elementPointers.data(), renderStates.data()); + submeshRenderer.PrepareEnd(*currentFrame, *spriteRendererData); + submeshRenderer.Render(viewerInstance, *submeshRendererData, builder, elementPointers.size(), elementPointers.data()); }); Nz::FramePass& lightingPass = graph.AddPass("Lighting pass"); @@ -918,12 +920,14 @@ int main() flareSprite.BuildElement(forwardPassIndex, flareInstance, elements); std::vector> elementPointers; + std::vector renderStates(elements.size()); + elementPointers.reserve(elements.size()); for (const auto& element : elements) elementPointers.emplace_back(element.get()); - spritechainRenderer.Prepare(viewerInstance, *spriteRendererData, *currentFrame, {}, elementPointers.data(), elementPointers.size()); - spritechainRenderer.Render(viewerInstance, *spriteRendererData, builder, elementPointers.data(), elementPointers.size()); + spritechainRenderer.Prepare(viewerInstance, *spriteRendererData, *currentFrame, elementPointers.size(), elementPointers.data(), renderStates.data()); + spritechainRenderer.Render(viewerInstance, *spriteRendererData, builder, elementPointers.size(), elementPointers.data()); }); forwardPass.SetExecutionCallback([&] { @@ -946,12 +950,15 @@ int main() flareSprite.BuildElement(forwardPassIndex, flareInstance, elements); std::vector> elementPointers; + std::vector renderStates(elements.size()); + elementPointers.reserve(elements.size()); for (const auto& element : elements) elementPointers.emplace_back(element.get()); - spritechainRenderer.Prepare(viewerInstance, *spriteRendererData, *currentFrame, {}, elementPointers.data(), elementPointers.size()); - spritechainRenderer.Render(viewerInstance, *spriteRendererData, builder, elementPointers.data(), elementPointers.size()); + spritechainRenderer.Prepare(viewerInstance, *spriteRendererData, *currentFrame, elementPointers.size(), elementPointers.data(), renderStates.data()); + spritechainRenderer.PrepareEnd(*currentFrame, *spriteRendererData); + spritechainRenderer.Render(viewerInstance, *spriteRendererData, builder, elementPointers.size(), elementPointers.data()); }); occluderPass.AddOutput(occluderTexture); diff --git a/examples/PhysicsDemo/main.cpp b/examples/PhysicsDemo/main.cpp index 39e999e2d..0313da7de 100644 --- a/examples/PhysicsDemo/main.cpp +++ b/examples/PhysicsDemo/main.cpp @@ -54,7 +54,7 @@ int main() Nz::MeshParams meshParams; meshParams.center = true; meshParams.matrix = Nz::Matrix4f::Rotate(Nz::EulerAnglesf(0.f, 90.f, 0.f)) * Nz::Matrix4f::Scale(Nz::Vector3f(0.002f)); - meshParams.vertexDeclaration = Nz::VertexDeclaration::Get(Nz::VertexLayout::XYZ_UV); + meshParams.vertexDeclaration = Nz::VertexDeclaration::Get(Nz::VertexLayout::XYZ_Normal_UV_Tangent); std::shared_ptr spaceshipMesh = Nz::Mesh::LoadFromFile(resourceDir / "Spaceship/spaceship.obj", meshParams); if (!spaceshipMesh) @@ -71,10 +71,10 @@ int main() std::shared_ptr depthPass = std::make_shared(Nz::DepthMaterial::GetSettings()); depthPass->EnableDepthBuffer(true); - depthPass->EnableDepthClamp(true); + //depthPass->EnableDepthClamp(true); depthPass->EnableFaceCulling(true); - std::shared_ptr materialPass = std::make_shared(Nz::BasicMaterial::GetSettings()); + std::shared_ptr materialPass = std::make_shared(Nz::PhongLightingMaterial::GetSettings()); materialPass->EnableDepthBuffer(true); materialPass->EnableDepthClamp(true); materialPass->EnableFaceCulling(true); @@ -91,7 +91,7 @@ int main() Nz::BasicMaterial basicMat(*materialPass); basicMat.EnableAlphaTest(false); - basicMat.SetAlphaMap(Nz::Texture::LoadFromFile(resourceDir / "alphatile.png", texParams)); + //basicMat.SetAlphaMap(Nz::Texture::LoadFromFile(resourceDir / "alphatile.png", texParams)); basicMat.SetDiffuseMap(Nz::Texture::LoadFromFile(resourceDir / "Spaceship/Texture/diffuse.png", texParams)); basicMat.SetDiffuseSampler(samplerInfo); @@ -143,37 +143,12 @@ int main() Nz::Physics3DSystem physSytem(registry); Nz::RenderSystem renderSystem(registry); - Nz::Canvas canvas2D(registry, window.GetEventHandler(), window.GetCursorController().CreateHandle(), 2); - canvas2D.Resize(Nz::Vector2f(window.GetSize())); - - Nz::LabelWidget* labelWidget = canvas2D.Add(); - labelWidget->SetPosition(0.f, 300.f, 0.f); - labelWidget->EnableBackground(true); - labelWidget->UpdateText(Nz::SimpleTextDrawer::Draw("Bonjour Paris !", 72)); - - Nz::ButtonWidget* buttonWidget = canvas2D.Add(); - buttonWidget->SetPosition(200.f, 400.f); - buttonWidget->UpdateText(Nz::SimpleTextDrawer::Draw("Press me senpai", 72)); - buttonWidget->Resize(buttonWidget->GetPreferredSize()); - buttonWidget->OnButtonTrigger.Connect([](const Nz::ButtonWidget*) - { - std::cout << "Coucou !" << std::endl; - }); - - entt::entity viewer2D = registry.create(); - { - registry.emplace(viewer2D); - auto& cameraComponent = registry.emplace(viewer2D, window.GetRenderTarget(), Nz::ProjectionType::Orthographic); - cameraComponent.UpdateClearColor(Nz::Color(0, 0, 0, 0)); - cameraComponent.UpdateRenderOrder(1); - cameraComponent.UpdateRenderMask(2); - } - entt::entity viewer = registry.create(); { registry.emplace(viewer); auto& cameraComponent = registry.emplace(viewer, window.GetRenderTarget()); cameraComponent.UpdateRenderMask(1); + //cameraComponent.UpdateClearColor(Nz::Color(127, 127, 127)); } auto shipCollider = std::make_shared(vertices, vertexMapper.GetVertexCount(), 0.01f); @@ -211,6 +186,9 @@ int main() entt::entity headingEntity = registry.create(); { + auto& entityLight = registry.emplace(playerEntity); + entityLight.AttachLight(std::make_shared(), 1); + auto& entityGfx = registry.emplace(playerEntity); entityGfx.AttachRenderable(model, 1); @@ -287,6 +265,7 @@ int main() case Nz::WindowEventType::KeyPressed: if (event.key.virtualKey == Nz::Keyboard::VKey::A) { + //canvas2D.Resize({ 1920.f, 1080.f }); basicMat.EnableAlphaTest(!basicMat.IsAlphaTestEnabled()); basicMatDepth.EnableAlphaTest(!basicMatDepth.IsAlphaTestEnabled()); } diff --git a/examples/WidgetDemo/main.cpp b/examples/WidgetDemo/main.cpp new file mode 100644 index 000000000..9f86592a8 --- /dev/null +++ b/examples/WidgetDemo/main.cpp @@ -0,0 +1,172 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +NAZARA_REQUEST_DEDICATED_GPU() + +int main() +{ + std::filesystem::path resourceDir = "resources"; + if (!std::filesystem::is_directory(resourceDir) && std::filesystem::is_directory(".." / resourceDir)) + resourceDir = ".." / resourceDir; + + Nz::Renderer::Config rendererConfig; + std::cout << "Run using Vulkan? (y/n)" << std::endl; + if (std::getchar() != 'n') + rendererConfig.preferredAPI = Nz::RenderAPI::Vulkan; + else + rendererConfig.preferredAPI = Nz::RenderAPI::OpenGL; + + std::cin.ignore(std::numeric_limits::max(), '\n'); + + Nz::Modules nazara(rendererConfig); + + Nz::RenderWindow window; + + std::shared_ptr device = Nz::Graphics::Instance()->GetRenderDevice(); + + std::string windowTitle = "Widget Test"; + if (!window.Create(device, Nz::VideoMode(1920, 1080, 32), windowTitle)) + { + std::cout << "Failed to create Window" << std::endl; + return __LINE__; + } + + entt::registry registry; + Nz::RenderSystem renderSystem(registry); + + Nz::Canvas canvas2D(registry, window.GetEventHandler(), window.GetCursorController().CreateHandle(), 0xFFFFFFFF); + canvas2D.Resize(Nz::Vector2f(window.GetSize())); + + Nz::LabelWidget* labelWidget = canvas2D.Add(); + labelWidget->SetPosition(0.f, 200.f, 0.f); + labelWidget->UpdateText(Nz::SimpleTextDrawer::Draw("Je suis un LabelWidget !", 72)); + + Nz::ButtonWidget* buttonWidget = canvas2D.Add(); + buttonWidget->SetPosition(200.f, 400.f); + buttonWidget->UpdateText(Nz::SimpleTextDrawer::Draw("Press me senpai", 72)); + buttonWidget->Resize(buttonWidget->GetPreferredSize()); + buttonWidget->OnButtonTrigger.Connect([=](const Nz::ButtonWidget*) + { + buttonWidget->Destroy(); + }); + + std::shared_ptr material = std::make_shared(); + + std::shared_ptr materialPass = std::make_shared(Nz::BasicMaterial::GetSettings()); + material->AddPass("ForwardPass", materialPass); + + Nz::TextureSamplerInfo samplerInfo; + samplerInfo.anisotropyLevel = 8; + + Nz::TextureParams texParams; + texParams.renderDevice = device; + texParams.loadFormat = Nz::PixelFormat::RGBA8_SRGB; + + Nz::BasicMaterial basicMat(*materialPass); + basicMat.SetDiffuseMap(Nz::Texture::LoadFromFile(resourceDir / "Spaceship/Texture/diffuse.png", texParams)); + basicMat.SetDiffuseSampler(samplerInfo); + + Nz::ImageWidget* imageWidget = canvas2D.Add(); + imageWidget->SetPosition(1200.f, 200.f); + imageWidget->SetMaterial(material); + imageWidget->Resize(imageWidget->GetPreferredSize() / 4.f); + + Nz::TextAreaWidget* textAreaWidget = canvas2D.Add(); + textAreaWidget->SetPosition(800.f, 500.f); + textAreaWidget->SetText("Je suis un TextAreaWidget !"); + textAreaWidget->Resize(Nz::Vector2f(400.f, textAreaWidget->GetPreferredHeight() * 5.f)); + textAreaWidget->SetBackgroundColor(Nz::Color::White); + textAreaWidget->SetTextColor(Nz::Color::Black); + textAreaWidget->EnableMultiline(true); + + Nz::CheckboxWidget* checkboxWidget = canvas2D.Add(); + //checkboxWidget->EnableTristate(true); + checkboxWidget->SetPosition(800.f, 800.f); + checkboxWidget->Resize({ 256.f, 256.f }); + checkboxWidget->SetState(true); + + /*Nz::TextAreaWidget* textAreaWidget2 = canvas2D.Add(); + textAreaWidget2->SetPosition(800.f, 700.f); + textAreaWidget2->SetText("Je suis un autre TextAreaWidget !"); + textAreaWidget2->Resize(Nz::Vector2f(500.f, textAreaWidget2->GetPreferredHeight())); + textAreaWidget2->SetBackgroundColor(Nz::Color::White); + textAreaWidget2->SetTextColor(Nz::Color::Black);*/ + + entt::entity viewer2D = registry.create(); + { + registry.emplace(viewer2D); + auto& cameraComponent = registry.emplace(viewer2D, window.GetRenderTarget(), Nz::ProjectionType::Orthographic); + cameraComponent.UpdateClearColor(Nz::Color(173, 216, 230, 255)); + } + + window.EnableEventPolling(true); + + Nz::Clock updateClock; + Nz::Clock secondClock; + unsigned int fps = 0; + + float elapsedTime = 0.f; + Nz::UInt64 time = Nz::GetElapsedMicroseconds(); + + while (window.IsOpen()) + { + Nz::UInt64 now = Nz::GetElapsedMicroseconds(); + elapsedTime = (now - time) / 1'000'000.f; + time = now; + + Nz::WindowEvent event; + while (window.PollEvent(&event)) + { + switch (event.type) + { + case Nz::WindowEventType::Quit: + window.Close(); + break; + + default: + break; + } + } + + Nz::RenderFrame frame = window.AcquireFrame(); + if (!frame) + continue; + + renderSystem.Render(registry, frame); + + frame.Present(); + + fps++; + + if (secondClock.GetMilliseconds() >= 1000) + { + window.SetTitle(windowTitle + " - " + Nz::NumberToString(fps) + " FPS" + " - " + Nz::NumberToString(registry.alive()) + " entities"); + + fps = 0; + + secondClock.Restart(); + } + } + + return EXIT_SUCCESS; +} diff --git a/examples/WidgetDemo/xmake.lua b/examples/WidgetDemo/xmake.lua new file mode 100644 index 000000000..505302ef4 --- /dev/null +++ b/examples/WidgetDemo/xmake.lua @@ -0,0 +1,6 @@ +target("WidgetDemo") + set_group("Examples") + set_kind("binary") + add_deps("NazaraGraphics", "NazaraPhysics3D", "NazaraWidgets") + add_packages("entt") + add_files("main.cpp") diff --git a/include/Nazara/Graphics.hpp b/include/Nazara/Graphics.hpp index 8153980dc..409850c9f 100644 --- a/include/Nazara/Graphics.hpp +++ b/include/Nazara/Graphics.hpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -54,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -61,6 +64,7 @@ #include #include #include +#include #include #include #include diff --git a/include/Nazara/Graphics/Components.hpp b/include/Nazara/Graphics/Components.hpp index fd126daa2..f0525b030 100644 --- a/include/Nazara/Graphics/Components.hpp +++ b/include/Nazara/Graphics/Components.hpp @@ -31,5 +31,6 @@ #include #include +#include #endif // NAZARA_GRAPHICS_COMPONENTS_HPP diff --git a/include/Nazara/Graphics/Components/LightComponent.hpp b/include/Nazara/Graphics/Components/LightComponent.hpp new file mode 100644 index 000000000..5101d746a --- /dev/null +++ b/include/Nazara/Graphics/Components/LightComponent.hpp @@ -0,0 +1,64 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// 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_GRAPHICS_COMPONENTS_LIGHTCOMPONENT_HPP +#define NAZARA_GRAPHICS_COMPONENTS_LIGHTCOMPONENT_HPP + +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_GRAPHICS_API LightComponent + { + public: + struct LightEntry; + + inline LightComponent(bool initialyVisible = true); + LightComponent(const LightComponent&) = default; + LightComponent(LightComponent&&) = default; + ~LightComponent() = default; + + inline void AttachLight(std::shared_ptr renderable, UInt32 renderMask); + + inline void Clear(); + + inline void DetachLight(const std::shared_ptr& renderable); + + inline const std::vector& GetLights() const; + + inline void Hide(); + + inline bool IsVisible() const; + + inline void Show(bool show = true); + + LightComponent& operator=(const LightComponent&) = default; + LightComponent& operator=(LightComponent&&) = default; + + NazaraSignal(OnLightAttached, LightComponent* /*graphicsComponent*/, const LightEntry& /*lightEntry*/); + NazaraSignal(OnLightDetach, LightComponent* /*graphicsComponent*/, const LightEntry& /*lightEntry*/); + NazaraSignal(OnVisibilityUpdate, LightComponent* /*graphicsComponent*/, bool /*newVisibilityState*/); + + struct LightEntry + { + std::shared_ptr light; + UInt32 renderMask; + }; + + private: + std::vector m_lightEntries; + bool m_isVisible; + }; +} + +#include + +#endif // NAZARA_GRAPHICS_COMPONENTS_LIGHTCOMPONENT_HPP diff --git a/include/Nazara/Graphics/Components/LightComponent.inl b/include/Nazara/Graphics/Components/LightComponent.inl new file mode 100644 index 000000000..61b2a9595 --- /dev/null +++ b/include/Nazara/Graphics/Components/LightComponent.inl @@ -0,0 +1,68 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// 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 LightComponent::LightComponent(bool initialyVisible) : + m_isVisible(initialyVisible) + { + } + + inline void LightComponent::AttachLight(std::shared_ptr light, UInt32 renderMask) + { + auto& entry = m_lightEntries.emplace_back(); + entry.light = std::move(light); + entry.renderMask = renderMask; + + OnLightAttached(this, m_lightEntries.back()); + } + + inline void LightComponent::Clear() + { + for (const auto& lightEntry : m_lightEntries) + OnLightDetach(this, lightEntry); + + m_lightEntries.clear(); + } + + inline void LightComponent::DetachLight(const std::shared_ptr& light) + { + auto it = std::find_if(m_lightEntries.begin(), m_lightEntries.end(), [&](const auto& lightEntry) { return lightEntry.light == light; }); + if (it != m_lightEntries.end()) + { + OnLightDetach(this, *it); + + m_lightEntries.erase(it); + } + } + + inline auto LightComponent::GetLights() const -> const std::vector& + { + return m_lightEntries; + } + + inline void LightComponent::Hide() + { + return Show(false); + } + + inline bool LightComponent::IsVisible() const + { + return m_isVisible; + } + + inline void LightComponent::Show(bool show) + { + if (m_isVisible != show) + { + OnVisibilityUpdate(this, show); + m_isVisible = show; + } + } +} + +#include diff --git a/include/Nazara/Graphics/DirectionalLight.hpp b/include/Nazara/Graphics/DirectionalLight.hpp new file mode 100644 index 000000000..aea839060 --- /dev/null +++ b/include/Nazara/Graphics/DirectionalLight.hpp @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// 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_GRAPHICS_DIRECTIONALLIGHT_HPP +#define NAZARA_GRAPHICS_DIRECTIONALLIGHT_HPP + +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_GRAPHICS_API DirectionalLight : public Light + { + public: + DirectionalLight(); + DirectionalLight(const DirectionalLight&) = delete; + DirectionalLight(DirectionalLight&&) noexcept = default; + ~DirectionalLight() = default; + + float ComputeContributionScore(const BoundingVolumef& boundingVolume) const override; + + void FillLightData(void* data) override; + + inline float GetAmbientFactor() const; + inline float GetDiffuseFactor() const; + inline Color GetColor() const; + inline const Vector3f& GetDirection() const; + inline const Quaternionf& GetRotation() const; + + inline void UpdateAmbientFactor(float factor); + inline void UpdateColor(Color color); + inline void UpdateDiffuseFactor(float factor); + inline void UpdateDirection(const Vector3f& direction); + inline void UpdateRotation(const Quaternionf& rotation); + + void UpdateTransform(const Vector3f& position, const Quaternionf& rotation, const Vector3f& scale) override; + + DirectionalLight& operator=(const DirectionalLight&) = delete; + DirectionalLight& operator=(DirectionalLight&&) noexcept = default; + + private: + inline void UpdateBoundingVolume(); + + Color m_color; + Quaternionf m_rotation; + Vector3f m_direction; + float m_ambientFactor; + float m_diffuseFactor; + }; +} + +#include + +#endif // NAZARA_GRAPHICS_DIRECTIONALLIGHT_HPP diff --git a/include/Nazara/Graphics/DirectionalLight.inl b/include/Nazara/Graphics/DirectionalLight.inl new file mode 100644 index 000000000..d0a28a6ac --- /dev/null +++ b/include/Nazara/Graphics/DirectionalLight.inl @@ -0,0 +1,85 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include + +namespace Nz +{ + inline DirectionalLight::DirectionalLight() : + m_color(Color::White), + m_ambientFactor(0.2f), + m_diffuseFactor(1.f) + { + UpdateRotation(Quaternionf::Identity()); + } + + inline float DirectionalLight::GetAmbientFactor() const + { + return m_ambientFactor; + } + + inline Color DirectionalLight::GetColor() const + { + return m_color; + } + + inline const Vector3f& DirectionalLight::GetDirection() const + { + return m_direction; + } + + inline const Quaternionf& DirectionalLight::GetRotation() const + { + return m_rotation; + } + + inline float DirectionalLight::GetDiffuseFactor() const + { + return m_diffuseFactor; + } + + inline void DirectionalLight::UpdateAmbientFactor(float factor) + { + m_ambientFactor = factor; + + OnLightDataInvalided(this); + } + + inline void DirectionalLight::UpdateColor(Color color) + { + m_color = color; + + OnLightDataInvalided(this); + } + + inline void DirectionalLight::UpdateDiffuseFactor(float factor) + { + m_diffuseFactor = factor; + + OnLightDataInvalided(this); + } + + inline void DirectionalLight::UpdateDirection(const Vector3f& direction) + { + UpdateRotation(Quaternionf::RotationBetween(Vector3f::Forward(), direction)); + } + + inline void DirectionalLight::UpdateRotation(const Quaternionf& rotation) + { + m_rotation = rotation; + m_direction = rotation * Vector3f::Forward(); + + UpdateBoundingVolume(); + } + + inline void DirectionalLight::UpdateBoundingVolume() + { + Light::UpdateBoundingVolume(BoundingVolumef::Infinite()); //< will trigger OnLightDataInvalided + } +} + +#include diff --git a/include/Nazara/Graphics/ElementRenderer.hpp b/include/Nazara/Graphics/ElementRenderer.hpp index d9e974f2d..cc0bc674e 100644 --- a/include/Nazara/Graphics/ElementRenderer.hpp +++ b/include/Nazara/Graphics/ElementRenderer.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -18,7 +19,6 @@ namespace Nz { class CommandBufferBuilder; - class RenderBuffer; class RenderElement; class RenderFrame; class ViewerInstance; @@ -33,13 +33,14 @@ namespace Nz virtual ~ElementRenderer(); virtual std::unique_ptr InstanciateData() = 0; - virtual void Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, const RenderStates& renderStates, const Pointer* elements, std::size_t elementCount); - virtual void Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, const Pointer* elements, std::size_t elementCount) = 0; + virtual void Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, std::size_t elementCount, const Pointer* elements, const RenderStates* renderStates); + virtual void PrepareEnd(RenderFrame& currentFrame, ElementRendererData& rendererData); + virtual void Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, std::size_t elementCount, const Pointer* elements) = 0; virtual void Reset(ElementRendererData& rendererData, RenderFrame& currentFrame); struct RenderStates { - std::optional lightData; + RenderBufferView lightData; }; }; diff --git a/include/Nazara/Graphics/ForwardFramePipeline.hpp b/include/Nazara/Graphics/ForwardFramePipeline.hpp index 43399deda..f7419679a 100644 --- a/include/Nazara/Graphics/ForwardFramePipeline.hpp +++ b/include/Nazara/Graphics/ForwardFramePipeline.hpp @@ -13,11 +13,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -25,6 +27,7 @@ namespace Nz { + class PointLight; class RenderFrame; class RenderTarget; @@ -40,16 +43,20 @@ namespace Nz void InvalidateWorldInstance(WorldInstance* worldInstance) override; void RegisterInstancedDrawable(WorldInstancePtr worldInstance, const InstancedRenderable* instancedRenderable, UInt32 renderMask) override; + void RegisterLight(std::shared_ptr light, UInt32 renderMask) override; void RegisterViewer(AbstractViewer* viewerInstance, Int32 renderOrder) override; void Render(RenderFrame& renderFrame) override; void UnregisterInstancedDrawable(const WorldInstancePtr& worldInstance, const InstancedRenderable* instancedRenderable) override; + void UnregisterLight(Light* light) override; void UnregisterViewer(AbstractViewer* viewerInstance) override; ForwardFramePipeline& operator=(const ForwardFramePipeline&) = delete; ForwardFramePipeline& operator=(ForwardFramePipeline&&) = delete; + static constexpr std::size_t MaxLightCountPerDraw = 3; + private: BakedFrameGraph BuildFrameGraph(); @@ -59,6 +66,28 @@ namespace Nz struct ViewerData; + struct LightData + { + std::shared_ptr light; + UInt32 renderMask; + + NazaraSlot(Light, OnLightDataInvalided, onLightInvalidated); + }; + + using LightKey = std::array; + + struct LightKeyHasher + { + inline std::size_t operator()(const LightKey& lightKey) const; + }; + + struct LightDataUbo + { + std::shared_ptr renderBuffer; + std::size_t offset = 0; + UploadPool::Allocation* allocation = nullptr; + }; + struct MaterialData { std::size_t usedCount = 0; @@ -92,6 +121,8 @@ namespace Nz std::size_t colorAttachment; std::size_t depthStencilAttachment; std::size_t visibilityHash = 0; + std::unordered_map lightPerRenderElement; + std::unordered_map lightBufferPerLights; std::vector> depthPrepassRenderElements; std::vector> forwardRenderElements; std::vector> elementRendererData; @@ -108,8 +139,8 @@ namespace Nz std::size_t m_depthPassIndex; std::size_t m_forwardPassIndex; - std::shared_ptr m_lightDataBuffer; std::unordered_map m_viewers; + std::unordered_map m_lights; std::unordered_map m_materials; std::unordered_map> m_renderables; std::unordered_map m_renderTargets; @@ -118,6 +149,9 @@ namespace Nz std::unordered_set m_invalidatedWorldInstances; std::unordered_set m_removedWorldInstances; std::vector> m_elementRenderers; + std::vector m_renderStates; + std::vector m_visibleLights; + std::vector m_lightDataBuffers; std::vector m_visibleRenderables; BakedFrameGraph m_bakedFrameGraph; RenderFrame* m_currentRenderFrame; diff --git a/include/Nazara/Graphics/ForwardFramePipeline.inl b/include/Nazara/Graphics/ForwardFramePipeline.inl index 834d564f6..8662726b6 100644 --- a/include/Nazara/Graphics/ForwardFramePipeline.inl +++ b/include/Nazara/Graphics/ForwardFramePipeline.inl @@ -3,10 +3,25 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include namespace Nz { + inline std::size_t ForwardFramePipeline::LightKeyHasher::operator()(const LightKey& lightKey) const + { + std::size_t lightHash = 5; + auto CombineHash = [](std::size_t currentHash, std::size_t newHash) + { + return currentHash * 23 + newHash; + }; + + std::hash lightPtrHasher; + for (std::size_t i = 0; i < lightKey.size(); ++i) + lightHash = CombineHash(lightHash, lightPtrHasher(lightKey[i])); + + return lightHash; + } } #include diff --git a/include/Nazara/Graphics/FramePipeline.hpp b/include/Nazara/Graphics/FramePipeline.hpp index d00260b9d..d9fd43a9b 100644 --- a/include/Nazara/Graphics/FramePipeline.hpp +++ b/include/Nazara/Graphics/FramePipeline.hpp @@ -15,6 +15,7 @@ namespace Nz { class AbstractViewer; class InstancedRenderable; + class Light; class RenderFrame; class NAZARA_GRAPHICS_API FramePipeline @@ -29,11 +30,13 @@ namespace Nz virtual void InvalidateWorldInstance(WorldInstance* worldInstance) = 0; virtual void RegisterInstancedDrawable(WorldInstancePtr worldInstance, const InstancedRenderable* instancedRenderable, UInt32 renderMask) = 0; + virtual void RegisterLight(std::shared_ptr light, UInt32 renderMask) = 0; virtual void RegisterViewer(AbstractViewer* viewerInstance, Int32 renderOrder) = 0; virtual void Render(RenderFrame& renderFrame) = 0; virtual void UnregisterInstancedDrawable(const WorldInstancePtr& worldInstance, const InstancedRenderable* instancedRenderable) = 0; + virtual void UnregisterLight(Light* light) = 0; virtual void UnregisterViewer(AbstractViewer* viewerInstance) = 0; FramePipeline& operator=(const FramePipeline&) = delete; diff --git a/include/Nazara/Graphics/Light.hpp b/include/Nazara/Graphics/Light.hpp new file mode 100644 index 000000000..7f05cb507 --- /dev/null +++ b/include/Nazara/Graphics/Light.hpp @@ -0,0 +1,55 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// 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_GRAPHICS_LIGHT_HPP +#define NAZARA_GRAPHICS_LIGHT_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class CommandBufferBuilder; + class RenderBuffer; + class RenderFrame; + + class NAZARA_GRAPHICS_API Light + { + public: + inline Light(); + Light(const Light&) = delete; + Light(Light&&) noexcept = default; + virtual ~Light(); + + virtual float ComputeContributionScore(const BoundingVolumef& boundingVolume) const = 0; + + virtual void FillLightData(void* data) = 0; + + inline const BoundingVolumef& GetBoundingVolume() const; + + virtual void UpdateTransform(const Vector3f& position, const Quaternionf& rotation, const Vector3f& scale) = 0; + + Light& operator=(const Light&) = delete; + Light& operator=(Light&&) noexcept = default; + + NazaraSignal(OnLightDataInvalided, Light* /*emitter*/); + + protected: + inline void UpdateBoundingVolume(const BoundingVolumef& boundingVolume); + + private: + BoundingVolumef m_boundingVolume; + }; +} + +#include + +#endif // NAZARA_GRAPHICS_LIGHT_HPP diff --git a/include/Nazara/Graphics/Light.inl b/include/Nazara/Graphics/Light.inl new file mode 100644 index 000000000..2680e37a8 --- /dev/null +++ b/include/Nazara/Graphics/Light.inl @@ -0,0 +1,29 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + inline Light::Light() : + m_boundingVolume(BoundingVolumef::Null()) + { + } + + inline const BoundingVolumef& Light::GetBoundingVolume() const + { + return m_boundingVolume; + } + + inline void Light::UpdateBoundingVolume(const BoundingVolumef& boundingVolume) + { + m_boundingVolume = boundingVolume; + + OnLightDataInvalided(this); + } +} + +#include diff --git a/include/Nazara/Graphics/PointLight.hpp b/include/Nazara/Graphics/PointLight.hpp new file mode 100644 index 000000000..08ae44ce5 --- /dev/null +++ b/include/Nazara/Graphics/PointLight.hpp @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// 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_GRAPHICS_POINTLIGHT_HPP +#define NAZARA_GRAPHICS_POINTLIGHT_HPP + +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_GRAPHICS_API PointLight : public Light + { + public: + PointLight(); + PointLight(const PointLight&) = delete; + PointLight(PointLight&&) noexcept = default; + ~PointLight() = default; + + float ComputeContributionScore(const BoundingVolumef& boundingVolume) const override; + + void FillLightData(void* data) override; + + inline float GetAmbientFactor() const; + inline float GetDiffuseFactor() const; + inline Color GetColor() const; + inline const Vector3f& GetPosition() const; + inline float GetRadius() const; + + inline void UpdateAmbientFactor(float factor); + inline void UpdateColor(Color color); + inline void UpdateDiffuseFactor(float factor); + inline void UpdatePosition(const Vector3f& position); + inline void UpdateRadius(float radius); + + void UpdateTransform(const Vector3f& position, const Quaternionf& rotation, const Vector3f& scale) override; + + PointLight& operator=(const PointLight&) = delete; + PointLight& operator=(PointLight&&) noexcept = default; + + private: + inline void UpdateBoundingVolume(); + + Color m_color; + Vector3f m_position; + float m_ambientFactor; + float m_diffuseFactor; + float m_invRadius; + float m_radius; + }; +} + +#include + +#endif // NAZARA_GRAPHICS_POINTLIGHT_HPP diff --git a/include/Nazara/Graphics/PointLight.inl b/include/Nazara/Graphics/PointLight.inl new file mode 100644 index 000000000..a054667ff --- /dev/null +++ b/include/Nazara/Graphics/PointLight.inl @@ -0,0 +1,91 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + inline PointLight::PointLight() : + m_color(Color::White), + m_position(Vector3f::Zero()), + m_ambientFactor(0.2f), + m_diffuseFactor(1.f) + { + UpdateRadius(5.f); + } + + inline float PointLight::GetAmbientFactor() const + { + return m_ambientFactor; + } + + inline Color PointLight::GetColor() const + { + return m_color; + } + + inline const Vector3f& PointLight::GetPosition() const + { + return m_position; + } + + inline float PointLight::GetDiffuseFactor() const + { + return m_diffuseFactor; + } + + inline float PointLight::GetRadius() const + { + return m_radius; + } + + inline void PointLight::UpdateAmbientFactor(float factor) + { + m_ambientFactor = factor; + + OnLightDataInvalided(this); + } + + inline void PointLight::UpdateColor(Color color) + { + m_color = color; + + OnLightDataInvalided(this); + } + + inline void PointLight::UpdateDiffuseFactor(float factor) + { + m_diffuseFactor = factor; + + OnLightDataInvalided(this); + } + + inline void PointLight::UpdatePosition(const Vector3f& position) + { + m_position = position; + + UpdateBoundingVolume(); + } + + inline void PointLight::UpdateRadius(float radius) + { + m_radius = radius; + m_invRadius = 1.f / m_radius; + + UpdateBoundingVolume(); + } + + inline void PointLight::UpdateBoundingVolume() + { + Vector3f extent = Vector3f(m_radius, m_radius, m_radius) * Sqrt3; + BoundingVolumef boundingVolume(Boxf(-extent, extent)); + boundingVolume.Update(m_position); + + Light::UpdateBoundingVolume(boundingVolume); //< will trigger OnLightDataInvalided + } +} + +#include diff --git a/include/Nazara/Graphics/RenderElement.hpp b/include/Nazara/Graphics/RenderElement.hpp index 604af6b6c..4edf6bdcf 100644 --- a/include/Nazara/Graphics/RenderElement.hpp +++ b/include/Nazara/Graphics/RenderElement.hpp @@ -25,7 +25,7 @@ namespace Nz inline RenderElement(UInt8 elementType); virtual ~RenderElement(); - virtual UInt64 ComputeSortingScore(const Nz::Frustumf& frustum, const RenderQueueRegistry& registry) const = 0; + virtual UInt64 ComputeSortingScore(const Frustumf& frustum, const RenderQueueRegistry& registry) const = 0; inline UInt8 GetElementType() const; diff --git a/include/Nazara/Graphics/SpotLight.hpp b/include/Nazara/Graphics/SpotLight.hpp new file mode 100644 index 000000000..cba896c4c --- /dev/null +++ b/include/Nazara/Graphics/SpotLight.hpp @@ -0,0 +1,77 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// 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_GRAPHICS_SPOTLIGHT_HPP +#define NAZARA_GRAPHICS_SPOTLIGHT_HPP + +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_GRAPHICS_API SpotLight : public Light + { + public: + SpotLight(); + SpotLight(const SpotLight&) = delete; + SpotLight(SpotLight&&) noexcept = default; + ~SpotLight() = default; + + float ComputeContributionScore(const BoundingVolumef& boundingVolume) const override; + + void FillLightData(void* data) override; + + inline float GetAmbientFactor() const; + inline float GetDiffuseFactor() const; + inline Color GetColor() const; + inline const Vector3f& GetDirection() const; + inline RadianAnglef GetInnerAngle() const; + inline RadianAnglef GetOuterAngle() const; + inline const Vector3f& GetPosition() const; + inline const Quaternionf& GetRotation() const; + inline float GetRadius() const; + + inline void UpdateAmbientFactor(float factor); + inline void UpdateColor(Color color); + inline void UpdateDiffuseFactor(float factor); + inline void UpdateDirection(const Vector3f& direction); + inline void UpdateInnerAngle(RadianAnglef innerAngle); + inline void UpdateOuterAngle(RadianAnglef outerAngle); + inline void UpdatePosition(const Vector3f& position); + inline void UpdateRadius(float radius); + inline void UpdateRotation(const Quaternionf& rotation); + + void UpdateTransform(const Vector3f& position, const Quaternionf& rotation, const Vector3f& scale) override; + + SpotLight& operator=(const SpotLight&) = delete; + SpotLight& operator=(SpotLight&&) noexcept = default; + + private: + inline void UpdateBoundingVolume(); + + Color m_color; + Quaternionf m_rotation; + RadianAnglef m_innerAngle; + RadianAnglef m_outerAngle; + Vector3f m_direction; + Vector3f m_position; + float m_ambientFactor; + float m_diffuseFactor; + float m_invRadius; + float m_radius; + float m_innerAngleCos; + float m_outerAngleCos; + float m_outerAngleTan; + }; +} + +#include + +#endif // NAZARA_GRAPHICS_SPOTLIGHT_HPP diff --git a/include/Nazara/Graphics/SpotLight.inl b/include/Nazara/Graphics/SpotLight.inl new file mode 100644 index 000000000..c96120d3a --- /dev/null +++ b/include/Nazara/Graphics/SpotLight.inl @@ -0,0 +1,161 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + inline SpotLight::SpotLight() : + m_color(Color::White), + m_position(Vector3f::Zero()), + m_ambientFactor(0.2f), + m_diffuseFactor(1.f) + { + UpdateInnerAngle(DegreeAnglef(30.f)); + UpdateOuterAngle(DegreeAnglef(45.f)); + UpdateRadius(5.f); + UpdateRotation(Quaternionf::Identity()); + } + + inline float SpotLight::GetAmbientFactor() const + { + return m_ambientFactor; + } + + inline Color SpotLight::GetColor() const + { + return m_color; + } + + inline const Vector3f& SpotLight::GetDirection() const + { + return m_direction; + } + + inline RadianAnglef SpotLight::GetInnerAngle() const + { + return m_innerAngle; + } + + inline RadianAnglef SpotLight::GetOuterAngle() const + { + return m_outerAngle; + } + + inline const Vector3f& SpotLight::GetPosition() const + { + return m_position; + } + + inline const Quaternionf& SpotLight::GetRotation() const + { + return m_rotation; + } + + inline float SpotLight::GetDiffuseFactor() const + { + return m_diffuseFactor; + } + + inline float SpotLight::GetRadius() const + { + return m_radius; + } + + inline void SpotLight::UpdateAmbientFactor(float factor) + { + m_ambientFactor = factor; + + OnLightDataInvalided(this); + } + + inline void SpotLight::UpdateColor(Color color) + { + m_color = color; + + OnLightDataInvalided(this); + } + + inline void SpotLight::UpdateDiffuseFactor(float factor) + { + m_diffuseFactor = factor; + + OnLightDataInvalided(this); + } + + inline void SpotLight::UpdateDirection(const Vector3f& direction) + { + UpdateRotation(Quaternionf::RotationBetween(Vector3f::Forward(), direction)); + } + + inline void SpotLight::UpdateInnerAngle(RadianAnglef innerAngle) + { + m_innerAngle = innerAngle; + m_innerAngleCos = m_innerAngle.GetCos(); + + UpdateBoundingVolume(); + } + + inline void SpotLight::UpdateOuterAngle(RadianAnglef outerAngle) + { + m_outerAngle = outerAngle; + m_outerAngleCos = m_outerAngle.GetCos(); + m_outerAngleTan = m_outerAngle.GetTan(); + + UpdateBoundingVolume(); + } + + inline void SpotLight::UpdatePosition(const Vector3f& position) + { + m_position = position; + + UpdateBoundingVolume(); + } + + inline void SpotLight::UpdateRadius(float radius) + { + m_radius = radius; + m_invRadius = 1.f / m_radius; + + UpdateBoundingVolume(); + } + + inline void SpotLight::UpdateRotation(const Quaternionf& rotation) + { + m_rotation = rotation; + m_direction = rotation * Vector3f::Forward(); + + UpdateBoundingVolume(); + } + + inline void SpotLight::UpdateBoundingVolume() + { + // We make a box center in the origin + Boxf box(Vector3f::Zero()); + + // We compute the other points + Vector3f base(Vector3f::Forward() * m_radius); + + // Now we need the radius of the projected circle depending on the distance + // Tangent = Opposite/Adjacent <=> Opposite = Adjacent * Tangent + float radius = m_radius * m_outerAngleTan; + Vector3f lExtend = Vector3f::Left() * radius; + Vector3f uExtend = Vector3f::Up() * radius; + + // And we add the four extremities of our pyramid + box.ExtendTo(base + lExtend + uExtend); + box.ExtendTo(base + lExtend - uExtend); + box.ExtendTo(base - lExtend + uExtend); + box.ExtendTo(base - lExtend - uExtend); + + BoundingVolumef boundingVolume(box); + boundingVolume.Update(Matrix4f::Transform(m_position, m_rotation)); + + Light::UpdateBoundingVolume(boundingVolume); //< will trigger OnLightDataInvalided + } +} + +#include diff --git a/include/Nazara/Graphics/SpriteChainRenderer.hpp b/include/Nazara/Graphics/SpriteChainRenderer.hpp index 0c1f20b04..3193e2501 100644 --- a/include/Nazara/Graphics/SpriteChainRenderer.hpp +++ b/include/Nazara/Graphics/SpriteChainRenderer.hpp @@ -18,44 +18,15 @@ namespace Nz { + class MaterialPass; class RenderDevice; class RenderPipeline; class RenderSpriteChain; class ShaderBinding; - - class NAZARA_GRAPHICS_API SpriteChainRenderer : public ElementRenderer - { - public: - SpriteChainRenderer(RenderDevice& device, std::size_t maxVertexBufferSize = 32 * 1024); - ~SpriteChainRenderer() = default; - - std::unique_ptr InstanciateData() override; - void Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, const RenderStates& renderStates, const Pointer* elements, std::size_t elementCount) override; - void Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, const Pointer* elements, std::size_t elementCount) override; - void Reset(ElementRendererData& rendererData, RenderFrame& currentFrame) override; - - private: - struct BufferCopy - { - RenderBuffer* targetBuffer; - UploadPool::Allocation* allocation; - std::size_t size; - }; - - struct VertexBufferPool - { - std::vector> vertexBuffers; - }; - - std::shared_ptr m_indexBuffer; - std::shared_ptr m_vertexBufferPool; - std::size_t m_maxVertexBufferSize; - std::size_t m_maxVertexCount; - std::vector m_pendingCopies; - std::vector m_bindingCache; - RenderDevice& m_device; - }; - + class Texture; + class VertexDeclaration; + class WorldInstance; + struct SpriteChainRendererData : public ElementRendererData { struct DrawCall @@ -79,6 +50,62 @@ namespace Nz std::vector> vertexBuffers; std::vector shaderBindings; }; + + class NAZARA_GRAPHICS_API SpriteChainRenderer final : public ElementRenderer + { + public: + SpriteChainRenderer(RenderDevice& device, std::size_t maxVertexBufferSize = 32 * 1024); + ~SpriteChainRenderer() = default; + + std::unique_ptr InstanciateData() override; + void Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, std::size_t elementCount, const Pointer* elements, const RenderStates* renderStates) override; + void PrepareEnd(RenderFrame& currentFrame, ElementRendererData& rendererData) override; + void Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, std::size_t elementCount, const Pointer* elements) override; + void Reset(ElementRendererData& rendererData, RenderFrame& currentFrame) override; + + private: + void Flush(); + void FlushDrawCall(); + void FlushDrawData(); + + struct BufferCopy + { + RenderBuffer* targetBuffer; + UploadPool::Allocation* allocation; + std::size_t size; + }; + + struct PendingData + { + std::size_t firstQuadIndex = 0; + SpriteChainRendererData::DrawCall* currentDrawCall = nullptr; + UploadPool::Allocation* currentAllocation = nullptr; + UInt8* currentAllocationMemPtr = nullptr; + const VertexDeclaration* currentVertexDeclaration = nullptr; + RenderBuffer* currentVertexBuffer = nullptr; + const MaterialPass* currentMaterialPass = nullptr; + const RenderPipeline* currentPipeline = nullptr; + const ShaderBinding* currentShaderBinding = nullptr; + const Texture* currentTextureOverlay = nullptr; + const WorldInstance* currentWorldInstance = nullptr; + RenderBufferView currentLightData; + Recti currentScissorBox = Recti(-1, -1, -1, -1); + }; + + struct VertexBufferPool + { + std::vector> vertexBuffers; + }; + + std::shared_ptr m_indexBuffer; + std::shared_ptr m_vertexBufferPool; + std::size_t m_maxVertexBufferSize; + std::size_t m_maxVertexCount; + std::vector m_pendingCopies; + std::vector m_bindingCache; + PendingData m_pendingData; + RenderDevice& m_device; + }; } #include diff --git a/include/Nazara/Graphics/SubmeshRenderer.hpp b/include/Nazara/Graphics/SubmeshRenderer.hpp index fd124bc9c..6fa71df76 100644 --- a/include/Nazara/Graphics/SubmeshRenderer.hpp +++ b/include/Nazara/Graphics/SubmeshRenderer.hpp @@ -15,6 +15,7 @@ namespace Nz { class RenderPipeline; + class RenderSubmesh; class ShaderBinding; class NAZARA_GRAPHICS_API SubmeshRenderer : public ElementRenderer @@ -24,8 +25,8 @@ namespace Nz ~SubmeshRenderer() = default; std::unique_ptr InstanciateData() override; - void Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, const RenderStates& renderStates, const Pointer* elements, std::size_t elementCount) override; - void Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, const Pointer* elements, std::size_t elementCount) override; + void Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, std::size_t elementCount, const Pointer* elements, const RenderStates* renderStates) override; + void Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, std::size_t elementCount, const Pointer* elements) override; void Reset(ElementRendererData& rendererData, RenderFrame& currentFrame) override; private: @@ -40,10 +41,18 @@ namespace Nz const RenderBuffer* vertexBuffer; const RenderPipeline* renderPipeline; const ShaderBinding* shaderBinding; + std::size_t firstIndex; std::size_t indexCount; Recti scissorBox; }; + struct DrawCallIndices + { + std::size_t start; + std::size_t count; + }; + + std::unordered_map drawCallPerElement; std::vector drawCalls; std::vector shaderBindings; }; diff --git a/include/Nazara/Graphics/Systems/RenderSystem.hpp b/include/Nazara/Graphics/Systems/RenderSystem.hpp index af2a22e61..d90ae1cd4 100644 --- a/include/Nazara/Graphics/Systems/RenderSystem.hpp +++ b/include/Nazara/Graphics/Systems/RenderSystem.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,7 @@ namespace Nz private: void OnCameraDestroy(entt::registry& registry, entt::entity entity); void OnGraphicsDestroy(entt::registry& registry, entt::entity entity); + void OnLightDestroy(entt::registry& registry, entt::entity entity); void OnNodeDestroy(entt::registry& registry, entt::entity entity); void UpdateInstances(entt::registry& registry); void UpdateVisibility(entt::registry& registry); @@ -56,18 +58,32 @@ namespace Nz NazaraSlot(Node, OnNodeInvalidation, onNodeInvalidation); }; + struct LightEntity + { + NazaraSlot(LightComponent, OnLightAttached, onLightAttached); + NazaraSlot(LightComponent, OnLightDetach, onLightDetach); + NazaraSlot(LightComponent, OnVisibilityUpdate, onVisibilityUpdate); + NazaraSlot(Node, OnNodeInvalidation, onNodeInvalidation); + }; + entt::connection m_cameraDestroyConnection; entt::connection m_graphicsDestroyConnection; + entt::connection m_lightDestroyConnection; entt::connection m_nodeDestroyConnection; entt::observer m_cameraConstructObserver; entt::observer m_graphicsConstructObserver; + entt::observer m_lightConstructObserver; std::set m_invalidatedCameraNode; - std::set m_invalidatedWorldNode; + std::set m_invalidatedGfxWorldNode; + std::set m_invalidatedLightWorldNode; std::unique_ptr m_pipeline; std::unordered_map m_cameraEntities; std::unordered_map m_graphicsEntities; - std::unordered_set m_newlyHiddenEntities; - std::unordered_set m_newlyVisibleEntities; + std::unordered_map m_lightEntities; + std::unordered_set m_newlyHiddenGfxEntities; + std::unordered_set m_newlyVisibleGfxEntities; + std::unordered_set m_newlyHiddenLightEntities; + std::unordered_set m_newlyVisibleLightEntities; }; } diff --git a/include/Nazara/Math/BoundingVolume.hpp b/include/Nazara/Math/BoundingVolume.hpp index db391be1c..6271f36a2 100644 --- a/include/Nazara/Math/BoundingVolume.hpp +++ b/include/Nazara/Math/BoundingVolume.hpp @@ -34,6 +34,8 @@ namespace Nz BoundingVolume& ExtendTo(const BoundingVolume& volume); + bool Intersect(const Box& box) const; + bool IsFinite() const; bool IsInfinite() const; bool IsNull() const; diff --git a/include/Nazara/Math/BoundingVolume.inl b/include/Nazara/Math/BoundingVolume.inl index 2dd73fc46..c96bb50dd 100644 --- a/include/Nazara/Math/BoundingVolume.inl +++ b/include/Nazara/Math/BoundingVolume.inl @@ -169,11 +169,28 @@ namespace Nz return *this; } + template + bool BoundingVolume::Intersect(const Box& box) const + { + switch (extend) + { + case Extend::Infinite: + return true; + + case Extend::Finite: + return aabb.Intersect(box); + + case Extend::Null: + return false; + } + + return false; + } + /*! * \brief Checks whether the volume is finite * \return true if extend is Extend::Finite */ - template bool BoundingVolume::IsFinite() const { diff --git a/include/Nazara/Math/Box.inl b/include/Nazara/Math/Box.inl index e54774c7a..b308b56a1 100644 --- a/include/Nazara/Math/Box.inl +++ b/include/Nazara/Math/Box.inl @@ -459,17 +459,12 @@ namespace Nz { T left = std::max(x, box.x); T right = std::min(x + width, box.x + box.width); - if (left >= right) - return false; - T top = std::max(y, box.y); T bottom = std::min(y + height, box.y + box.height); - if (top >= bottom) - return false; - T up = std::max(z, box.z); T down = std::min(z + depth, box.z + box.depth); - if (up >= down) + + if (left >= right || top >= bottom || up >= down) return false; if (intersection) diff --git a/include/Nazara/Renderer/RenderBufferView.hpp b/include/Nazara/Renderer/RenderBufferView.hpp index c01c2960c..61b3b329a 100644 --- a/include/Nazara/Renderer/RenderBufferView.hpp +++ b/include/Nazara/Renderer/RenderBufferView.hpp @@ -16,6 +16,7 @@ namespace Nz class RenderBufferView { public: + inline RenderBufferView(); inline RenderBufferView(RenderBuffer* buffer); inline RenderBufferView(RenderBuffer* buffer, UInt64 offset, UInt64 size); RenderBufferView(const RenderBufferView&) = default; @@ -26,6 +27,11 @@ namespace Nz inline UInt64 GetOffset() const; inline UInt64 GetSize() const; + inline explicit operator bool() const; + + inline bool operator==(const RenderBufferView& rhs) const; + inline bool operator!=(const RenderBufferView& rhs) const; + RenderBufferView& operator=(const RenderBufferView&) = default; RenderBufferView& operator=(RenderBufferView&&) = default; diff --git a/include/Nazara/Renderer/RenderBufferView.inl b/include/Nazara/Renderer/RenderBufferView.inl index 5e368bad9..d41794511 100644 --- a/include/Nazara/Renderer/RenderBufferView.inl +++ b/include/Nazara/Renderer/RenderBufferView.inl @@ -8,6 +8,13 @@ namespace Nz { + inline RenderBufferView::RenderBufferView() : + m_offset(0), + m_size(0), + m_buffer(nullptr) + { + } + inline RenderBufferView::RenderBufferView(RenderBuffer* buffer) : RenderBufferView(buffer, 0, buffer->GetSize()) { @@ -34,6 +41,21 @@ namespace Nz { return m_size; } + + inline RenderBufferView::operator bool() const + { + return m_buffer != nullptr; + } + + inline bool RenderBufferView::operator==(const RenderBufferView& rhs) const + { + return m_buffer == rhs.m_buffer && m_offset == rhs.m_offset && m_size == rhs.m_size; + } + + inline bool RenderBufferView::operator!=(const RenderBufferView& rhs) const + { + return !operator==(rhs); + } } #include diff --git a/include/Nazara/Utility/Algorithm.hpp b/include/Nazara/Utility/Algorithm.hpp index 4b5f6becc..3b4ad1750 100644 --- a/include/Nazara/Utility/Algorithm.hpp +++ b/include/Nazara/Utility/Algorithm.hpp @@ -44,7 +44,7 @@ namespace Nz NAZARA_UTILITY_API Boxf ComputeAABB(SparsePtr positionPtr, std::size_t vertexCount); NAZARA_UTILITY_API void ComputeBoxIndexVertexCount(const Vector3ui& subdivision, std::size_t* indexCount, std::size_t* vertexCount); - NAZARA_UTILITY_API UInt64 ComputeCacheMissCount(IndexIterator indices, std::size_t indexCount); + NAZARA_UTILITY_API UInt64 ComputeCacheMissCount(IndexIterator indices, UInt32 indexCount); NAZARA_UTILITY_API void ComputeConeIndexVertexCount(unsigned int subdivision, std::size_t* indexCount, std::size_t* vertexCount); NAZARA_UTILITY_API void ComputeCubicSphereIndexVertexCount(unsigned int subdivision, std::size_t* indexCount, std::size_t* vertexCount); NAZARA_UTILITY_API void ComputeIcoSphereIndexVertexCount(unsigned int recursionLevel, std::size_t* indexCount, std::size_t* vertexCount); diff --git a/src/Nazara/Audio/Formats/libflacLoader.cpp b/src/Nazara/Audio/Formats/libflacLoader.cpp index 52f2ad1ff..ab2a5b0d4 100644 --- a/src/Nazara/Audio/Formats/libflacLoader.cpp +++ b/src/Nazara/Audio/Formats/libflacLoader.cpp @@ -224,7 +224,7 @@ namespace Nz UInt32 channelCount = 0; UInt64 frameCount = 0; UInt64 sampleCount = 0; - UInt64 sampleRate = 0; + UInt32 sampleRate = 0; ud.metadataCallback = [&](const FLAC__StreamDecoder* /*decoder*/, const FLAC__StreamMetadata* meta) { diff --git a/src/Nazara/Graphics/Components/LightComponent.cpp b/src/Nazara/Graphics/Components/LightComponent.cpp new file mode 100644 index 000000000..2871a1535 --- /dev/null +++ b/src/Nazara/Graphics/Components/LightComponent.cpp @@ -0,0 +1,10 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// 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 +{ +} diff --git a/src/Nazara/Graphics/DirectionalLight.cpp b/src/Nazara/Graphics/DirectionalLight.cpp new file mode 100644 index 000000000..b1f1b8e06 --- /dev/null +++ b/src/Nazara/Graphics/DirectionalLight.cpp @@ -0,0 +1,36 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + float DirectionalLight::ComputeContributionScore(const BoundingVolumef& /*boundingVolume*/) const + { + return -std::numeric_limits::infinity(); + } + + void DirectionalLight::FillLightData(void* data) + { + auto lightOffset = PredefinedLightData::GetOffsets(); + + AccessByOffset(data, lightOffset.lightMemberOffsets.type) = UnderlyingCast(BasicLightType::Directional); + AccessByOffset(data, lightOffset.lightMemberOffsets.color) = Vector4f(m_color.r / 255.f, m_color.g / 255.f, m_color.b / 255.f, m_color.a / 255.f); + AccessByOffset(data, lightOffset.lightMemberOffsets.factor) = Vector2f(m_ambientFactor, m_diffuseFactor); + AccessByOffset(data, lightOffset.lightMemberOffsets.parameter1) = Vector4f(m_direction.x, m_direction.y, m_direction.z, 0.f); + AccessByOffset(data, lightOffset.lightMemberOffsets.shadowMappingFlag) = 0; + } + + void DirectionalLight::UpdateTransform(const Vector3f& /*position*/, const Quaternionf& rotation, const Vector3f& /*scale*/) + { + UpdateRotation(rotation); + } +} diff --git a/src/Nazara/Graphics/ElementRenderer.cpp b/src/Nazara/Graphics/ElementRenderer.cpp index b43681d03..ce189341c 100644 --- a/src/Nazara/Graphics/ElementRenderer.cpp +++ b/src/Nazara/Graphics/ElementRenderer.cpp @@ -9,7 +9,11 @@ namespace Nz { ElementRenderer::~ElementRenderer() = default; - void ElementRenderer::Prepare(const ViewerInstance& /*viewerInstance*/, ElementRendererData& /*rendererData*/, RenderFrame& /*currentFrame*/, const RenderStates& /*renderStates*/, const Pointer* /*elements*/, std::size_t /*elementCount*/) + void ElementRenderer::Prepare(const ViewerInstance& /*viewerInstance*/, ElementRendererData& /*rendererData*/, RenderFrame& /*currentFrame*/, std::size_t /*elementCount*/, const Pointer* /*elements*/, const RenderStates* /*renderStates*/) + { + } + + void ElementRenderer::PrepareEnd(RenderFrame& /*currentFrame*/, ElementRendererData& /*rendererData*/) { } diff --git a/src/Nazara/Graphics/ForwardFramePipeline.cpp b/src/Nazara/Graphics/ForwardFramePipeline.cpp index bc187cdc8..6f4fecfbd 100644 --- a/src/Nazara/Graphics/ForwardFramePipeline.cpp +++ b/src/Nazara/Graphics/ForwardFramePipeline.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -37,37 +38,6 @@ namespace Nz m_elementRenderers.resize(BasicRenderElementCount); m_elementRenderers[UnderlyingCast(BasicRenderElement::SpriteChain)] = std::make_unique(*Graphics::Instance()->GetRenderDevice()); m_elementRenderers[UnderlyingCast(BasicRenderElement::Submesh)] = std::make_unique(); - - auto lightOffset = PredefinedLightData::GetOffsets(); - - m_lightDataBuffer = Graphics::Instance()->GetRenderDevice()->InstantiateBuffer(BufferType::Uniform, lightOffset.totalSize, BufferUsage::DeviceLocal | BufferUsage::Write); - - std::vector staticLightData(lightOffset.totalSize); - /*AccessByOffset(staticLightData.data(), lightOffset.lightCountOffset) = 1; - AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.type) = 0; - AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.color) = Vector4f(1.f, 1.f, 1.f, 1.f); - AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.factor) = Vector2f(0.2f, 1.f); - AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.parameter1) = Vector4f(0.f, 0.f, -1.f, 1.f); - AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.shadowMappingFlag) = 0;*/ - - AccessByOffset(staticLightData.data(), lightOffset.lightCountOffset) = 1; - AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.type) = 1; - AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.color) = Vector4f(1.f, 1.f, 1.f, 1.f); - AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.factor) = Vector2f(0.2f, 1.f); - AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.parameter1) = Vector4f(0.f, 0.f, 0.f, 1.f / 3.f); - AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.shadowMappingFlag) = 0; - - /*AccessByOffset(staticLightData.data(), lightOffset.lightCountOffset) = 1; - AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.type) = 2; - AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.color) = Vector4f(1.f, 1.f, 1.f, 1.f); - AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.factor) = Vector2f(0.2f, 1.f); - AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.parameter1) = Vector4f(0.f, 0.f, 0.f, 1.f / 3.f); - AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.parameter2) = Vector4f(0.f, 0.f, -1.f, 0.f); - AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.parameter3) = Vector4f(DegreeAnglef(15.f).GetCos(), DegreeAnglef(20.f).GetCos(), 0.f, 0.f); - AccessByOffset(staticLightData.data(), lightOffset.lightsOffset + lightOffset.lightMemberOffsets.shadowMappingFlag) = 0;*/ - - if (!m_lightDataBuffer->Fill(staticLightData.data(), 0, staticLightData.size())) - throw std::runtime_error("failed to fill light data buffer"); } void ForwardFramePipeline::InvalidateViewer(AbstractViewer* viewerInstance) @@ -159,6 +129,21 @@ namespace Nz } } + void ForwardFramePipeline::RegisterLight(std::shared_ptr light, UInt32 renderMask) + { + auto& lightData = m_lights[light.get()]; + lightData.light = std::move(light); + lightData.renderMask = renderMask; + lightData.onLightInvalidated.Connect(lightData.light->OnLightDataInvalided, [this](Light*) + { + for (auto&& [viewer, viewerData] : m_viewers) + { + viewerData.rebuildForwardPass = true; + viewerData.prepare = true; + } + }); + } + void ForwardFramePipeline::RegisterViewer(AbstractViewer* viewerInstance, Int32 renderOrder) { auto& viewerData = m_viewers.emplace(viewerInstance, ViewerData{}).first->second; @@ -226,6 +211,9 @@ namespace Nz return currentHash * 23 + newHash; }; + PredefinedLightData lightOffsets = PredefinedLightData::GetOffsets(); + std::size_t lightUboAlignedSize = Align(lightOffsets.totalSize, graphics->GetRenderDevice()->GetDeviceInfo().limits.minUniformBufferOffsetAlignment); + // Render queues handling for (auto&& [viewer, data] : m_viewers) { @@ -307,12 +295,104 @@ namespace Nz { renderFrame.PushForRelease(std::move(viewerData.forwardRenderElements)); viewerData.forwardRenderElements.clear(); - - for (const auto& renderableData : m_visibleRenderables) - renderableData.instancedRenderable->BuildElement(m_forwardPassIndex, *renderableData.worldInstance, viewerData.forwardRenderElements); - viewerData.forwardRegistry.Clear(); viewerData.forwardRenderQueue.Clear(); + viewerData.lightBufferPerLights.clear(); + viewerData.lightPerRenderElement.clear(); + + for (auto& lightDataUbo : m_lightDataBuffers) + { + lightDataUbo.allocation = nullptr; + lightDataUbo.offset = 0; + } + + for (const auto& renderableData : m_visibleRenderables) + { + BoundingVolumef renderableBoundingVolume(renderableData.instancedRenderable->GetAABB()); + renderableBoundingVolume.Update(renderableData.worldInstance->GetWorldMatrix()); + + // Select lights (TODO: Cull lights in frustum) + m_visibleLights.clear(); + for (auto&& [light, lightData] : m_lights) + { + const BoundingVolumef& boundingVolume = light->GetBoundingVolume(); + if ((renderMask & lightData.renderMask) && boundingVolume.Intersect(renderableBoundingVolume.aabb)) + m_visibleLights.push_back(light); + } + + // Sort lights + std::sort(m_visibleLights.begin(), m_visibleLights.end(), [&](Light* lhs, Light* rhs) + { + return lhs->ComputeContributionScore(renderableBoundingVolume) < rhs->ComputeContributionScore(renderableBoundingVolume); + }); + + std::size_t lightCount = std::min(m_visibleLights.size(), MaxLightCountPerDraw); + + LightKey lightKey; + lightKey.fill(nullptr); + for (std::size_t i = 0; i < lightCount; ++i) + lightKey[i] = m_visibleLights[i]; + + RenderBufferView lightUboView; + + auto it = viewerData.lightBufferPerLights.find(lightKey); + if (it == viewerData.lightBufferPerLights.end()) + { + // Prepare light ubo upload + + // Find light ubo + LightDataUbo* targetLightData = nullptr; + for (auto& lightUboData : m_lightDataBuffers) + { + if (lightUboData.offset + lightUboAlignedSize <= lightUboData.renderBuffer->GetSize()) + { + targetLightData = &lightUboData; + break; + } + } + + if (!targetLightData) + { + // Allocate a new light UBO + auto& lightUboData = m_lightDataBuffers.emplace_back(); + lightUboData.renderBuffer = graphics->GetRenderDevice()->InstantiateBuffer(BufferType::Uniform, 256 * lightUboAlignedSize, BufferUsage::DeviceLocal | BufferUsage::Dynamic | BufferUsage::Write); + + targetLightData = &lightUboData; + } + + assert(targetLightData); + if (!targetLightData->allocation) + targetLightData->allocation = &uploadPool.Allocate(targetLightData->renderBuffer->GetSize()); + + void* lightDataPtr = static_cast(targetLightData->allocation->mappedPtr) + targetLightData->offset; + AccessByOffset(lightDataPtr, lightOffsets.lightCountOffset) = SafeCast(lightCount); + + UInt8* lightPtr = static_cast(lightDataPtr) + lightOffsets.lightsOffset; + for (std::size_t i = 0; i < lightCount; ++i) + { + m_visibleLights[i]->FillLightData(lightPtr); + lightPtr += lightOffsets.lightSize; + } + + // Associate render element with light ubo + lightUboView = RenderBufferView(targetLightData->renderBuffer.get(), targetLightData->offset, lightUboAlignedSize); + + targetLightData->offset += lightUboAlignedSize; + + viewerData.lightBufferPerLights.emplace(lightKey, lightUboView); + } + else + lightUboView = it->second; + + std::size_t previousCount = viewerData.forwardRenderElements.size(); + renderableData.instancedRenderable->BuildElement(m_forwardPassIndex, *renderableData.worldInstance, viewerData.forwardRenderElements); + for (std::size_t i = previousCount; i < viewerData.forwardRenderElements.size(); ++i) + { + const RenderElement* element = viewerData.forwardRenderElements[i].get(); + viewerData.lightPerRenderElement.emplace(element, lightUboView); + } + } + for (const auto& renderElement : viewerData.forwardRenderElements) { renderElement->Register(viewerData.forwardRegistry); @@ -320,6 +400,25 @@ namespace Nz } viewerData.forwardRegistry.Finalize(); + + renderFrame.Execute([&](CommandBufferBuilder& builder) + { + builder.BeginDebugRegion("Light UBO Update", Color::Yellow); + { + builder.PreTransferBarrier(); + + for (auto& lightUboData : m_lightDataBuffers) + { + if (!lightUboData.allocation) + continue; + + builder.CopyBuffer(*lightUboData.allocation, RenderBufferView(lightUboData.renderBuffer.get(), 0, lightUboData.offset)); + } + + builder.PostTransferBarrier(); + } + builder.EndDebugRegion(); + }, QueueType::Transfer); } viewerData.forwardRenderQueue.Sort([&](const RenderElement* element) @@ -353,20 +452,41 @@ namespace Nz const auto& viewerInstance = viewer->GetViewerInstance(); - ElementRenderer::RenderStates renderStates; - renderStates.lightData = m_lightDataBuffer; - ProcessRenderQueue(viewerData.depthPrepassRenderQueue, [&](std::size_t elementType, const Pointer* elements, std::size_t elementCount) { ElementRenderer& elementRenderer = *m_elementRenderers[elementType]; - elementRenderer.Prepare(viewerInstance, *rendererData[elementType], renderFrame, renderStates, elements, elementCount); + + m_renderStates.clear(); + m_renderStates.resize(elementCount); + + elementRenderer.Prepare(viewerInstance, *rendererData[elementType], renderFrame, elementCount, elements, m_renderStates.data()); }); + for (std::size_t i = 0; i < m_elementRenderers.size(); ++i) + m_elementRenderers[i]->PrepareEnd(renderFrame, *rendererData[i]); + + auto& lightPerRenderElement = viewerData.lightPerRenderElement; ProcessRenderQueue(viewerData.forwardRenderQueue, [&](std::size_t elementType, const Pointer* elements, std::size_t elementCount) { ElementRenderer& elementRenderer = *m_elementRenderers[elementType]; - elementRenderer.Prepare(viewerInstance, *rendererData[elementType], renderFrame, renderStates, elements, elementCount); + + m_renderStates.clear(); + + m_renderStates.reserve(elementCount); + for (std::size_t i = 0; i < elementCount; ++i) + { + auto it = lightPerRenderElement.find(elements[i]); + assert(it != lightPerRenderElement.end()); + + auto& renderStates = m_renderStates.emplace_back(); + renderStates.lightData = it->second; + } + + elementRenderer.Prepare(viewerInstance, *rendererData[elementType], renderFrame, elementCount, elements, m_renderStates.data()); }); + + for (std::size_t i = 0; i < m_elementRenderers.size(); ++i) + m_elementRenderers[i]->PrepareEnd(renderFrame, *rendererData[i]); } if (m_bakedFrameGraph.Resize(renderFrame)) @@ -493,6 +613,17 @@ namespace Nz } } + void ForwardFramePipeline::UnregisterLight(Light* light) + { + m_lights.erase(light); + + for (auto&& [viewer, viewerData] : m_viewers) + { + viewerData.rebuildForwardPass = true; + viewerData.prepare = true; + } + } + void ForwardFramePipeline::UnregisterViewer(AbstractViewer* viewerInstance) { m_viewers.erase(viewerInstance); @@ -544,7 +675,7 @@ namespace Nz ProcessRenderQueue(viewerData.depthPrepassRenderQueue, [&](std::size_t elementType, const Pointer* elements, std::size_t elementCount) { ElementRenderer& elementRenderer = *m_elementRenderers[elementType]; - elementRenderer.Render(viewerInstance, *viewerData.elementRendererData[elementType], builder, elements, elementCount); + elementRenderer.Render(viewerInstance, *viewerData.elementRendererData[elementType], builder, elementCount, elements); }); }); @@ -576,7 +707,7 @@ namespace Nz ProcessRenderQueue(viewerData.forwardRenderQueue, [&](std::size_t elementType, const Pointer* elements, std::size_t elementCount) { ElementRenderer& elementRenderer = *m_elementRenderers[elementType]; - elementRenderer.Render(viewerInstance , *viewerData.elementRendererData[elementType], builder, elements, elementCount); + elementRenderer.Render(viewerInstance, *viewerData.elementRendererData[elementType], builder, elementCount, elements); }); }); } diff --git a/src/Nazara/Graphics/Light.cpp b/src/Nazara/Graphics/Light.cpp new file mode 100644 index 000000000..dc94e501e --- /dev/null +++ b/src/Nazara/Graphics/Light.cpp @@ -0,0 +1,11 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// 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 +{ + Light::~Light() = default; +} diff --git a/src/Nazara/Graphics/PointLight.cpp b/src/Nazara/Graphics/PointLight.cpp new file mode 100644 index 000000000..cbf81387b --- /dev/null +++ b/src/Nazara/Graphics/PointLight.cpp @@ -0,0 +1,36 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + float PointLight::ComputeContributionScore(const BoundingVolumef& boundingVolume) const + { + // TODO: take luminosity/radius into account + return Vector3f::SquaredDistance(m_position, boundingVolume.aabb.GetCenter()); + } + + void PointLight::FillLightData(void* data) + { + auto lightOffset = PredefinedLightData::GetOffsets(); + + AccessByOffset(data, lightOffset.lightMemberOffsets.type) = UnderlyingCast(BasicLightType::Point); + AccessByOffset(data, lightOffset.lightMemberOffsets.color) = Vector4f(m_color.r / 255.f, m_color.g / 255.f, m_color.b / 255.f, m_color.a / 255.f); + AccessByOffset(data, lightOffset.lightMemberOffsets.factor) = Vector2f(m_ambientFactor, m_diffuseFactor); + AccessByOffset(data, lightOffset.lightMemberOffsets.parameter1) = Vector4f(m_position.x, m_position.y, m_position.z, m_invRadius); + AccessByOffset(data, lightOffset.lightMemberOffsets.shadowMappingFlag) = 0; + } + + void PointLight::UpdateTransform(const Vector3f& position, const Quaternionf& /*rotation*/, const Vector3f& /*scale*/) + { + UpdatePosition(position); + } +} diff --git a/src/Nazara/Graphics/Resources/Shaders/phong_material.nzsl b/src/Nazara/Graphics/Resources/Shaders/phong_material.nzsl index ce623ab78..984088ed4 100644 --- a/src/Nazara/Graphics/Resources/Shaders/phong_material.nzsl +++ b/src/Nazara/Graphics/Resources/Shaders/phong_material.nzsl @@ -72,7 +72,7 @@ struct Light struct LightData { lights: array[Light, MaxLightCount], - lightCount: u32 + lightCount: u32, } [layout(std140)] @@ -250,7 +250,7 @@ fn main(input: VertToFrag) -> FragOut else { let output: FragOut; - output.RenderTarget0 = diffuseColor.w; + output.RenderTarget0 = diffuseColor; return output; } } diff --git a/src/Nazara/Graphics/SpotLight.cpp b/src/Nazara/Graphics/SpotLight.cpp new file mode 100644 index 000000000..72ecebdc3 --- /dev/null +++ b/src/Nazara/Graphics/SpotLight.cpp @@ -0,0 +1,39 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + float SpotLight::ComputeContributionScore(const BoundingVolumef& boundingVolume) const + { + // TODO: take luminosity/radius/direction into account + return Vector3f::SquaredDistance(m_position, boundingVolume.aabb.GetCenter()); + } + + void SpotLight::FillLightData(void* data) + { + auto lightOffset = PredefinedLightData::GetOffsets(); + + AccessByOffset(data, lightOffset.lightMemberOffsets.type) = UnderlyingCast(BasicLightType::Spot); + AccessByOffset(data, lightOffset.lightMemberOffsets.color) = Vector4f(m_color.r / 255.f, m_color.g / 255.f, m_color.b / 255.f, m_color.a / 255.f); + AccessByOffset(data, lightOffset.lightMemberOffsets.factor) = Vector2f(m_ambientFactor, m_diffuseFactor); + AccessByOffset(data, lightOffset.lightMemberOffsets.parameter1) = Vector4f(m_position.x, m_position.y, m_position.z, m_invRadius); + AccessByOffset(data, lightOffset.lightMemberOffsets.parameter2) = Vector4f(m_direction.x, m_direction.y, m_direction.z, 0.f); + AccessByOffset(data, lightOffset.lightMemberOffsets.parameter3) = Vector4f(m_innerAngleCos, m_outerAngleCos, 0.f, 0.f); + AccessByOffset(data, lightOffset.lightMemberOffsets.shadowMappingFlag) = 0; + } + + void SpotLight::UpdateTransform(const Vector3f& position, const Quaternionf& rotation, const Vector3f& /*scale*/) + { + UpdatePosition(position); + UpdateRotation(rotation); + } +} diff --git a/src/Nazara/Graphics/SpriteChainRenderer.cpp b/src/Nazara/Graphics/SpriteChainRenderer.cpp index 69d64cfc3..60dba6ec4 100644 --- a/src/Nazara/Graphics/SpriteChainRenderer.cpp +++ b/src/Nazara/Graphics/SpriteChainRenderer.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -49,7 +50,7 @@ namespace Nz return std::make_unique(); } - void SpriteChainRenderer::Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, const RenderStates& renderStates, const Pointer* elements, std::size_t elementCount) + void SpriteChainRenderer::Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, std::size_t elementCount, const Pointer* elements, const RenderStates* renderStates) { Graphics* graphics = Graphics::Instance(); @@ -57,103 +58,65 @@ namespace Nz Recti invalidScissorBox(-1, -1, -1, -1); - std::size_t firstQuadIndex = 0; - SpriteChainRendererData::DrawCall* currentDrawCall = nullptr; - UploadPool::Allocation* currentAllocation = nullptr; - UInt8* currentAllocationMemPtr = nullptr; - const VertexDeclaration* currentVertexDeclaration = nullptr; - RenderBuffer* currentVertexBuffer = nullptr; - const MaterialPass* currentMaterialPass = nullptr; - const RenderPipeline* currentPipeline = nullptr; - const ShaderBinding* currentShaderBinding = nullptr; - const Texture* currentTextureOverlay = nullptr; - const WorldInstance* currentWorldInstance = nullptr; - Recti currentScissorBox = invalidScissorBox; - - auto FlushDrawCall = [&]() - { - currentDrawCall = nullptr; - }; - - auto FlushDrawData = [&]() - { - FlushDrawCall(); - - currentShaderBinding = nullptr; - }; - - auto Flush = [&]() - { - // changing vertex buffer always mean we have to switch draw calls - FlushDrawCall(); - - if (currentAllocation) - { - std::size_t size = currentAllocationMemPtr - static_cast(currentAllocation->mappedPtr); - - m_pendingCopies.emplace_back(BufferCopy{ - currentVertexBuffer, - currentAllocation, - size - }); - - firstQuadIndex = 0; - currentAllocation = nullptr; - currentVertexBuffer = nullptr; - } - }; + const auto& defaultSampler = graphics->GetSamplerCache().Get({}); std::size_t oldDrawCallCount = data.drawCalls.size(); - const auto& defaultSampler = graphics->GetSamplerCache().Get({}); for (std::size_t i = 0; i < elementCount; ++i) { assert(elements[i]->GetElementType() == UnderlyingCast(BasicRenderElement::SpriteChain)); const RenderSpriteChain& spriteChain = static_cast(*elements[i]); + const RenderStates& renderState = renderStates[i]; const VertexDeclaration* vertexDeclaration = spriteChain.GetVertexDeclaration(); std::size_t stride = vertexDeclaration->GetStride(); - if (currentVertexDeclaration != vertexDeclaration) + if (m_pendingData.currentVertexDeclaration != vertexDeclaration) { // TODO: It's be possible to use another vertex declaration with the same vertex buffer but currently very complicated // Wait until buffer rewrite Flush(); - currentVertexDeclaration = vertexDeclaration; + m_pendingData.currentVertexDeclaration = vertexDeclaration; } - if (const RenderPipeline* pipeline = &spriteChain.GetRenderPipeline(); currentPipeline != pipeline) + if (const RenderPipeline* pipeline = &spriteChain.GetRenderPipeline(); m_pendingData.currentPipeline != pipeline) { FlushDrawCall(); - currentPipeline = pipeline; + m_pendingData.currentPipeline = pipeline; } - if (const MaterialPass* materialPass = &spriteChain.GetMaterialPass(); currentMaterialPass != materialPass) + if (const MaterialPass* materialPass = &spriteChain.GetMaterialPass(); m_pendingData.currentMaterialPass != materialPass) { FlushDrawData(); - currentMaterialPass = materialPass; + m_pendingData.currentMaterialPass = materialPass; } - if (const WorldInstance* worldInstance = &spriteChain.GetWorldInstance(); currentWorldInstance != worldInstance) + if (const WorldInstance* worldInstance = &spriteChain.GetWorldInstance(); m_pendingData.currentWorldInstance != worldInstance) { // TODO: Flushing draw calls on instance binding means we can have e.g. 1000 sprites rendered using a draw call for each one // which is far from being efficient, using some bindless could help (or at least instancing?) FlushDrawData(); - currentWorldInstance = worldInstance; + m_pendingData.currentWorldInstance = worldInstance; } - if (const Texture* textureOverlay = spriteChain.GetTextureOverlay(); currentTextureOverlay != textureOverlay) + if (const Texture* textureOverlay = spriteChain.GetTextureOverlay(); m_pendingData.currentTextureOverlay != textureOverlay) { FlushDrawData(); - currentTextureOverlay = textureOverlay; + m_pendingData.currentTextureOverlay = textureOverlay; + } + + if (m_pendingData.currentLightData != renderState.lightData) + { + FlushDrawData(); + m_pendingData.currentLightData = renderState.lightData; } const Recti& scissorBox = spriteChain.GetScissorBox(); const Recti& targetScissorBox = (scissorBox.width >= 0) ? scissorBox : invalidScissorBox; - if (currentScissorBox != targetScissorBox) + if (m_pendingData.currentScissorBox != targetScissorBox) { - FlushDrawData(); - currentScissorBox = targetScissorBox; + FlushDrawCall(); + m_pendingData.currentScissorBox = targetScissorBox; } std::size_t remainingQuads = spriteChain.GetSpriteCount(); @@ -161,10 +124,10 @@ namespace Nz while (remainingQuads > 0) { - if (!currentAllocation) + if (!m_pendingData.currentAllocation) { - currentAllocation = ¤tFrame.GetUploadPool().Allocate(m_maxVertexBufferSize); - currentAllocationMemPtr = static_cast(currentAllocation->mappedPtr); + m_pendingData.currentAllocation = ¤tFrame.GetUploadPool().Allocate(m_maxVertexBufferSize); + m_pendingData.currentAllocationMemPtr = static_cast(m_pendingData.currentAllocation->mappedPtr); std::shared_ptr vertexBuffer; @@ -177,12 +140,12 @@ namespace Nz else vertexBuffer = m_device.InstantiateBuffer(BufferType::Vertex, m_maxVertexBufferSize, BufferUsage::DeviceLocal | BufferUsage::Dynamic | BufferUsage::Write); - currentVertexBuffer = vertexBuffer.get(); + m_pendingData.currentVertexBuffer = vertexBuffer.get(); data.vertexBuffers.emplace_back(std::move(vertexBuffer)); } - if (!currentShaderBinding) + if (!m_pendingData.currentShaderBinding) { m_bindingCache.clear(); @@ -193,7 +156,7 @@ namespace Nz const auto& matSettings = materialPass.GetSettings(); if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::InstanceDataUbo); bindingIndex != MaterialSettings::InvalidIndex) { - const auto& instanceBuffer = currentWorldInstance->GetInstanceBuffer(); + const auto& instanceBuffer = m_pendingData.currentWorldInstance->GetInstanceBuffer(); auto& bindingEntry = m_bindingCache.emplace_back(); bindingEntry.bindingIndex = bindingIndex; @@ -203,13 +166,13 @@ namespace Nz }; } - if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::LightDataUbo); bindingIndex != MaterialSettings::InvalidIndex) + if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::LightDataUbo); bindingIndex != MaterialSettings::InvalidIndex && m_pendingData.currentLightData) { auto& bindingEntry = m_bindingCache.emplace_back(); bindingEntry.bindingIndex = bindingIndex; bindingEntry.content = ShaderBinding::UniformBufferBinding{ - renderStates.lightData.get(), - 0, renderStates.lightData->GetSize() + m_pendingData.currentLightData.GetBuffer(), + m_pendingData.currentLightData.GetOffset(), m_pendingData.currentLightData.GetSize() }; } @@ -230,33 +193,33 @@ namespace Nz auto& bindingEntry = m_bindingCache.emplace_back(); bindingEntry.bindingIndex = bindingIndex; bindingEntry.content = ShaderBinding::TextureBinding{ - currentTextureOverlay, defaultSampler.get() + m_pendingData.currentTextureOverlay, defaultSampler.get() }; } - ShaderBindingPtr drawDataBinding = currentPipeline->GetPipelineInfo().pipelineLayout->AllocateShaderBinding(0); + ShaderBindingPtr drawDataBinding = m_pendingData.currentPipeline->GetPipelineInfo().pipelineLayout->AllocateShaderBinding(0); drawDataBinding->Update(m_bindingCache.data(), m_bindingCache.size()); - currentShaderBinding = drawDataBinding.get(); + m_pendingData.currentShaderBinding = drawDataBinding.get(); data.shaderBindings.emplace_back(std::move(drawDataBinding)); } - if (!currentDrawCall) + if (!m_pendingData.currentDrawCall) { data.drawCalls.push_back(SpriteChainRendererData::DrawCall{ - currentVertexBuffer, - currentPipeline, - currentShaderBinding, - 6 * firstQuadIndex, + m_pendingData.currentVertexBuffer, + m_pendingData.currentPipeline, + m_pendingData.currentShaderBinding, + 6 * m_pendingData.firstQuadIndex, 0, - currentScissorBox + m_pendingData.currentScissorBox }); - currentDrawCall = &data.drawCalls.back(); + m_pendingData.currentDrawCall = &data.drawCalls.back(); } - std::size_t remainingSpace = m_maxVertexBufferSize - (currentAllocationMemPtr - static_cast(currentAllocation->mappedPtr)); + std::size_t remainingSpace = m_maxVertexBufferSize - (m_pendingData.currentAllocationMemPtr - static_cast(m_pendingData.currentAllocation->mappedPtr)); std::size_t maxQuads = remainingSpace / (4 * stride); if (maxQuads == 0) { @@ -267,12 +230,12 @@ namespace Nz std::size_t copiedQuadCount = std::min(maxQuads, remainingQuads); std::size_t copiedSize = 4 * copiedQuadCount * stride; - std::memcpy(currentAllocationMemPtr, spriteData, copiedSize); - currentAllocationMemPtr += copiedSize; + std::memcpy(m_pendingData.currentAllocationMemPtr, spriteData, copiedSize); + m_pendingData.currentAllocationMemPtr += copiedSize; spriteData += copiedSize; - firstQuadIndex += copiedQuadCount; - currentDrawCall->quadCount += copiedQuadCount; + m_pendingData.firstQuadIndex += copiedQuadCount; + m_pendingData.currentDrawCall->quadCount += copiedQuadCount; remainingQuads -= copiedQuadCount; // If there's still data to copy, it means buffer is full, flush it @@ -281,12 +244,16 @@ namespace Nz } } - //TODO: Add Finish()/PrepareEnd() call to allow to reuse buffers/draw calls for multiple Prepare calls - Flush(); + FlushDrawCall(); const RenderSpriteChain* firstSpriteChain = static_cast(elements[0]); std::size_t drawCallCount = data.drawCalls.size() - oldDrawCallCount; data.drawCallPerElement[firstSpriteChain] = SpriteChainRendererData::DrawCallIndices{ oldDrawCallCount, drawCallCount }; + } + + void SpriteChainRenderer::PrepareEnd(RenderFrame& currentFrame, ElementRendererData& /*rendererData*/) + { + Flush(); if (!m_pendingCopies.empty()) { @@ -300,9 +267,11 @@ namespace Nz m_pendingCopies.clear(); } + + m_pendingData = PendingData{}; } - void SpriteChainRenderer::Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, const Pointer* elements, std::size_t /*elementCount*/) + void SpriteChainRenderer::Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, std::size_t /*elementCount*/, const Pointer* elements) { auto& data = static_cast(rendererData); @@ -374,4 +343,37 @@ namespace Nz data.drawCalls.clear(); } + + void SpriteChainRenderer::Flush() + { + // changing vertex buffer always mean we have to switch draw calls + FlushDrawCall(); + + if (m_pendingData.currentAllocation) + { + std::size_t size = m_pendingData.currentAllocationMemPtr - static_cast(m_pendingData.currentAllocation->mappedPtr); + + m_pendingCopies.emplace_back(BufferCopy{ + m_pendingData.currentVertexBuffer, + m_pendingData.currentAllocation, + size + }); + + m_pendingData.firstQuadIndex = 0; + m_pendingData.currentAllocation = nullptr; + m_pendingData.currentVertexBuffer = nullptr; + } + } + + void SpriteChainRenderer::FlushDrawCall() + { + m_pendingData.currentDrawCall = nullptr; + } + + void SpriteChainRenderer::FlushDrawData() + { + FlushDrawCall(); + + m_pendingData.currentShaderBinding = nullptr; + } } diff --git a/src/Nazara/Graphics/SubmeshRenderer.cpp b/src/Nazara/Graphics/SubmeshRenderer.cpp index 93e5913f2..6b048d88b 100644 --- a/src/Nazara/Graphics/SubmeshRenderer.cpp +++ b/src/Nazara/Graphics/SubmeshRenderer.cpp @@ -17,7 +17,7 @@ namespace Nz return std::make_unique(); } - void SubmeshRenderer::Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& /*currentFrame*/, const RenderStates& renderStates, const Pointer* elements, std::size_t elementCount) + void SubmeshRenderer::Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& /*currentFrame*/, std::size_t elementCount, const Pointer* elements, const RenderStates* renderStates) { Graphics* graphics = Graphics::Instance(); @@ -32,6 +32,7 @@ namespace Nz const ShaderBinding* currentShaderBinding = nullptr; const WorldInstance* currentWorldInstance = nullptr; Recti currentScissorBox = invalidScissorBox; + RenderBufferView currentLightData; auto FlushDrawCall = [&]() { @@ -48,10 +49,13 @@ namespace Nz const auto& whiteTexture = Graphics::Instance()->GetDefaultTextures().whiteTextures[UnderlyingCast(ImageType::E2D)]; const auto& defaultSampler = graphics->GetSamplerCache().Get({}); + std::size_t oldDrawCallCount = data.drawCalls.size(); + for (std::size_t i = 0; i < elementCount; ++i) { assert(elements[i]->GetElementType() == UnderlyingCast(BasicRenderElement::Submesh)); const RenderSubmesh& submesh = static_cast(*elements[i]); + const RenderStates& renderState = renderStates[i]; if (const RenderPipeline* pipeline = submesh.GetRenderPipeline(); currentPipeline != pipeline) { @@ -85,6 +89,12 @@ namespace Nz currentWorldInstance = worldInstance; } + if (currentLightData != renderState.lightData) + { + FlushDrawData(); + currentLightData = renderState.lightData; + } + const Recti& scissorBox = submesh.GetScissorBox(); const Recti& targetScissorBox = (scissorBox.width >= 0) ? scissorBox : invalidScissorBox; if (currentScissorBox != targetScissorBox) @@ -114,13 +124,13 @@ namespace Nz }; } - if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::LightDataUbo); bindingIndex != MaterialSettings::InvalidIndex) + if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::LightDataUbo); bindingIndex != MaterialSettings::InvalidIndex && currentLightData) { auto& bindingEntry = m_bindingCache.emplace_back(); bindingEntry.bindingIndex = bindingIndex; bindingEntry.content = ShaderBinding::UniformBufferBinding{ - renderStates.lightData.get(), - 0, renderStates.lightData->GetSize() + currentLightData.GetBuffer(), + currentLightData.GetOffset(), currentLightData.GetSize() }; } @@ -154,6 +164,7 @@ namespace Nz } auto& drawCall = data.drawCalls.emplace_back(); + drawCall.firstIndex = 0; drawCall.indexBuffer = currentIndexBuffer; drawCall.indexCount = submesh.GetIndexCount(); drawCall.renderPipeline = currentPipeline; @@ -161,9 +172,13 @@ namespace Nz drawCall.shaderBinding = currentShaderBinding; drawCall.vertexBuffer = currentVertexBuffer; } + + const RenderSubmesh* firstSubmesh = static_cast(elements[0]); + std::size_t drawCallCount = data.drawCalls.size() - oldDrawCallCount; + data.drawCallPerElement[firstSubmesh] = SubmeshRendererData::DrawCallIndices{ oldDrawCallCount, drawCallCount }; } - void SubmeshRenderer::Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, const Pointer* /*elements*/, std::size_t /*elementCount*/) + void SubmeshRenderer::Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, std::size_t /*elementCount*/, const Pointer* elements) { auto& data = static_cast(rendererData); @@ -176,8 +191,16 @@ namespace Nz const ShaderBinding* currentShaderBinding = nullptr; Recti currentScissorBox(-1, -1, -1, -1); - for (const auto& drawData : data.drawCalls) + const RenderSubmesh* firstSubmesh = static_cast(elements[0]); + auto it = data.drawCallPerElement.find(firstSubmesh); + assert(it != data.drawCallPerElement.end()); + + const auto& indices = it->second; + + for (std::size_t i = 0; i < indices.count; ++i) { + const auto& drawData = data.drawCalls[indices.start + i]; + if (currentPipeline != drawData.renderPipeline) { commandBuffer.BindPipeline(*drawData.renderPipeline); @@ -210,9 +233,9 @@ namespace Nz } if (currentIndexBuffer) - commandBuffer.DrawIndexed(SafeCast(drawData.indexCount)); + commandBuffer.DrawIndexed(SafeCast(drawData.indexCount), 1U, SafeCast(drawData.firstIndex)); else - commandBuffer.Draw(SafeCast(drawData.indexCount)); + commandBuffer.Draw(SafeCast(drawData.indexCount), 1U, SafeCast(drawData.firstIndex)); } } diff --git a/src/Nazara/Graphics/Systems/RenderSystem.cpp b/src/Nazara/Graphics/Systems/RenderSystem.cpp index ecbaee8cf..47adc692e 100644 --- a/src/Nazara/Graphics/Systems/RenderSystem.cpp +++ b/src/Nazara/Graphics/Systems/RenderSystem.cpp @@ -18,10 +18,12 @@ namespace Nz { RenderSystem::RenderSystem(entt::registry& registry) : m_cameraConstructObserver(registry, entt::collector.group()), - m_graphicsConstructObserver(registry, entt::collector.group()) + m_graphicsConstructObserver(registry, entt::collector.group()), + m_lightConstructObserver(registry, entt::collector.group()) { m_cameraDestroyConnection = registry.on_destroy().connect<&RenderSystem::OnCameraDestroy>(this); m_graphicsDestroyConnection = registry.on_destroy().connect<&RenderSystem::OnGraphicsDestroy>(this); + m_lightDestroyConnection = registry.on_destroy().connect<&RenderSystem::OnLightDestroy>(this); m_nodeDestroyConnection = registry.on_destroy().connect<&RenderSystem::OnNodeDestroy>(this); m_pipeline = std::make_unique(); @@ -31,8 +33,10 @@ namespace Nz { m_cameraConstructObserver.disconnect(); m_graphicsConstructObserver.disconnect(); + m_lightConstructObserver.disconnect(); m_cameraDestroyConnection.release(); m_graphicsDestroyConnection.release(); + m_lightDestroyConnection.release(); m_nodeDestroyConnection.release(); } @@ -67,13 +71,13 @@ namespace Nz m_pipeline->RegisterInstancedDrawable(worldInstance, renderableEntry.renderable.get(), renderableEntry.renderMask); } - m_invalidatedWorldNode.insert(entity); + m_invalidatedGfxWorldNode.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); + m_invalidatedGfxWorldNode.insert(entity); }); graphicsEntity.onRenderableAttached.Connect(entityGfx.OnRenderableAttached, [this](GraphicsComponent* gfx, const GraphicsComponent::Renderable& renderableEntry) @@ -98,13 +102,64 @@ namespace Nz { if (isVisible) { - m_newlyHiddenEntities.erase(entity); - m_newlyVisibleEntities.insert(entity); + m_newlyHiddenGfxEntities.erase(entity); + m_newlyVisibleGfxEntities.insert(entity); } else { - m_newlyHiddenEntities.insert(entity); - m_newlyVisibleEntities.erase(entity); + m_newlyHiddenGfxEntities.insert(entity); + m_newlyVisibleGfxEntities.erase(entity); + } + }); + }); + + m_lightConstructObserver.each([&](entt::entity entity) + { + LightComponent& entityLight = registry.get(entity); + NodeComponent& entityNode = registry.get(entity); + + if (entityLight.IsVisible()) + { + for (const auto& lightEntry : entityLight.GetLights()) + m_pipeline->RegisterLight(lightEntry.light, lightEntry.renderMask); + } + + m_invalidatedLightWorldNode.insert(entity); + + assert(m_lightEntities.find(entity) == m_lightEntities.end()); + auto& lightEntity = m_lightEntities[entity]; + lightEntity.onNodeInvalidation.Connect(entityNode.OnNodeInvalidation, [this, entity](const Node* /*node*/) + { + m_invalidatedLightWorldNode.insert(entity); + }); + + lightEntity.onLightAttached.Connect(entityLight.OnLightAttached, [this](LightComponent* light, const LightComponent::LightEntry& lightEntry) + { + if (!light->IsVisible()) + return; + + m_pipeline->RegisterLight(lightEntry.light, lightEntry.renderMask); + }); + + lightEntity.onLightDetach.Connect(entityLight.OnLightDetach, [this](LightComponent* light, const LightComponent::LightEntry& lightEntry) + { + if (!light->IsVisible()) + return; + + m_pipeline->UnregisterLight(lightEntry.light.get()); + }); + + lightEntity.onVisibilityUpdate.Connect(entityLight.OnVisibilityUpdate, [this, entity](LightComponent* /*light*/, bool isVisible) + { + if (isVisible) + { + m_newlyHiddenLightEntities.erase(entity); + m_newlyVisibleLightEntities.insert(entity); + } + else + { + m_newlyHiddenLightEntities.insert(entity); + m_newlyVisibleLightEntities.erase(entity); } }); }); @@ -127,9 +182,22 @@ namespace Nz void RenderSystem::OnGraphicsDestroy(entt::registry& registry, entt::entity entity) { m_graphicsEntities.erase(entity); - m_invalidatedWorldNode.erase(entity); - m_newlyHiddenEntities.erase(entity); - m_newlyVisibleEntities.erase(entity); + m_invalidatedGfxWorldNode.erase(entity); + m_newlyHiddenGfxEntities.erase(entity); + m_newlyVisibleGfxEntities.erase(entity); + + GraphicsComponent& entityGfx = registry.get(entity); + const WorldInstancePtr& worldInstance = entityGfx.GetWorldInstance(); + for (const auto& renderableEntry : entityGfx.GetRenderables()) + m_pipeline->UnregisterInstancedDrawable(worldInstance, renderableEntry.renderable.get()); + } + + void RenderSystem::OnLightDestroy(entt::registry& registry, entt::entity entity) + { + m_lightEntities.erase(entity); + m_invalidatedLightWorldNode.erase(entity); + m_newlyHiddenLightEntities.erase(entity); + m_newlyVisibleLightEntities.erase(entity); GraphicsComponent& entityGfx = registry.get(entity); const WorldInstancePtr& worldInstance = entityGfx.GetWorldInstance(); @@ -139,14 +207,19 @@ namespace Nz void RenderSystem::OnNodeDestroy(entt::registry& registry, entt::entity entity) { - m_newlyHiddenEntities.erase(entity); - m_newlyVisibleEntities.erase(entity); + m_newlyHiddenGfxEntities.erase(entity); + m_newlyVisibleGfxEntities.erase(entity); + m_newlyHiddenLightEntities.erase(entity); + m_newlyVisibleLightEntities.erase(entity); if (registry.try_get(entity)) OnCameraDestroy(registry, entity); if (registry.try_get(entity)) OnGraphicsDestroy(registry, entity); + + if (registry.try_get(entity)) + OnLightDestroy(registry, entity); } void RenderSystem::UpdateInstances(entt::registry& registry) @@ -166,7 +239,7 @@ namespace Nz } m_invalidatedCameraNode.clear(); - for (entt::entity entity : m_invalidatedWorldNode) + for (entt::entity entity : m_invalidatedGfxWorldNode) { const NodeComponent& entityNode = registry.get(entity); GraphicsComponent& entityGraphics = registry.get(entity); @@ -176,13 +249,27 @@ namespace Nz m_pipeline->InvalidateWorldInstance(worldInstance.get()); } - m_invalidatedWorldNode.clear(); + m_invalidatedGfxWorldNode.clear(); + + for (entt::entity entity : m_invalidatedLightWorldNode) + { + const NodeComponent& entityNode = registry.get(entity); + LightComponent& entityLight = registry.get(entity); + + const Vector3f& position = entityNode.GetPosition(CoordSys::Global); + const Quaternionf& rotation = entityNode.GetRotation(CoordSys::Global); + const Vector3f& scale = entityNode.GetScale(CoordSys::Global); + + for (const auto& lightEntry : entityLight.GetLights()) + lightEntry.light->UpdateTransform(position, rotation, scale); + } + m_invalidatedLightWorldNode.clear(); } void RenderSystem::UpdateVisibility(entt::registry& registry) { - // Unregister drawables for hidden entities - for (entt::entity entity : m_newlyHiddenEntities) + // Unregister drawable for hidden entities + for (entt::entity entity : m_newlyHiddenGfxEntities) { GraphicsComponent& entityGfx = registry.get(entity); @@ -190,10 +277,10 @@ namespace Nz for (const auto& renderableEntry : entityGfx.GetRenderables()) m_pipeline->UnregisterInstancedDrawable(worldInstance, renderableEntry.renderable.get()); } - m_newlyHiddenEntities.clear(); + m_newlyHiddenGfxEntities.clear(); - // Register drawables for newly visible entities - for (entt::entity entity : m_newlyVisibleEntities) + // Register drawable for newly visible entities + for (entt::entity entity : m_newlyVisibleGfxEntities) { GraphicsComponent& entityGfx = registry.get(entity); @@ -201,6 +288,6 @@ namespace Nz for (const auto& renderableEntry : entityGfx.GetRenderables()) m_pipeline->RegisterInstancedDrawable(worldInstance, renderableEntry.renderable.get(), renderableEntry.renderMask); } - m_newlyVisibleEntities.clear(); + m_newlyVisibleGfxEntities.clear(); } } diff --git a/src/Nazara/Network/Win32/SocketImpl.cpp b/src/Nazara/Network/Win32/SocketImpl.cpp index c14f6d988..694e65ce9 100644 --- a/src/Nazara/Network/Win32/SocketImpl.cpp +++ b/src/Nazara/Network/Win32/SocketImpl.cpp @@ -42,7 +42,7 @@ namespace Nz NazaraAssert(handle != InvalidHandle, "Invalid handle"); IpAddressImpl::SockAddrBuffer nameBuffer; - std::fill(nameBuffer.begin(), nameBuffer.end(), 0); + nameBuffer.fill(0); int bufferLength = static_cast(nameBuffer.size()); diff --git a/src/Nazara/Utility/AlgorithmUtility.cpp b/src/Nazara/Utility/AlgorithmUtility.cpp index fb958082e..85d891001 100644 --- a/src/Nazara/Utility/AlgorithmUtility.cpp +++ b/src/Nazara/Utility/AlgorithmUtility.cpp @@ -665,7 +665,7 @@ namespace Nz *vertexCount = xVertexCount*2 + yVertexCount*2 + zVertexCount*2; } - UInt64 ComputeCacheMissCount(IndexIterator indices, std::size_t indexCount) + UInt64 ComputeCacheMissCount(IndexIterator indices, UInt32 indexCount) { VertexCache cache(indices, indexCount); return cache.GetMissCount(); From 109127459b2c335d6ad24fe6ede8b39e7cd5b8e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 2 Feb 2022 13:47:29 +0100 Subject: [PATCH 12/14] Graphics/ForwardFramePipeline: Reuse light UBO --- .../Nazara/Graphics/ForwardFramePipeline.hpp | 6 +++++ src/Nazara/Graphics/ForwardFramePipeline.cpp | 23 ++++++++++++++----- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/include/Nazara/Graphics/ForwardFramePipeline.hpp b/include/Nazara/Graphics/ForwardFramePipeline.hpp index f7419679a..2e680b9d0 100644 --- a/include/Nazara/Graphics/ForwardFramePipeline.hpp +++ b/include/Nazara/Graphics/ForwardFramePipeline.hpp @@ -88,6 +88,11 @@ namespace Nz UploadPool::Allocation* allocation = nullptr; }; + struct LightUboPool + { + std::vector> lightUboBuffers; + }; + struct MaterialData { std::size_t usedCount = 0; @@ -139,6 +144,7 @@ namespace Nz std::size_t m_depthPassIndex; std::size_t m_forwardPassIndex; + std::shared_ptr m_lightUboPool; std::unordered_map m_viewers; std::unordered_map m_lights; std::unordered_map m_materials; diff --git a/src/Nazara/Graphics/ForwardFramePipeline.cpp b/src/Nazara/Graphics/ForwardFramePipeline.cpp index 6f4fecfbd..e440d5fdf 100644 --- a/src/Nazara/Graphics/ForwardFramePipeline.cpp +++ b/src/Nazara/Graphics/ForwardFramePipeline.cpp @@ -38,6 +38,8 @@ namespace Nz m_elementRenderers.resize(BasicRenderElementCount); m_elementRenderers[UnderlyingCast(BasicRenderElement::SpriteChain)] = std::make_unique(*Graphics::Instance()->GetRenderDevice()); m_elementRenderers[UnderlyingCast(BasicRenderElement::Submesh)] = std::make_unique(); + + m_lightUboPool = std::make_shared(); } void ForwardFramePipeline::InvalidateViewer(AbstractViewer* viewerInstance) @@ -302,9 +304,12 @@ namespace Nz for (auto& lightDataUbo : m_lightDataBuffers) { - lightDataUbo.allocation = nullptr; - lightDataUbo.offset = 0; + renderFrame.PushReleaseCallback([pool = m_lightUboPool, lightUbo = std::move(lightDataUbo.renderBuffer)]() + { + pool->lightUboBuffers.push_back(std::move(lightUbo)); + }); } + m_lightDataBuffers.clear(); for (const auto& renderableData : m_visibleRenderables) { @@ -353,9 +358,17 @@ namespace Nz if (!targetLightData) { - // Allocate a new light UBO + // Make a new light UBO auto& lightUboData = m_lightDataBuffers.emplace_back(); - lightUboData.renderBuffer = graphics->GetRenderDevice()->InstantiateBuffer(BufferType::Uniform, 256 * lightUboAlignedSize, BufferUsage::DeviceLocal | BufferUsage::Dynamic | BufferUsage::Write); + + // Reuse from pool if possible + if (!m_lightUboPool->lightUboBuffers.empty()) + { + lightUboData.renderBuffer = m_lightUboPool->lightUboBuffers.back(); + m_lightUboPool->lightUboBuffers.pop_back(); + } + else + lightUboData.renderBuffer = graphics->GetRenderDevice()->InstantiateBuffer(BufferType::Uniform, 256 * lightUboAlignedSize, BufferUsage::DeviceLocal | BufferUsage::Dynamic | BufferUsage::Write); targetLightData = &lightUboData; } @@ -405,8 +418,6 @@ namespace Nz { builder.BeginDebugRegion("Light UBO Update", Color::Yellow); { - builder.PreTransferBarrier(); - for (auto& lightUboData : m_lightDataBuffers) { if (!lightUboData.allocation) From 25c446e10f4b44ff3f765c8f3781e61a0256e9f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 2 Feb 2022 13:47:39 +0100 Subject: [PATCH 13/14] GraphicsTest: Add light --- examples/GraphicsTest/main.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/examples/GraphicsTest/main.cpp b/examples/GraphicsTest/main.cpp index b65070537..c8412f107 100644 --- a/examples/GraphicsTest/main.cpp +++ b/examples/GraphicsTest/main.cpp @@ -104,6 +104,11 @@ int main() framePipeline.RegisterInstancedDrawable(modelInstance, &model, 0xFFFFFFFF); framePipeline.RegisterInstancedDrawable(modelInstance2, &model, 0xFFFFFFFF); + std::shared_ptr light = std::make_shared(); + light->UpdateColor(Nz::Color::Green); + + framePipeline.RegisterLight(light, 0xFFFFFFFF); + Nz::Vector3f viewerPos = Nz::Vector3f::Zero(); Nz::EulerAnglesf camAngles(0.f, 0.f, 0.f); @@ -202,6 +207,8 @@ int main() // Contrôle (Gauche ou droite) pour descendre dans l'espace global, etc... if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::LControl) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::RControl)) viewerPos += Nz::Vector3f::Down() * cameraSpeed; + + light->UpdatePosition(viewerPos); } Nz::RenderFrame frame = window.AcquireFrame(); From 5945a7145cda2397b6fb0f60864b3d39313a8e2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 2 Feb 2022 13:48:39 +0100 Subject: [PATCH 14/14] Fix MinGW compilation error --- include/Nazara/VulkanRenderer/VulkanBuffer.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/Nazara/VulkanRenderer/VulkanBuffer.hpp b/include/Nazara/VulkanRenderer/VulkanBuffer.hpp index 7314c6835..94d06b34d 100644 --- a/include/Nazara/VulkanRenderer/VulkanBuffer.hpp +++ b/include/Nazara/VulkanRenderer/VulkanBuffer.hpp @@ -21,7 +21,7 @@ namespace Nz class NAZARA_VULKANRENDERER_API VulkanBuffer : public RenderBuffer { public: - inline VulkanBuffer(VulkanDevice& device, BufferType type, UInt64 size, BufferUsageFlags usage, const void* initialData = nullptr); + VulkanBuffer(VulkanDevice& device, BufferType type, UInt64 size, BufferUsageFlags usage, const void* initialData = nullptr); VulkanBuffer(const VulkanBuffer&) = delete; VulkanBuffer(VulkanBuffer&&) = delete; ///TODO virtual ~VulkanBuffer();