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] 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;