Fix reflection probes capture seams on cube face edges due to volumetric fog

#3252
This commit is contained in:
Wojtek Figat
2025-07-03 13:54:22 +02:00
parent a138c6b062
commit bf345f13ce
5 changed files with 22 additions and 7 deletions

View File

@@ -200,12 +200,19 @@ void SceneRenderTask::RemoveGlobalCustomPostFx(PostProcessEffect* fx)
void SceneRenderTask::CollectPostFxVolumes(RenderContext& renderContext)
{
PROFILE_CPU();
// Cache WorldPosition used for PostFx volumes blending (RenderView caches it later on)
renderContext.View.WorldPosition = renderContext.View.Origin + renderContext.View.Position;
if (EnumHasAllFlags(ActorsSource, ActorsSources::Scenes))
{
Level::CollectPostFxVolumes(renderContext);
//ScopeLock lock(Level::ScenesLock);
for (Scene* scene : Level::Scenes)
{
if (scene->IsActiveInHierarchy())
scene->Rendering.CollectPostFxVolumes(renderContext);
}
}
if (EnumHasAllFlags(ActorsSource, ActorsSources::CustomActors))
{

View File

@@ -2,6 +2,7 @@
#include "ProbesRenderer.h"
#include "Renderer.h"
#include "RenderList.h"
#include "ReflectionsPass.h"
#include "Engine/Core/Config/GraphicsSettings.h"
#include "Engine/Engine/Time.h"
@@ -17,7 +18,6 @@
#include "Engine/Content/Content.h"
#include "Engine/Content/Assets/Shader.h"
#include "Engine/Content/AssetReference.h"
#include "Engine/Graphics/Graphics.h"
#include "Engine/Graphics/PixelFormat.h"
#include "Engine/Graphics/GPUContext.h"
#include "Engine/Graphics/Textures/GPUTexture.h"
@@ -115,7 +115,6 @@ private:
GPUTexture* _output = nullptr;
GPUTexture* _probe = nullptr;
GPUTexture* _tmpFace = nullptr;
GPUTexture* _skySHIrradianceMap = nullptr;
uint64 _updateFrameNumber = 0;
public:
@@ -132,6 +131,7 @@ public:
private:
void OnRender(RenderTask* task, GPUContext* context);
void OnSetupRender(RenderContext& renderContext);
#if COMPILE_WITH_DEV_ENV
bool _initShader = false;
void OnShaderReloading(Asset* obj)
@@ -234,6 +234,7 @@ bool ProbesRendererService::LazyInit()
task->Order = -100; // Run before main view rendering (realtime probes will get smaller latency)
task->Enabled = false;
task->IsCustomRendering = true;
task->ActorsSource = ActorsSources::ScenesAndCustomActors;
task->Output = _output;
auto& view = task->View;
view.Flags =
@@ -254,6 +255,7 @@ bool ProbesRendererService::LazyInit()
task->IsCameraCut = true;
task->Resize(probeResolution, probeResolution);
task->Render.Bind<ProbesRendererService, &ProbesRendererService::OnRender>(this);
task->SetupRender.Bind<ProbesRendererService, &ProbesRendererService::OnSetupRender>(this);
// Init render targets
_probe = GPUDevice::Instance->CreateTexture(TEXT("ProbesRenderer.Probe"));
@@ -362,7 +364,6 @@ void ProbesRendererService::Dispose()
SAFE_DELETE_GPU_RESOURCE(_output);
SAFE_DELETE_GPU_RESOURCE(_probe);
SAFE_DELETE_GPU_RESOURCE(_tmpFace);
SAFE_DELETE_GPU_RESOURCE(_skySHIrradianceMap);
SAFE_DELETE(_task);
_shader = nullptr;
_initDone = false;
@@ -589,3 +590,9 @@ void ProbesRendererService::OnRender(RenderTask* task, GPUContext* context)
_current.Type = ProbeEntry::Types::Invalid;
}
}
void ProbesRendererService::OnSetupRender(RenderContext& renderContext)
{
// Disable Volumetric Fog in reflection as it causes seams on cubemap face edges
renderContext.List->Setup.UseVolumetricFog = false;
}

View File

@@ -14,4 +14,5 @@ struct FLAXENGINE_API RenderSetup
bool UseTemporalAAJitter = false;
bool UseGlobalSDF = false;
bool UseGlobalSurfaceAtlas = false;
bool UseVolumetricFog = false;
};

View File

@@ -379,6 +379,7 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderCont
setup.UseGlobalSDF = (graphicsSettings->EnableGlobalSDF && EnumHasAnyFlags(view.Flags, ViewFlags::GlobalSDF)) ||
renderContext.View.Mode == ViewMode::GlobalSDF ||
setup.UseGlobalSurfaceAtlas;
setup.UseVolumetricFog = (view.Flags & ViewFlags::Fog) != ViewFlags::None;
// Disable TAA jitter in debug modes
switch (renderContext.View.Mode)

View File

@@ -99,7 +99,6 @@ float ComputeZSliceFromDepth(float sceneDepth, const VolumetricFogOptions& optio
bool VolumetricFogPass::Init(RenderContext& renderContext, GPUContext* context, VolumetricFogOptions& options)
{
auto& view = renderContext.View;
const auto fog = renderContext.List->Fog;
// Check if already prepared for this frame
@@ -111,7 +110,7 @@ bool VolumetricFogPass::Init(RenderContext& renderContext, GPUContext* context,
}
// Check if skip rendering
if (fog == nullptr || (view.Flags & ViewFlags::Fog) == ViewFlags::None || !_isSupported || checkIfSkipPass())
if (fog == nullptr || !renderContext.List->Setup.UseVolumetricFog || !_isSupported || checkIfSkipPass())
{
RenderTargetPool::Release(renderContext.Buffers->VolumetricFog);
renderContext.Buffers->VolumetricFog = nullptr;
@@ -184,7 +183,7 @@ bool VolumetricFogPass::Init(RenderContext& renderContext, GPUContext* context,
_cache.Data.PhaseG = options.ScatteringDistribution;
_cache.Data.VolumetricFogMaxDistance = options.Distance;
_cache.Data.MissedHistorySamplesCount = Math::Clamp(_cache.MissedHistorySamplesCount, 1, (int32)ARRAY_COUNT(_cache.Data.FrameJitterOffsets));
Matrix::Transpose(view.PrevViewProjection, _cache.Data.PrevWorldToClip);
Matrix::Transpose(renderContext.View.PrevViewProjection, _cache.Data.PrevWorldToClip);
_cache.Data.SkyLight.VolumetricScatteringIntensity = 0;
// Fill frame jitter history