diff --git a/SDK/src/NDK/Lua/LuaBinding_Graphics.cpp b/SDK/src/NDK/Lua/LuaBinding_Graphics.cpp index f87ac6556..b626f9665 100644 --- a/SDK/src/NDK/Lua/LuaBinding_Graphics.cpp +++ b/SDK/src/NDK/Lua/LuaBinding_Graphics.cpp @@ -92,6 +92,7 @@ namespace Ndk material.BindMethod("EnableDepthSorting", &Nz::Material::EnableDepthSorting); material.BindMethod("EnableDepthWrite", &Nz::Material::EnableDepthWrite); material.BindMethod("EnableFaceCulling", &Nz::Material::EnableFaceCulling); + material.BindMethod("EnableReflectionMapping", &Nz::Material::EnableReflectionMapping); material.BindMethod("EnableScissorTest", &Nz::Material::EnableScissorTest); material.BindMethod("EnableShadowCasting", &Nz::Material::EnableShadowCasting); material.BindMethod("EnableShadowReceive", &Nz::Material::EnableShadowReceive); @@ -139,6 +140,7 @@ namespace Ndk material.BindMethod("IsDepthSortingEnabled", &Nz::Material::IsDepthSortingEnabled); material.BindMethod("IsDepthWriteEnabled", &Nz::Material::IsDepthWriteEnabled); material.BindMethod("IsFaceCullingEnabled", &Nz::Material::IsFaceCullingEnabled); + material.BindMethod("IsReflectionMappingEnabled", &Nz::Material::IsReflectionMappingEnabled); material.BindMethod("IsScissorTestEnabled", &Nz::Material::IsScissorTestEnabled); material.BindMethod("IsStencilTestEnabled", &Nz::Material::IsStencilTestEnabled); material.BindMethod("IsShadowCastingEnabled", &Nz::Material::IsShadowCastingEnabled); diff --git a/SDK/src/NDK/Systems/RenderSystem.cpp b/SDK/src/NDK/Systems/RenderSystem.cpp index bdbb6cb5b..c5f385bde 100644 --- a/SDK/src/NDK/Systems/RenderSystem.cpp +++ b/SDK/src/NDK/Systems/RenderSystem.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -181,7 +182,7 @@ namespace Ndk GraphicsComponent& graphicsComponent = drawable->GetComponent(); graphicsComponent.EnsureBoundingVolumeUpdate(); } - + bool forceInvalidation = false; std::size_t visibilityHash = m_drawableCulling.Cull(camComponent.GetFrustum(), &forceInvalidation); @@ -220,8 +221,12 @@ namespace Ndk Nz::SceneData sceneData; sceneData.ambientColor = Nz::Color(25, 25, 25); sceneData.background = m_background; + sceneData.globalReflectionTexture = nullptr; sceneData.viewer = &camComponent; + if (m_background && m_background->GetBackgroundType() == Nz::BackgroundType_Skybox) + sceneData.globalReflectionTexture = static_cast(m_background.Get())->GetTexture(); + m_renderTechnique->Clear(sceneData); m_renderTechnique->Draw(sceneData); } diff --git a/include/Nazara/Graphics/ForwardRenderTechnique.hpp b/include/Nazara/Graphics/ForwardRenderTechnique.hpp index 0a35518fc..2ff4dd76e 100644 --- a/include/Nazara/Graphics/ForwardRenderTechnique.hpp +++ b/include/Nazara/Graphics/ForwardRenderTechnique.hpp @@ -76,6 +76,7 @@ namespace Nz // Other uniforms int eyePosition; + int reflectionMap; int sceneAmbient; int textureOverlay; }; @@ -90,6 +91,8 @@ namespace Nz unsigned int m_maxLightPassPerObject; static IndexBuffer s_quadIndexBuffer; + static Texture s_dummyReflection; + static TextureSampler s_reflectionSampler; static TextureSampler s_shadowSampler; static VertexBuffer s_quadVertexBuffer; static VertexDeclaration s_billboardInstanceDeclaration; diff --git a/include/Nazara/Graphics/Material.hpp b/include/Nazara/Graphics/Material.hpp index be6e2c58b..b45d92aa2 100644 --- a/include/Nazara/Graphics/Material.hpp +++ b/include/Nazara/Graphics/Material.hpp @@ -79,6 +79,7 @@ namespace Nz inline void EnableDepthSorting(bool depthSorting); inline void EnableDepthWrite(bool depthWrite); inline void EnableFaceCulling(bool faceCulling); + inline void EnableReflectionMapping(bool reflection); inline void EnableScissorTest(bool scissorTest); inline void EnableShadowCasting(bool castShadows); inline void EnableShadowReceive(bool receiveShadows); @@ -128,6 +129,7 @@ namespace Nz inline bool IsDepthSortingEnabled() const; inline bool IsDepthWriteEnabled() const; inline bool IsFaceCullingEnabled() const; + inline bool IsReflectionMappingEnabled() const; inline bool IsScissorTestEnabled() const; inline bool IsStencilTestEnabled() const; inline bool IsShadowCastingEnabled() const; diff --git a/include/Nazara/Graphics/Material.inl b/include/Nazara/Graphics/Material.inl index b0ce4ff1c..fd8a06903 100644 --- a/include/Nazara/Graphics/Material.inl +++ b/include/Nazara/Graphics/Material.inl @@ -146,7 +146,7 @@ namespace Nz /*! * \brief Enable/Disable alpha test for this material * - * When enabled, all objects using this material will be rendered using alpha testing, + * When enabled, all objects using this material will be rendered using alpha testing, * rejecting pixels if their alpha component is under a defined threshold. * This allows some kind of transparency with a much cheaper cost as it doesn't prevent any optimization (as deferred rendering or batching). * @@ -252,7 +252,7 @@ namespace Nz * When enabled, and if depth buffer is enabled and present, all fragments generated with this material will write * to the depth buffer if they pass depth test. * - * This is usually disabled with translucent objects, as depth test is wanted to prevent them from rendering on top of opaque objects but + * This is usually disabled with translucent objects, as depth test is wanted to prevent them from rendering on top of opaque objects but * not depth writing (which could make other translucent fragments to fail depth test) * * \param depthBuffer Defines if this material will use depth write @@ -291,6 +291,31 @@ namespace Nz InvalidatePipeline(); } + /*! + * \brief Enable/Disable reflection mapping for this material + * + * When enabled, the material will render reflections from the object environment according to the reflection mode. + * Whether or not this is expensive depends of the reflection mode and size. + * + * Please note this is only a hint for the render technique, and reflections can be forcefully enabled or disabled depending on the material shader. + * + * Use SetReflectionMode and SetReflectionSize to control reflection quality. + * + * \param reflection Defines if this material should use reflection mapping + * + * \remark May invalidates the pipeline + * + * \see IsReflectionMappingEnabled + * \see SetReflectionMode + * \see SetReflectionSize + */ + inline void Material::EnableReflectionMapping(bool reflection) + { + m_pipelineInfo.reflectionMapping = reflection; + + InvalidatePipeline(); + } + /*! * \brief Enable/Disable scissor test for this material * @@ -782,6 +807,17 @@ namespace Nz return m_pipelineInfo.faceCulling; } + /*! + * \brief Checks whether this material has reflection mapping enabled + * \return true If it is the case + * + * \see EnableReflectionMapping + */ + inline bool Material::IsReflectionMappingEnabled() const + { + return m_pipelineInfo.reflectionMapping; + } + /*! * \brief Checks whether this material has scissor test enabled * \return true If it is the case diff --git a/include/Nazara/Graphics/MaterialPipeline.hpp b/include/Nazara/Graphics/MaterialPipeline.hpp index cf64d5e40..a0bb06e21 100644 --- a/include/Nazara/Graphics/MaterialPipeline.hpp +++ b/include/Nazara/Graphics/MaterialPipeline.hpp @@ -20,15 +20,16 @@ namespace Nz { struct MaterialPipelineInfo : RenderStates { - bool alphaTest = false; - bool depthSorting = false; - bool hasAlphaMap = false; - bool hasDiffuseMap = false; - bool hasEmissiveMap = false; - bool hasHeightMap = false; - bool hasNormalMap = false; - bool hasSpecularMap = false; - bool shadowReceive = true; + bool alphaTest = false; + bool depthSorting = false; + bool hasAlphaMap = false; + bool hasDiffuseMap = false; + bool hasEmissiveMap = false; + bool hasHeightMap = false; + bool hasNormalMap = false; + bool hasSpecularMap = false; + bool reflectionMapping = false; + bool shadowReceive = true; UberShaderConstRef uberShader; }; diff --git a/include/Nazara/Graphics/MaterialPipeline.inl b/include/Nazara/Graphics/MaterialPipeline.inl index 0cbea4e61..88e01c02b 100644 --- a/include/Nazara/Graphics/MaterialPipeline.inl +++ b/include/Nazara/Graphics/MaterialPipeline.inl @@ -72,6 +72,7 @@ namespace Nz NazaraPipelineBoolMember(hasHeightMap); NazaraPipelineBoolMember(hasNormalMap); NazaraPipelineBoolMember(hasSpecularMap); + NazaraPipelineBoolMember(reflectionMapping); NazaraPipelineBoolMember(shadowReceive); NazaraPipelineMember(uberShader); @@ -127,6 +128,7 @@ namespace std NazaraPipelineBoolMember(hasHeightMap); NazaraPipelineBoolMember(hasNormalMap); NazaraPipelineBoolMember(hasSpecularMap); + NazaraPipelineBoolMember(reflectionMapping); NazaraPipelineBoolMember(shadowReceive); NazaraPipelineMember(uberShader); diff --git a/include/Nazara/Graphics/SceneData.hpp b/include/Nazara/Graphics/SceneData.hpp index 94aafbda4..882243e00 100644 --- a/include/Nazara/Graphics/SceneData.hpp +++ b/include/Nazara/Graphics/SceneData.hpp @@ -13,12 +13,14 @@ namespace Nz { class AbstractBackground; class AbstractViewer; + class Texture; struct SceneData { Color ambientColor; const AbstractBackground* background; const AbstractViewer* viewer; + Texture* globalReflectionTexture; }; } diff --git a/src/Nazara/Graphics/ForwardRenderTechnique.cpp b/src/Nazara/Graphics/ForwardRenderTechnique.cpp index 2e8f3e12f..24d200754 100644 --- a/src/Nazara/Graphics/ForwardRenderTechnique.cpp +++ b/src/Nazara/Graphics/ForwardRenderTechnique.cpp @@ -214,8 +214,15 @@ namespace Nz s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData1, ComponentType_Float4, NazaraOffsetOf(ForwardRenderQueue::BillboardData, size)); // Englobe sincos s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData2, ComponentType_Color, NazaraOffsetOf(ForwardRenderQueue::BillboardData, color)); + s_reflectionSampler.SetFilterMode(SamplerFilter_Bilinear); + s_reflectionSampler.SetWrapMode(SamplerWrap_Clamp); + s_shadowSampler.SetFilterMode(SamplerFilter_Bilinear); s_shadowSampler.SetWrapMode(SamplerWrap_Clamp); + + std::array whitePixels = { { 255, 255, 255, 255, 255, 255 } }; + s_dummyReflection.Create(ImageType_Cubemap, PixelFormatType_L8, 1, 1); + s_dummyReflection.Update(whitePixels.data()); } catch (const std::exception& e) { @@ -232,6 +239,7 @@ namespace Nz void ForwardRenderTechnique::Uninitialize() { + s_dummyReflection.Destroy(); s_quadIndexBuffer.Reset(); s_quadVertexBuffer.Reset(); } @@ -583,6 +591,10 @@ namespace Nz const Shader* lastShader = nullptr; const ShaderUniforms* shaderUniforms = nullptr; + Texture* reflectionMap = sceneData.globalReflectionTexture; + if (!reflectionMap) + reflectionMap = &s_dummyReflection; + for (auto& pipelinePair : layer.opaqueModels) { const MaterialPipeline* pipeline = pipelinePair.first; @@ -618,6 +630,15 @@ namespace Nz { material->Apply(pipelineInstance); + if (shaderUniforms->reflectionMap != -1) + { + unsigned int textureUnit = Material::GetTextureUnit(TextureMap_ReflectionCube); + + shader->SendInteger(shaderUniforms->reflectionMap, textureUnit); + Renderer::SetTexture(textureUnit, reflectionMap); + Renderer::SetTextureSampler(textureUnit, s_reflectionSampler); + } + ForwardRenderQueue::MeshInstanceContainer& meshInstances = matEntry.meshMap; // Meshes @@ -895,6 +916,7 @@ namespace Nz uniforms.shaderUniformInvalidatedSlot.Connect(shader->OnShaderUniformInvalidated, this, &ForwardRenderTechnique::OnShaderInvalidated); uniforms.eyePosition = shader->GetUniformLocation("EyePosition"); + uniforms.reflectionMap = shader->GetUniformLocation("ReflectionMap"); uniforms.sceneAmbient = shader->GetUniformLocation("SceneAmbient"); uniforms.textureOverlay = shader->GetUniformLocation("TextureOverlay"); @@ -1037,6 +1059,8 @@ namespace Nz } IndexBuffer ForwardRenderTechnique::s_quadIndexBuffer; + Texture ForwardRenderTechnique::s_dummyReflection; + TextureSampler ForwardRenderTechnique::s_reflectionSampler; TextureSampler ForwardRenderTechnique::s_shadowSampler; VertexBuffer ForwardRenderTechnique::s_quadVertexBuffer; VertexDeclaration ForwardRenderTechnique::s_billboardInstanceDeclaration; diff --git a/src/Nazara/Graphics/MaterialPipeline.cpp b/src/Nazara/Graphics/MaterialPipeline.cpp index e9f947c90..4c7c42d8e 100644 --- a/src/Nazara/Graphics/MaterialPipeline.cpp +++ b/src/Nazara/Graphics/MaterialPipeline.cpp @@ -77,19 +77,20 @@ namespace Nz NazaraAssert(m_pipelineInfo.uberShader, "Material pipeline has no uber shader"); ParameterList list; - list.SetParameter("ALPHA_MAPPING", m_pipelineInfo.hasAlphaMap); - list.SetParameter("ALPHA_TEST", m_pipelineInfo.alphaTest); - list.SetParameter("COMPUTE_TBNMATRIX", m_pipelineInfo.hasNormalMap || m_pipelineInfo.hasHeightMap); - list.SetParameter("DIFFUSE_MAPPING", m_pipelineInfo.hasDiffuseMap); - list.SetParameter("EMISSIVE_MAPPING", m_pipelineInfo.hasEmissiveMap); - list.SetParameter("NORMAL_MAPPING", m_pipelineInfo.hasNormalMap); - list.SetParameter("PARALLAX_MAPPING", m_pipelineInfo.hasHeightMap); - list.SetParameter("SHADOW_MAPPING", m_pipelineInfo.shadowReceive); - list.SetParameter("SPECULAR_MAPPING", m_pipelineInfo.hasSpecularMap); - list.SetParameter("TEXTURE_MAPPING", m_pipelineInfo.hasAlphaMap || m_pipelineInfo.hasDiffuseMap || m_pipelineInfo.hasEmissiveMap || - m_pipelineInfo.hasNormalMap || m_pipelineInfo.hasHeightMap || m_pipelineInfo.hasSpecularMap || - flags & ShaderFlags_TextureOverlay); - list.SetParameter("TRANSFORM", true); + list.SetParameter("ALPHA_MAPPING", m_pipelineInfo.hasAlphaMap); + list.SetParameter("ALPHA_TEST", m_pipelineInfo.alphaTest); + list.SetParameter("COMPUTE_TBNMATRIX", m_pipelineInfo.hasNormalMap || m_pipelineInfo.hasHeightMap); + list.SetParameter("DIFFUSE_MAPPING", m_pipelineInfo.hasDiffuseMap); + list.SetParameter("EMISSIVE_MAPPING", m_pipelineInfo.hasEmissiveMap); + list.SetParameter("NORMAL_MAPPING", m_pipelineInfo.hasNormalMap); + list.SetParameter("PARALLAX_MAPPING", m_pipelineInfo.hasHeightMap); + list.SetParameter("REFLECTION_MAPPING", m_pipelineInfo.reflectionMapping); + list.SetParameter("SHADOW_MAPPING", m_pipelineInfo.shadowReceive); + list.SetParameter("SPECULAR_MAPPING", m_pipelineInfo.hasSpecularMap); + list.SetParameter("TEXTURE_MAPPING", m_pipelineInfo.hasAlphaMap || m_pipelineInfo.hasDiffuseMap || m_pipelineInfo.hasEmissiveMap || + m_pipelineInfo.hasNormalMap || m_pipelineInfo.hasHeightMap || m_pipelineInfo.hasSpecularMap || + m_pipelineInfo.reflectionMapping || flags & ShaderFlags_TextureOverlay); + list.SetParameter("TRANSFORM", true); list.SetParameter("FLAG_BILLBOARD", static_cast((flags & ShaderFlags_Billboard) != 0)); list.SetParameter("FLAG_DEFERRED", static_cast((flags & ShaderFlags_Deferred) != 0)); @@ -175,7 +176,7 @@ namespace Nz OverrideShader("Shaders/PhongLighting/core.vert", &vertexShader); #endif - uberShader->SetShader(ShaderStageType_Fragment, fragmentShader, "FLAG_DEFERRED FLAG_TEXTUREOVERLAY ALPHA_MAPPING ALPHA_TEST AUTO_TEXCOORDS DIFFUSE_MAPPING EMISSIVE_MAPPING NORMAL_MAPPING PARALLAX_MAPPING SHADOW_MAPPING SPECULAR_MAPPING"); + uberShader->SetShader(ShaderStageType_Fragment, fragmentShader, "FLAG_DEFERRED FLAG_TEXTUREOVERLAY ALPHA_MAPPING ALPHA_TEST AUTO_TEXCOORDS DIFFUSE_MAPPING EMISSIVE_MAPPING NORMAL_MAPPING PARALLAX_MAPPING REFLECTION_MAPPING SHADOW_MAPPING SPECULAR_MAPPING"); uberShader->SetShader(ShaderStageType_Vertex, vertexShader, "FLAG_BILLBOARD FLAG_DEFERRED FLAG_INSTANCING FLAG_VERTEXCOLOR COMPUTE_TBNMATRIX PARALLAX_MAPPING SHADOW_MAPPING TEXTURE_MAPPING TRANSFORM UNIFORM_VERTEX_DEPTH"); UberShaderLibrary::Register("PhongLighting", uberShader);