Optimize env probes data storage in renderer

This commit is contained in:
Wojtek Figat
2024-03-26 15:01:12 +01:00
parent 4ab572426d
commit 55af307c43
7 changed files with 63 additions and 49 deletions

View File

@@ -74,24 +74,21 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<by
}
// Set reflection probe data
EnvironmentProbe* probe = nullptr;
bool noEnvProbe = true;
// TODO: optimize env probe searching for a transparent material - use spatial cache for renderer to find it
const BoundingSphere objectBoundsWorld(drawCall.ObjectPosition + view.Origin, drawCall.ObjectRadius);
const BoundingSphere objectBounds(drawCall.ObjectPosition, drawCall.ObjectRadius);
for (int32 i = 0; i < cache->EnvironmentProbes.Count(); i++)
{
const auto p = cache->EnvironmentProbes[i];
if (CollisionsHelper::SphereIntersectsSphere(objectBoundsWorld, p->GetSphere()))
const RenderEnvironmentProbeData& probe = cache->EnvironmentProbes.Get()[i];
if (CollisionsHelper::SphereIntersectsSphere(objectBounds, BoundingSphere(probe.Position, probe.Radius)))
{
probe = p;
noEnvProbe = false;
probe.SetShaderData(data.EnvironmentProbe);
params.GPUContext->BindSR(envProbeShaderRegisterIndex, probe.Texture);
break;
}
}
if (probe && probe->GetProbe())
{
probe->SetupProbeData(params.RenderContext, &data.EnvironmentProbe);
params.GPUContext->BindSR(envProbeShaderRegisterIndex, probe->GetProbe());
}
else
if (noEnvProbe)
{
data.EnvironmentProbe.Data1 = Float4::Zero;
params.GPUContext->UnBindSR(envProbeShaderRegisterIndex);
@@ -99,7 +96,6 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<by
// Set local lights
data.LocalLightsCount = 0;
const BoundingSphere objectBounds(drawCall.ObjectPosition, drawCall.ObjectRadius);
// TODO: optimize lights searching for a transparent material - use spatial cache for renderer to find it
for (int32 i = 0; i < cache->PointLights.Count() && data.LocalLightsCount < MaxLocalLights; i++)
{

View File

@@ -4,6 +4,7 @@
#include "Engine/Platform/FileSystem.h"
#include "Engine/Graphics/RenderView.h"
#include "Engine/Graphics/RenderTask.h"
#include "Engine/Graphics/GPUContext.h"
#include "Engine/Graphics/Textures/GPUTexture.h"
#include "Engine/Graphics/Textures/TextureData.h"
#include "Engine/Renderer/RenderList.h"
@@ -12,7 +13,7 @@
#include "Engine/Content/Content.h"
#include "Engine/ContentExporters/AssetExporters.h"
#include "Engine/ContentImporters/AssetsImportingManager.h"
#include "Engine/Graphics/GPUContext.h"
#include "Engine/Graphics/RenderTools.h"
#include "Engine/Serialization/Serialization.h"
#include "Engine/Level/Scene/Scene.h"
@@ -61,13 +62,6 @@ bool EnvironmentProbe::IsUsingCustomProbe() const
return _isUsingCustomProbe;
}
void EnvironmentProbe::SetupProbeData(const RenderContext& renderContext, ShaderEnvProbeData* data) const
{
const float radius = GetScaledRadius();
data->Data0 = Float4(GetPosition() - renderContext.View.Origin, 0);
data->Data1 = Float4(radius, 1.0f / radius, Brightness, 0);
}
CubeTexture* EnvironmentProbe::GetCustomProbe() const
{
return _isUsingCustomProbe ? _probe : nullptr;
@@ -181,11 +175,29 @@ void EnvironmentProbe::Draw(RenderContext& renderContext)
EnumHasAnyFlags(renderContext.View.Flags, ViewFlags::Reflections) &&
EnumHasAnyFlags(renderContext.View.Pass, DrawPass::GBuffer))
{
// Size culling
const Float3 position = _sphere.Center - renderContext.View.Origin;
const float radius = GetScaledRadius();
const float drawMinScreenSize = 0.02f;
const auto lodView = (renderContext.LodProxyView ? renderContext.LodProxyView : &renderContext.View);
const float screenRadiusSquared = RenderTools::ComputeBoundsScreenRadiusSquared(position, radius, *lodView) * renderContext.View.ModelLODDistanceFactorSqrt;
if (Math::Square(drawMinScreenSize * 0.5f) > screenRadiusSquared)
return;
// Realtime probe update
if (UpdateMode == ProbeUpdateMode::Realtime)
ProbesRenderer::Bake(this, 0.0f);
if ((_probe != nullptr && _probe->IsLoaded()) || _probeTexture != nullptr)
GPUTexture* texture = GetProbe();
if (texture)
{
renderContext.List->EnvironmentProbes.Add(this);
RenderEnvironmentProbeData data;
data.Texture = texture;
data.Position = position;
data.Radius = radius;
data.Brightness = Brightness;
data.HashID = GetHash(_id);
renderContext.List->EnvironmentProbes.Add(data);
}
}
}

View File

