Optimize env probes data storage in renderer
This commit is contained in:
@@ -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++)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user