diff --git a/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.cpp b/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.cpp index 952fbce3e..7045cc77d 100644 --- a/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.cpp +++ b/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.cpp @@ -455,6 +455,7 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext, } // Render indirect lighting + if (lightBuffer) { PROFILE_GPU_CPU("Indirect Lighting"); #if 0 @@ -477,7 +478,7 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext, #if USE_EDITOR // Probes debug drawing - if (debugProbes) + if (debugProbes && lightBuffer) { PROFILE_GPU_CPU("Debug Probes"); if (!_debugModel) diff --git a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp index 4aa4382a1..2c52711a1 100644 --- a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp +++ b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp @@ -1,6 +1,7 @@ // Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. #include "GlobalSurfaceAtlasPass.h" +#include "DynamicDiffuseGlobalIllumination.h" #include "../GlobalSignDistanceFieldPass.h" #include "../GBufferPass.h" #include "../RenderList.h" @@ -44,6 +45,7 @@ PACK_STRUCT(struct Data0 Vector4 ViewFrustumWorldRays[4]; GlobalSignDistanceFieldPass::ConstantsData GlobalSDF; GlobalSurfaceAtlasPass::ConstantsData GlobalSurfaceAtlas; + DynamicDiffuseGlobalIlluminationPass::ConstantsData DDGI; LightData Light; }); @@ -123,7 +125,7 @@ public: GPUTexture* AtlasGBuffer0 = nullptr; GPUTexture* AtlasGBuffer1 = nullptr; GPUTexture* AtlasGBuffer2 = nullptr; - GPUTexture* AtlasDirectLight = nullptr; + GPUTexture* AtlasLighting = nullptr; GPUBuffer* ChunksBuffer = nullptr; GPUBuffer* CulledObjectsBuffer = nullptr; int32 CulledObjectsCounterIndex = -1; @@ -155,7 +157,7 @@ public: RenderTargetPool::Release(AtlasGBuffer0); RenderTargetPool::Release(AtlasGBuffer1); RenderTargetPool::Release(AtlasGBuffer2); - RenderTargetPool::Release(AtlasDirectLight); + RenderTargetPool::Release(AtlasLighting); ClearObjects(); } @@ -238,13 +240,17 @@ bool GlobalSurfaceAtlasPass::setupResources() psDesc.DepthFunc = ComparisonFunc::Never; psDesc.BlendMode = BlendingMode::Add; psDesc.BlendMode.RenderTargetWriteMask = BlendingMode::ColorWrite::RGB; - psDesc.PS = shader->GetPS("PS_DirectLighting", 0); + psDesc.PS = shader->GetPS("PS_Lighting", 0); if (_psDirectLighting0->Init(psDesc)) return true; _psDirectLighting1 = device->CreatePipelineState(); - psDesc.PS = shader->GetPS("PS_DirectLighting", 1); + psDesc.PS = shader->GetPS("PS_Lighting", 1); if (_psDirectLighting1->Init(psDesc)) return true; + _psIndirectLighting = device->CreatePipelineState(); + psDesc.PS = shader->GetPS("PS_Lighting", 2); + if (_psIndirectLighting->Init(psDesc)) + return true; } return false; @@ -257,6 +263,7 @@ void GlobalSurfaceAtlasPass::OnShaderReloading(Asset* obj) SAFE_DELETE_GPU_RESOURCE(_psClear); SAFE_DELETE_GPU_RESOURCE(_psDirectLighting0); SAFE_DELETE_GPU_RESOURCE(_psDirectLighting1); + SAFE_DELETE_GPU_RESOURCE(_psIndirectLighting); SAFE_DELETE_GPU_RESOURCE(_psDebug); invalidateResources(); } @@ -274,6 +281,7 @@ void GlobalSurfaceAtlasPass::Dispose() SAFE_DELETE_GPU_RESOURCE(_psClear); SAFE_DELETE_GPU_RESOURCE(_psDirectLighting0); SAFE_DELETE_GPU_RESOURCE(_psDirectLighting1); + SAFE_DELETE_GPU_RESOURCE(_psIndirectLighting); SAFE_DELETE_GPU_RESOURCE(_psDebug); _cb0 = nullptr; _shader = nullptr; @@ -323,7 +331,7 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co INIT_ATLAS_TEXTURE(AtlasGBuffer0, GBUFFER0_FORMAT); INIT_ATLAS_TEXTURE(AtlasGBuffer1, GBUFFER1_FORMAT); INIT_ATLAS_TEXTURE(AtlasGBuffer2, GBUFFER2_FORMAT); - INIT_ATLAS_TEXTURE(AtlasDirectLight, LIGHT_BUFFER_FORMAT); + INIT_ATLAS_TEXTURE(AtlasLighting, LIGHT_BUFFER_FORMAT); desc.Flags = GPUTextureFlags::DepthStencil | GPUTextureFlags::ShaderResource; INIT_ATLAS_TEXTURE(AtlasDepth, PixelFormat::D16_UNorm); #undef INIT_ATLAS_TEXTURE @@ -679,7 +687,7 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co result.Atlas[1] = surfaceAtlasData.AtlasGBuffer0; result.Atlas[2] = surfaceAtlasData.AtlasGBuffer1; result.Atlas[3] = surfaceAtlasData.AtlasGBuffer2; - result.Atlas[4] = surfaceAtlasData.AtlasDirectLight; + result.Atlas[4] = surfaceAtlasData.AtlasLighting; result.Chunks = surfaceAtlasData.ChunksBuffer; result.CulledObjects = surfaceAtlasData.CulledObjectsBuffer; surfaceAtlasData.Result = result; @@ -690,14 +698,14 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co PROFILE_GPU_CPU("Direct Lighting"); // Copy emissive light into the final direct lighting atlas - // TODO: test perf diff when manually copying only dirty object tiles and dirty light tiles + // TODO: test perf diff when manually copying only dirty object tiles and dirty light tiles together with indirect lighting { PROFILE_GPU_CPU("Copy Emissive"); - context->CopyTexture(surfaceAtlasData.AtlasDirectLight, 0, 0, 0, 0, surfaceAtlasData.AtlasEmissive, 0); + context->CopyTexture(surfaceAtlasData.AtlasLighting, 0, 0, 0, 0, surfaceAtlasData.AtlasEmissive, 0); } context->SetViewportAndScissors(Viewport(0, 0, resolution, resolution)); - context->SetRenderTarget(surfaceAtlasData.AtlasDirectLight->View()); + context->SetRenderTarget(surfaceAtlasData.AtlasLighting->View()); context->BindSR(0, surfaceAtlasData.AtlasGBuffer0->View()); context->BindSR(1, surfaceAtlasData.AtlasGBuffer1->View()); context->BindSR(2, surfaceAtlasData.AtlasGBuffer2->View()); @@ -795,7 +803,38 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co context->SetState(_psDirectLighting1); VB_DRAW(); } + if (renderContext.View.Flags & ViewFlags::GI) + { + // TODO: add option to PostFx Volume for realtime GI type (None, DDGI) + DynamicDiffuseGlobalIlluminationPass::BindingData bindingDataDDGI; + if (!DynamicDiffuseGlobalIlluminationPass::Instance()->Get(renderContext.Buffers, bindingDataDDGI)) + { + // Collect tiles to shade + _vertexBuffer->Clear(); + for (const auto& e : surfaceAtlasData.Objects) + { + const auto& object = e.Value; + for (int32 tileIndex = 0; tileIndex < 6; tileIndex++) + { + auto* tile = object.Tiles[tileIndex]; + if (!tile) + continue; + VB_WRITE_TILE(tile); + } + } + // Draw draw indirect light + data.DDGI = bindingDataDDGI.Constants; + context->BindSR(5, bindingDataDDGI.ProbesState); + context->BindSR(6, bindingDataDDGI.ProbesDistance); + context->BindSR(7, bindingDataDDGI.ProbesIrradiance); + context->UpdateCB(_cb0, &data); + context->SetState(_psIndirectLighting); + VB_DRAW(); + } + } + + context->ResetSR(); context->ResetRenderTarget(); } @@ -809,6 +848,12 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co void GlobalSurfaceAtlasPass::RenderDebug(RenderContext& renderContext, GPUContext* context, GPUTexture* output) { + // Render all dependant effects + if (renderContext.View.Flags & ViewFlags::GI) + { + // TODO: add option to PostFx Volume for realtime GI type (None, DDGI) + DynamicDiffuseGlobalIlluminationPass::Instance()->Render(renderContext, context, nullptr); + } GlobalSignDistanceFieldPass::BindingData bindingDataSDF; BindingData bindingData; if (GlobalSignDistanceFieldPass::Instance()->Render(renderContext, context, bindingDataSDF) || Render(renderContext, context, bindingData)) diff --git a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.h b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.h index ca33ddc68..64b3e9705 100644 --- a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.h +++ b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.h @@ -47,6 +47,7 @@ private: GPUPipelineState* _psClear = nullptr; GPUPipelineState* _psDirectLighting0 = nullptr; GPUPipelineState* _psDirectLighting1 = nullptr; + GPUPipelineState* _psIndirectLighting = nullptr; GPUPipelineState* _psDebug = nullptr; GPUConstantBuffer* _cb0 = nullptr; GPUShaderProgramCS* _csCullObjects; diff --git a/Source/Shaders/GI/GlobalSurfaceAtlas.shader b/Source/Shaders/GI/GlobalSurfaceAtlas.shader index 9057419a5..83707ac38 100644 --- a/Source/Shaders/GI/GlobalSurfaceAtlas.shader +++ b/Source/Shaders/GI/GlobalSurfaceAtlas.shader @@ -8,6 +8,7 @@ #include "./Flax/LightingCommon.hlsl" #include "./Flax/GlobalSignDistanceField.hlsl" #include "./Flax/GI/GlobalSurfaceAtlas.hlsl" +#include "./Flax/GI/DDGI.hlsl" META_CB_BEGIN(0, Data) float3 ViewWorldPos; @@ -19,6 +20,7 @@ float ViewFarPlane; float4 ViewFrustumWorldRays[4]; GlobalSDFData GlobalSDF; GlobalSurfaceAtlasData GlobalSurfaceAtlas; +DDGIData DDGI; LightData Light; META_CB_END @@ -60,7 +62,7 @@ void PS_Clear(out float4 Light : SV_Target0, out float4 RT0 : SV_Target1, out fl RT2 = float4(1, 0, 0, 0); } -#ifdef _PS_DirectLighting +#ifdef _PS_Lighting #include "./Flax/GBuffer.hlsl" #include "./Flax/Matrix.hlsl" @@ -68,14 +70,21 @@ void PS_Clear(out float4 Light : SV_Target0, out float4 RT0 : SV_Target1, out fl // GBuffer+Depth at 0-3 slots Buffer GlobalSurfaceAtlasObjects : register(t4); +#if INDIRECT_LIGHT +Texture2D ProbesState : register(t5); +Texture2D ProbesDistance : register(t6); +Texture2D ProbesIrradiance : register(t7); +#else Texture3D GlobalSDFTex[4] : register(t5); Texture3D GlobalSDFMip[4] : register(t9); +#endif // Pixel shader for Global Surface Atlas shading with direct light contribution META_PS(true, FEATURE_LEVEL_SM5) META_PERMUTATION_1(RADIAL_LIGHT=0) META_PERMUTATION_1(RADIAL_LIGHT=1) -float4 PS_DirectLighting(AtlasVertexOutput input) : SV_Target +META_PERMUTATION_1(INDIRECT_LIGHT=1) +float4 PS_Lighting(AtlasVertexOutput input) : SV_Target { // Load current tile info GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(GlobalSurfaceAtlasObjects, input.TileAddress); @@ -104,6 +113,16 @@ float4 PS_DirectLighting(AtlasVertexOutput input) : SV_Target float4x4 tileLocalToWorld = Inverse(tile.WorldToLocal); gBuffer.WorldPos = mul(float4(gBufferTilePos, 1), tileLocalToWorld).xyz; +#if INDIRECT_LIGHT + // Sample irradiance + float bias = 1.0f; + float3 irradiance = SampleDDGIIrradiance(DDGI, ProbesState, ProbesDistance, ProbesIrradiance, gBuffer.WorldPos, gBuffer.Normal, bias); + + // Calculate lighting + float3 diffuseColor = GetDiffuseColor(gBuffer); + float3 diffuse = Diffuse_Lambert(diffuseColor); + float4 light = float4(diffuse * irradiance, 1); +#else // Calculate shadowing float3 L = Light.Direction; #if RADIAL_LIGHT @@ -150,6 +169,7 @@ float4 PS_DirectLighting(AtlasVertexOutput input) : SV_Target bool isSpotLight = false; #endif float4 light = GetLighting(ViewWorldPos, Light, gBuffer, shadowMask, RADIAL_LIGHT, isSpotLight); +#endif return light; }