Add indirect lighting to Global Surface Atlas to achieve infinite GI bounces
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<float4> GlobalSurfaceAtlasObjects : register(t4);
|
||||
#if INDIRECT_LIGHT
|
||||
Texture2D<float4> ProbesState : register(t5);
|
||||
Texture2D<float4> ProbesDistance : register(t6);
|
||||
Texture2D<float4> ProbesIrradiance : register(t7);
|
||||
#else
|
||||
Texture3D<float> GlobalSDFTex[4] : register(t5);
|
||||
Texture3D<float> 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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user