/
redgpu
/
ezEngine
Обзор
Документация
Войти
/
redgpu
/
ezEngine
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
dev
Code/Engine/RendererCore/Pipeline/Implementation/Passes/ScreenSpaceShadowPass.cpp
194 строки
8 KB
Sanakan8472
Render Graph (#1948)
03 июн 2026, 10:19
Не верифицирован
03 июн 2026, 10:19
60bb12c
Код
Авторство
О чём код?
#include <RendererCore/RendererCorePCH.h> #include <Foundation/IO/TypeVersionContext.h> #include <RendererCore/Lights/DirectionalLightComponent.h> #include <RendererCore/Pipeline/Passes/ScreenSpaceShadowPass.h> #include <RendererCore/Pipeline/View.h> #include <RendererCore/RenderContext/RenderContext.h> #include <RendererFoundation/Profiling/Profiling.h> #include <RendererFoundation/Resources/Texture.h> #include <Shaders/Pipeline/ScreenSpaceShadowConstants.h> EZ_WARNING_PUSH() EZ_WARNING_DISABLE_MSVC(4244) #include <Shaders/Pipeline/bend_sss/bend_sss_cpu.h> EZ_WARNING_POP() // clang-format off EZ_BEGIN_DYNAMIC_REFLECTED_TYPE(ezScreenSpaceShadowPass, 1, ezRTTIDefaultAllocator<ezScreenSpaceShadowPass>) { EZ_BEGIN_PROPERTIES { EZ_MEMBER_PROPERTY("DepthInput", m_PinDepthInput), EZ_MEMBER_PROPERTY("Output", m_PinOutput), EZ_MEMBER_PROPERTY("SurfaceThickness", m_fSurfaceThickness)->AddAttributes(new ezDefaultValueAttribute(0.005f), new ezClampValueAttribute(0.001f, 0.5f)), EZ_MEMBER_PROPERTY("ShadowContrast", m_fShadowContrast)->AddAttributes(new ezDefaultValueAttribute(4.0f), new ezClampValueAttribute(1.0f, 10.0f)), } EZ_END_PROPERTIES; EZ_BEGIN_ATTRIBUTES { new ezCategoryAttribute("Effects") } EZ_END_ATTRIBUTES; } EZ_END_DYNAMIC_REFLECTED_TYPE; // clang-format on ezScreenSpaceShadowPass::ezScreenSpaceShadowPass() : ezRenderPipelinePass("ScreenSpaceShadowPass", true) { m_hShader = ezResourceManager::LoadResource<ezShaderResource>("Shaders/Pipeline/ScreenSpaceShadow.ezShader"); m_hConstantBuffer = ezRenderContext::CreateConstantBufferStorage<ezScreenSpaceShadowConstants>(); } ezScreenSpaceShadowPass::~ezScreenSpaceShadowPass() { ezGALDevice::GetDefaultDevice()->DestroySamplerState(m_hDepthSamplerState); ezRenderContext::DeleteConstantBufferStorage(m_hConstantBuffer); } ezStatus ezScreenSpaceShadowPass::AddRenderPasses(const ezViewData& viewData, const ezCamera& camera, ezRenderGraph& ref_graph, const ezArrayPtr<const ezRenderPipelinePinConnection> inputs, ezArrayPtr<ezRenderPipelinePinConnection> outputs) { ezRenderGraphTextureHandle hDepthInput = inputs[m_PinDepthInput.m_uiInputIndex].m_TextureHandle; if (hDepthInput.IsInvalidated()) return ezStatus(ezFmt("DepthInput: Not connected")); const ezGALTextureCreationDescription depthDesc = ref_graph.GetTextureDesc(hDepthInput); if (depthDesc.m_SampleCount != ezGALMSAASampleCount::None) return ezStatus(ezFmt("DepthInput: Must be resolved")); // Create output texture ezGALTextureCreationDescription outputDesc = depthDesc; outputDesc.m_Format = ezGALResourceFormat::RUByteNormalized; outputDesc.m_TextureFlags = ezGALTextureUsageFlags::ShaderResource | ezGALTextureUsageFlags::UnorderedAccess; ezRenderGraphTextureHandle hOutput = ref_graph.CreateTexture(outputDesc); outputs[m_PinOutput.m_uiOutputIndex].m_TextureHandle = hOutput; const ezGALTextureCreationDescription& depthTexDesc = ref_graph.GetTextureDesc(hDepthInput); const ezUInt32 uiWidth = depthTexDesc.m_uiWidth; const ezUInt32 uiHeight = depthTexDesc.m_uiHeight; CreateSamplerState(); bool bRendered = false; auto batchList = GetPipeline()->GetRenderDataBatchesWithCategory(ezDefaultRenderDataCategories::Light); const ezUInt32 uiBatchCount = batchList.GetBatchCount(); for (ezUInt32 i = 0; i < uiBatchCount; ++i) { const ezRenderDataBatch& batch = batchList.GetBatch(i); for (auto it = batch.GetIterator<ezRenderData>(); it.IsValid(); ++it) { const auto pDirLight = ezDynamicCast<const ezDirectionalLightRenderData*>(it); if (pDirLight == nullptr) { // Directional lights come first in the list, so we can stop as soon as we encounter a non-directional light. return EZ_SUCCESS; } if (!pDirLight->m_bScreenSpaceShadows) continue; if (bRendered) { ezLog::Warning("Multiple directional lights with screen space shadows are not yet supported. Only the first one will be rendered."); return EZ_SUCCESS; } ezVec3 lightDir = pDirLight->m_vDirection; lightDir.Normalize(); const ezUInt32 uiEyeCount = camera.IsStereoscopic() ? 2 : 1; for (ezUInt32 uiEyeIndex = 0; uiEyeIndex < uiEyeCount; ++uiEyeIndex) { // Ray march pass: writes raw shadow to output texture auto pass = ref_graph.AddComputePass("ScreenSpaceShadow"); pass.ReadTexture(hDepthInput, {}, ezGALResourceState::ShaderResource); pass.WriteTexture(hOutput, {}, ezGALResourceState::UnorderedAccess); pass.SetStereoscopic(camera.IsStereoscopic()); pass.SetExecuteCallback([this, uiWidth, uiHeight, hDepthInput, hOutput, uiEyeIndex, lightDir](const ezRenderGraphContext& ctx) { const ezRenderViewContext& renderViewContext = *ctx.GetUserData<ezRenderViewContext>(); ezVec2I32 viewportSize = ezVec2I32::Make(uiWidth, uiHeight); ezVec2I32 minRenderBounds = ezVec2I32::Make(0, 0); ezVec2I32 maxRenderBounds = viewportSize; ezVec4 projectedLightDir = renderViewContext.m_pViewData->m_ViewProjectionMatrix[uiEyeIndex] * ezVec4(lightDir, 0.0f); Bend::DispatchList dispatchList = Bend::BuildDispatchList(projectedLightDir.GetData(), viewportSize.GetData(), minRenderBounds.GetData(), maxRenderBounds.GetData(), false, WAVE_SIZE); ezBindGroupBuilder& bindGroup = renderViewContext.m_pRenderContext->GetBindGroup(); bindGroup.BindBuffer("ezScreenSpaceShadowConstants", m_hConstantBuffer); bindGroup.BindTexture("DepthTexture", ctx.ResolveTexture(hDepthInput)); bindGroup.BindSampler("DepthTextureSampler", m_hDepthSamplerState); bindGroup.BindTexture("OutputTexture", ctx.ResolveTexture(hOutput)); renderViewContext.m_pRenderContext->BindShader(m_hShader); for (int j = 0; j < dispatchList.DispatchCount; ++j) { auto& dispatch = dispatchList.Dispatch[j]; // Fill constant buffer { auto cb = ezRenderContext::GetConstantBufferData<ezScreenSpaceShadowConstants>(m_hConstantBuffer); cb->LightCoordinate = ezVec4(dispatchList.LightCoordinate_Shader[0], dispatchList.LightCoordinate_Shader[1], dispatchList.LightCoordinate_Shader[2], dispatchList.LightCoordinate_Shader[3]); cb->WaveOffset = ezVec2I32(dispatch.WaveOffset_Shader[0], dispatch.WaveOffset_Shader[1]); cb->InvDepthTextureSize = ezVec2(1.0f / uiWidth, 1.0f / uiHeight); cb->SurfaceThickness = m_fSurfaceThickness; cb->ShadowContrast = m_fShadowContrast; cb->EyeIndex = uiEyeIndex; } renderViewContext.m_pRenderContext->Dispatch(dispatch.WaveCount[0], dispatch.WaveCount[1], dispatch.WaveCount[2]).IgnoreResult(); } // }); } bRendered = true; } } // return EZ_SUCCESS; } ezResult ezScreenSpaceShadowPass::Serialize(ezStreamWriter& inout_stream) const { EZ_SUCCEED_OR_RETURN(SUPER::Serialize(inout_stream)); inout_stream << m_fSurfaceThickness; inout_stream << m_fShadowContrast; return EZ_SUCCESS; } ezResult ezScreenSpaceShadowPass::Deserialize(ezStreamReader& inout_stream) { EZ_SUCCEED_OR_RETURN(SUPER::Deserialize(inout_stream)); const ezUInt32 uiVersion = ezTypeVersionReadContext::GetContext()->GetTypeVersion(GetStaticRTTI()); inout_stream >> m_fSurfaceThickness; inout_stream >> m_fShadowContrast; return EZ_SUCCESS; } void ezScreenSpaceShadowPass::CreateSamplerState() { if (m_hDepthSamplerState.IsInvalidated()) { ezGALSamplerStateCreationDescription desc; desc.m_MinFilter = ezGALTextureFilterMode::Point; desc.m_MagFilter = ezGALTextureFilterMode::Point; desc.m_MipFilter = ezGALTextureFilterMode::Point; desc.m_AddressU = ezImageAddressMode::ClampBorder; desc.m_AddressV = ezImageAddressMode::ClampBorder; desc.m_AddressW = ezImageAddressMode::ClampBorder; desc.m_BorderColor = ezColor::White; m_hDepthSamplerState = ezGALDevice::GetDefaultDevice()->CreateSamplerState(desc); } } EZ_STATICLINK_FILE(RendererCore, RendererCore_Pipeline_Implementation_Passes_ScreenSpaceShadowPass);