@@ -90,13 +90,6 @@ public:
/// </summary>
API_PROPERTY() bool IsUsingCustomProbe() const;
/// <summary>
/// Setup probe data structure
/// </summary>
/// <param name="renderContext">Rendering context</param>
/// <param name="data">Packed probe data to set</param>
void SetupProbeData(const RenderContext& renderContext, struct ShaderEnvProbeData* data) const;
/// <summary>
/// Gets the custom probe (null if using baked one or none).
/// </summary>

View File

@@ -336,19 +336,15 @@ void ReflectionsPass::Dispose()
_preIntegratedGF = nullptr;
}
bool sortProbes(EnvironmentProbe* const& p1, EnvironmentProbe* const& p2)
bool SortProbes(RenderEnvironmentProbeData const& p1, RenderEnvironmentProbeData const& p2)
{
// Compare by radius
int32 res = static_cast<int32>(p2->GetScaledRadius() - p1->GetScaledRadius());
// Check if are the same
int32 res = static_cast<int32>(p2.Radius - p1.Radius);
if (res == 0)
{
// Compare by ID to prevent flickering
res = GetHash(p2->GetID()) - GetHash(p1->GetID());
res = p2.HashID - p1.HashID;
}
// Return result
return res < 0;
}
@@ -400,38 +396,34 @@ void ReflectionsPass::Render(RenderContext& renderContext, GPUTextureView* light
context->SetRenderTarget(*reflectionsBuffer);
// Sort probes by the radius
Sorting::QuickSort(renderContext.List->EnvironmentProbes.Get(), renderContext.List->EnvironmentProbes.Count(), &sortProbes);
// TODO: don't render too far probes, check area of the screen and apply culling!
Sorting::QuickSort(renderContext.List->EnvironmentProbes.Get(), renderContext.List->EnvironmentProbes.Count(), &SortProbes);
// Render all env probes
for (int32 probeIndex = 0; probeIndex < probesCount; probeIndex++)
for (int32 i = 0; i < probesCount; i++)
{
// Cache data
auto probe = renderContext.List->EnvironmentProbes[probeIndex];
float probeRadius = probe->GetScaledRadius();
Float3 probePosition = probe->GetPosition() - renderContext.View.Origin;
const RenderEnvironmentProbeData& probe = renderContext.List->EnvironmentProbes.Get()[i];
// Get distance from view center to light center less radius (check if view is inside a sphere)
const float sphereModelScale = 2.0f;
float distance = ViewToCenterLessRadius(view, probePosition, probeRadius);
float distance = ViewToCenterLessRadius(view, probe.Position, probe.Radius);
bool isViewInside = distance < 0;
// Calculate world view projection matrix for the light sphere
Matrix world, wvp, matrix;
Matrix::Scaling(probeRadius * sphereModelScale, wvp);
Matrix::Translation(probePosition, matrix);
Matrix::Scaling(probe.Radius * sphereModelScale, wvp);
Matrix::Translation(probe.Position, matrix);
Matrix::Multiply(wvp, matrix, world);
Matrix::Multiply(world, view.ViewProjection(), wvp);
// Pack probe properties buffer
probe->SetupProbeData(renderContext, &data.PData);
probe.SetShaderData(data.PData);
Matrix::Transpose(wvp, data.WVP);
// Render reflections
context->UpdateCB(cb, &data);
context->BindCB(0, cb);
context->BindSR(4, probe->GetProbe());
context->BindSR(4, probe.Texture);
context->SetState(isViewInside ? _psProbeInverted : _psProbeNormal);
_sphereModel->Render(context);

View File

@@ -106,6 +106,11 @@ void RenderSkyLightData::SetShaderData(ShaderLightData& data, bool useShadow) co
data.InverseSquared = 0;
data.RadiusInv = 1.0f / Radius;
}
void RenderEnvironmentProbeData::SetShaderData(ShaderEnvProbeData& data) const
{
data.Data0 = Float4(Position, 0);
data.Data1 = Float4(Radius, 1.0f / Radius, Brightness, 0);
}
void* RendererAllocation::Allocate(uintptr size)

View File

@@ -106,6 +106,17 @@ struct RenderSkyLightData : RenderLightData
void SetShaderData(ShaderLightData& data, bool useShadow) const;
};
struct RenderEnvironmentProbeData
{
GPUTexture* Texture;
Float3 Position;
float Radius;
float Brightness;
uint32 HashID;
void SetShaderData(ShaderEnvProbeData& data) const;
};
struct RenderDecalData
{
Matrix World;
@@ -290,7 +301,7 @@ public:
/// <summary>
/// Environment probes to use for rendering reflections
/// </summary>
Array<EnvironmentProbe*> EnvironmentProbes;
Array<RenderEnvironmentProbeData> EnvironmentProbes;
/// <summary>
/// Decals registered for the rendering.

View File

@@ -180,6 +180,11 @@ void Renderer::Render(SceneRenderTask* task)
RenderContextBatch renderContextBatch(task);
renderContextBatch.Contexts.Add(renderContext);
// Pre-init render view cache early in case it's used in PreRender drawing
Float4 jitter = renderContext.View.TemporalAAJitter; // Preserve temporal jitter value (PrepareCache modifies it)
renderContext.View.PrepareCache(renderContext, viewport.Width, viewport.Height, Float2::Zero);
renderContext.View.TemporalAAJitter = jitter;
#if USE_EDITOR
// Turn on low quality rendering during baking lightmaps (leave more GPU power for baking)
const auto flags = renderContext.View.Flags;