// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) // This file is part of the "Nazara Engine - Graphics module" // For conditions of distribution and use, see copyright notice in Config.hpp #include #include #include #include #include #include #include #include namespace Nz { SpotLightShadowData::SpotLightShadowData(FramePipeline& pipeline, ElementRendererRegistry& elementRegistry, const SpotLight& light) : m_pipeline(pipeline), m_light(light) { UInt32 shadowMapSize = light.GetShadowMapSize(); m_viewer.UpdateRenderMask(0xFFFFFFFF); m_viewer.UpdateViewport(Recti(0, 0, SafeCast(shadowMapSize), SafeCast(shadowMapSize))); constexpr float zNear = 0.01f; ViewerInstance& viewerInstance = m_viewer.GetViewerInstance(); viewerInstance.UpdateProjectionMatrix(Matrix4f::Perspective(m_light.GetOuterAngle() * 2.f, 1.f, zNear, m_light.GetRadius())); viewerInstance.UpdateNearFarPlanes(zNear, m_light.GetRadius()); m_onLightShadowMapSettingChange.Connect(m_light.OnLightShadowMapSettingChange, [this](Light* /*light*/, PixelFormat /*newPixelFormat*/, UInt32 newSize) { m_viewer.UpdateViewport(Recti(0, 0, SafeCast(newSize), SafeCast(newSize))); }); m_onLightTransformInvalidated.Connect(m_light.OnLightTransformInvalided, [this]([[maybe_unused]] Light* light) { assert(&m_light == light); ViewerInstance& viewerInstance = m_viewer.GetViewerInstance(); viewerInstance.UpdateEyePosition(m_light.GetPosition()); viewerInstance.UpdateViewMatrix(Nz::Matrix4f::TransformInverse(m_light.GetPosition(), m_light.GetRotation())); m_pipeline.QueueTransfer(&viewerInstance); }); viewerInstance.UpdateEyePosition(m_light.GetPosition()); viewerInstance.UpdateViewMatrix(Nz::Matrix4f::TransformInverse(m_light.GetPosition(), m_light.GetRotation())); m_pipeline.QueueTransfer(&viewerInstance); std::size_t shadowPassIndex = Graphics::Instance()->GetMaterialPassRegistry().GetPassIndex("ShadowPass"); FramePipelinePass::PassData passData = { &m_viewer, elementRegistry, m_pipeline }; m_depthPass.emplace(passData, "Spotlight shadow mapping", shadowPassIndex); m_pipeline.ForEachRegisteredMaterialInstance([this](const MaterialInstance& matInstance) { m_depthPass->RegisterMaterialInstance(matInstance); }); } void SpotLightShadowData::PrepareRendering(RenderFrame& renderFrame, [[maybe_unused]] const AbstractViewer* viewer) { assert(viewer == nullptr); const Matrix4f& viewProjMatrix = m_viewer.GetViewerInstance().GetViewProjMatrix(); Frustumf frustum = Frustumf::Extract(viewProjMatrix); std::size_t visibilityHash = 5U; const auto& visibleRenderables = m_pipeline.FrustumCull(frustum, 0xFFFFFFFF, visibilityHash); FramePipelinePass::FrameData passData = { nullptr, frustum, renderFrame, visibleRenderables, visibilityHash }; m_depthPass->Prepare(passData); } void SpotLightShadowData::RegisterMaterialInstance(const MaterialInstance& matInstance) { m_depthPass->RegisterMaterialInstance(matInstance); } void SpotLightShadowData::RegisterPassInputs(FramePass& pass, [[maybe_unused]] const AbstractViewer* viewer) { assert(viewer == nullptr); pass.AddInput(m_attachmentIndex); } void SpotLightShadowData::RegisterToFrameGraph(FrameGraph& frameGraph, [[maybe_unused]] const AbstractViewer* viewer) { assert(viewer == nullptr); UInt32 shadowMapSize = m_light.GetShadowMapSize(); m_attachmentIndex = frameGraph.AddAttachment({ .name = "Shadowmap", .format = m_light.GetShadowMapFormat(), .size = FramePassAttachmentSize::Fixed, .width = shadowMapSize, .height = shadowMapSize, }); FramePipelinePass::PassInputOuputs passInputOuputs; passInputOuputs.depthStencilOutput = m_attachmentIndex; m_depthPass->RegisterToFrameGraph(frameGraph, passInputOuputs); } const Texture* SpotLightShadowData::RetrieveLightShadowmap(const BakedFrameGraph& bakedGraph, const AbstractViewer* /*viewer*/) const { return bakedGraph.GetAttachmentTexture(m_attachmentIndex).get(); } void SpotLightShadowData::UnregisterMaterialInstance(const MaterialInstance& matInstance) { m_depthPass->UnregisterMaterialInstance(matInstance); } }