diff --git a/examples/PhysicsDemo/main.cpp b/examples/PhysicsDemo/main.cpp index ef823402c..ef0045145 100644 --- a/examples/PhysicsDemo/main.cpp +++ b/examples/PhysicsDemo/main.cpp @@ -75,6 +75,7 @@ int main() std::shared_ptr material = std::make_shared(Nz::BasicMaterial::GetSettings()); material->EnableDepthBuffer(true); + material->EnableDepthClamp(true); material->EnableFaceCulling(true); Nz::TextureSamplerInfo samplerInfo; diff --git a/include/Nazara/Graphics/Material.hpp b/include/Nazara/Graphics/Material.hpp index 25ed79ba2..a6aa8572b 100644 --- a/include/Nazara/Graphics/Material.hpp +++ b/include/Nazara/Graphics/Material.hpp @@ -42,6 +42,7 @@ namespace Nz inline void EnableBlending(bool blending); inline void EnableColorWrite(bool colorWrite); inline void EnableDepthBuffer(bool depthBuffer); + inline void EnableDepthClamp(bool depthClamp); inline void EnableDepthSorting(bool depthSorting); inline void EnableDepthWrite(bool depthWrite); inline void EnableFaceCulling(bool faceCulling); @@ -84,6 +85,7 @@ namespace Nz inline bool IsBlendingEnabled() const; inline bool IsColorWriteEnabled() const; inline bool IsDepthBufferEnabled() const; + inline bool IsDepthClampEnabled() const; inline bool IsDepthSortingEnabled() const; inline bool IsDepthWriteEnabled() const; inline bool IsFaceCullingEnabled() const; diff --git a/include/Nazara/Graphics/Material.inl b/include/Nazara/Graphics/Material.inl index 3aba0acb4..c3a228edc 100644 --- a/include/Nazara/Graphics/Material.inl +++ b/include/Nazara/Graphics/Material.inl @@ -115,6 +115,28 @@ namespace Nz InvalidatePipeline(); } + /*! + * \brief Enable/Disable depth clamp for this material + * + * When enabled, all fragments generated by this material will be clamped to znear or zfar + * instead of being clipped out when outside this range. + * + * This can be useful to prevent clipping near or far primitives. + * + * \param depthClamp Defines if this material will use depth clamping + * + * \remark Invalidates the pipeline + * \remark Depth clamping requires RenderDeviceFeatures::depthClamping to be true + * + * \see IsDepthClampEnabled + */ + inline void Material::EnableDepthClamp(bool depthClamp) + { + m_pipelineInfo.depthClamp = depthClamp; + + InvalidatePipeline(); + } + /*! * \brief Enable/Disable depth sorting for this material * @@ -524,6 +546,15 @@ namespace Nz return m_pipelineInfo.depthBuffer; } + /*! + * \brief Checks whether this material has depth clamping enabled + * \return true If it is the case + */ + inline bool Material::IsDepthClampEnabled() const + { + return false; + } + /*! * \brief Checks whether this material has depth sorting enabled * \return true If it is the case diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp b/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp index 2dad92f74..303aab549 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp +++ b/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp @@ -48,6 +48,7 @@ namespace Nz::GL enum class Extension { + DepthClamp, SpirV, TextureCompressionS3tc, TextureFilterAnisotropic, diff --git a/include/Nazara/Renderer/RenderDeviceInfo.hpp b/include/Nazara/Renderer/RenderDeviceInfo.hpp index 5beb28c66..c20016ec9 100644 --- a/include/Nazara/Renderer/RenderDeviceInfo.hpp +++ b/include/Nazara/Renderer/RenderDeviceInfo.hpp @@ -16,6 +16,7 @@ namespace Nz struct RenderDeviceFeatures { bool anisotropicFiltering = false; + bool depthClamping = false; bool nonSolidFaceFilling = false; }; diff --git a/include/Nazara/Renderer/RenderPipeline.hpp b/include/Nazara/Renderer/RenderPipeline.hpp index a6485cd85..500e8ec8a 100644 --- a/include/Nazara/Renderer/RenderPipeline.hpp +++ b/include/Nazara/Renderer/RenderPipeline.hpp @@ -7,9 +7,9 @@ #ifndef NAZARA_RENDERPIPELINE_HPP #define NAZARA_RENDERPIPELINE_HPP -#include #include #include +#include namespace Nz { @@ -26,6 +26,8 @@ namespace Nz std::vector vertexBuffers; }; + class RenderDevice; + class NAZARA_RENDERER_API RenderPipeline { public: @@ -33,6 +35,9 @@ namespace Nz virtual ~RenderPipeline(); virtual const RenderPipelineInfo& GetPipelineInfo() const = 0; + + protected: + static void ValidatePipelineInfo(const RenderDevice& device, RenderPipelineInfo& pipelineInfo); }; } diff --git a/include/Nazara/Renderer/RenderStates.hpp b/include/Nazara/Renderer/RenderStates.hpp index a162ac042..05b371fcf 100644 --- a/include/Nazara/Renderer/RenderStates.hpp +++ b/include/Nazara/Renderer/RenderStates.hpp @@ -49,6 +49,7 @@ namespace Nz bool blending = false; bool colorWrite = true; bool depthBuffer = false; + bool depthClamp = false; bool depthWrite = true; bool faceCulling = false; bool scissorTest = false; diff --git a/include/Nazara/Renderer/RenderStates.inl b/include/Nazara/Renderer/RenderStates.inl index 0e2ed11bd..78d5688ba 100644 --- a/include/Nazara/Renderer/RenderStates.inl +++ b/include/Nazara/Renderer/RenderStates.inl @@ -19,6 +19,7 @@ namespace Nz NazaraRenderStateBoolMember(blending); NazaraRenderStateBoolMember(colorWrite); NazaraRenderStateBoolMember(depthBuffer); + NazaraRenderStateBoolMember(depthClamp); NazaraRenderStateBoolMember(faceCulling); NazaraRenderStateBoolMember(scissorTest); NazaraRenderStateBoolMember(stencilTest); @@ -95,6 +96,7 @@ namespace std NazaraRenderStateBool(blending); NazaraRenderStateBool(colorWrite); NazaraRenderStateBool(depthBuffer); + NazaraRenderStateBool(depthClamp); NazaraRenderStateBool(faceCulling); NazaraRenderStateBool(scissorTest); NazaraRenderStateBool(stencilTest); diff --git a/src/Nazara/Graphics/Graphics.cpp b/src/Nazara/Graphics/Graphics.cpp index df031c8c5..c13db9a36 100644 --- a/src/Nazara/Graphics/Graphics.cpp +++ b/src/Nazara/Graphics/Graphics.cpp @@ -53,6 +53,7 @@ namespace Nz RenderDeviceFeatures enabledFeatures; enabledFeatures.anisotropicFiltering = renderDeviceInfo[bestRenderDeviceIndex].features.anisotropicFiltering; + enabledFeatures.depthClamping = renderDeviceInfo[bestRenderDeviceIndex].features.depthClamping; enabledFeatures.nonSolidFaceFilling = renderDeviceInfo[bestRenderDeviceIndex].features.nonSolidFaceFilling; m_renderDevice = renderer->InstanciateRenderDevice(bestRenderDeviceIndex, enabledFeatures); diff --git a/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp b/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp index 67680135c..3bdc5c754 100644 --- a/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp +++ b/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp @@ -281,6 +281,16 @@ namespace Nz::GL m_extensionStatus.fill(ExtensionStatus::NotSupported); + // Depth clamp + if (m_params.type == ContextType::OpenGL && m_params.glMajorVersion >= 3 && m_params.glMajorVersion >= 2) + m_extensionStatus[UnderlyingCast(Extension::DepthClamp)] = ExtensionStatus::Core; + else if (m_supportedExtensions.count("GL_ARB_depth_clamp")) + m_extensionStatus[UnderlyingCast(Extension::DepthClamp)] = ExtensionStatus::ARB; + else if (m_supportedExtensions.count("GL_EXT_depth_clamp")) + m_extensionStatus[UnderlyingCast(Extension::DepthClamp)] = ExtensionStatus::EXT; + else if (m_supportedExtensions.count("GL_NV_depth_clamp")) + m_extensionStatus[UnderlyingCast(Extension::DepthClamp)] = ExtensionStatus::Vendor; + // SpirV if (m_params.type == ContextType::OpenGL && m_params.glMajorVersion >= 4 && m_params.glMajorVersion >= 6) m_extensionStatus[UnderlyingCast(Extension::SpirV)] = ExtensionStatus::Core; @@ -599,6 +609,17 @@ namespace Nz::GL m_state.renderStates.depthBuffer = renderStates.depthBuffer; } + // Depth clamp + if (m_state.renderStates.depthClamp != renderStates.depthClamp) + { + if (renderStates.depthClamp) + glEnable(GL_DEPTH_CLAMP_EXT); + else + glDisable(GL_DEPTH_CLAMP_EXT); + + m_state.renderStates.depthClamp = renderStates.depthClamp; + } + // Face culling if (m_state.renderStates.faceCulling != renderStates.faceCulling) { diff --git a/src/Nazara/VulkanRenderer/Vulkan.cpp b/src/Nazara/VulkanRenderer/Vulkan.cpp index 024c530ce..231d189b0 100644 --- a/src/Nazara/VulkanRenderer/Vulkan.cpp +++ b/src/Nazara/VulkanRenderer/Vulkan.cpp @@ -54,6 +54,7 @@ namespace Nz deviceInfo.name = physDevice.properties.deviceName; deviceInfo.features.anisotropicFiltering = physDevice.features.samplerAnisotropy; + deviceInfo.features.depthClamping = physDevice.features.depthClamp; deviceInfo.features.nonSolidFaceFilling = physDevice.features.fillModeNonSolid; deviceInfo.limits.minUniformBufferOffsetAlignment = physDevice.properties.limits.minUniformBufferOffsetAlignment; @@ -578,6 +579,9 @@ namespace Nz if (enabledFeatures.anisotropicFiltering) deviceFeatures.samplerAnisotropy = VK_TRUE; + if (enabledFeatures.depthClamping) + deviceFeatures.depthClamp = VK_TRUE; + if (enabledFeatures.nonSolidFaceFilling) deviceFeatures.fillModeNonSolid = VK_TRUE; diff --git a/src/Nazara/VulkanRenderer/VulkanRenderPipeline.cpp b/src/Nazara/VulkanRenderer/VulkanRenderPipeline.cpp index 39ee2c154..95b2e8a48 100644 --- a/src/Nazara/VulkanRenderer/VulkanRenderPipeline.cpp +++ b/src/Nazara/VulkanRenderer/VulkanRenderPipeline.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -142,10 +143,11 @@ namespace Nz { VkPipelineRasterizationStateCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - createInfo.polygonMode = ToVulkan(pipelineInfo.faceFilling); createInfo.cullMode = (pipelineInfo.faceCulling) ? ToVulkan(pipelineInfo.cullingSide) : VK_CULL_MODE_NONE; + createInfo.depthClampEnable = pipelineInfo.depthClamp; createInfo.frontFace = ToVulkan(pipelineInfo.frontFace); createInfo.lineWidth = pipelineInfo.lineWidth; + createInfo.polygonMode = ToVulkan(pipelineInfo.faceFilling); return createInfo; }