diff --git a/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp b/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp index c89688a9d..e2e07b397 100644 --- a/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp +++ b/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp @@ -74,24 +74,21 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, SpanEnvironmentProbes.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, SpanPointLights.Count() && data.LocalLightsCount < MaxLocalLights; i++) { diff --git a/Source/Engine/Level/Actors/EnvironmentProbe.cpp b/Source/Engine/Level/Actors/EnvironmentProbe.cpp index 4584cfe14..ada74d410 100644 --- a/Source/Engine/Level/Actors/EnvironmentProbe.cpp +++ b/Source/Engine/Level/Actors/EnvironmentProbe.cpp @@ -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); } } } diff --git a/Source/Engine/Level/Actors/EnvironmentProbe.h b/Source/Engine/Level/Actors/EnvironmentProbe.h index dd90a446c..bde48d309 100644 --- a/Source/Engine/Level/Actors/EnvironmentProbe.h +++ b/Source/Engine/Level/Actors/EnvironmentProbe.h @@ -90,13 +90,6 @@ public: /// API_PROPERTY() bool IsUsingCustomProbe() const; - /// - /// Setup probe data structure - /// - /// Rendering context - /// Packed probe data to set - void SetupProbeData(const RenderContext& renderContext, struct ShaderEnvProbeData* data) const; - /// /// Gets the custom probe (null if using baked one or none). /// diff --git a/Source/Engine/Renderer/ReflectionsPass.cpp b/Source/Engine/Renderer/ReflectionsPass.cpp index f7e825e14..9a136d354 100644 --- a/Source/Engine/Renderer/ReflectionsPass.cpp +++ b/Source/Engine/Renderer/ReflectionsPass.cpp @@ -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(p2->GetScaledRadius() - p1->GetScaledRadius()); - - // Check if are the same + int32 res = static_cast(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); diff --git a/Source/Engine/Renderer/RenderList.cpp b/Source/Engine/Renderer/RenderList.cpp index 67f6bab03..29b9bd622 100644 --- a/Source/Engine/Renderer/RenderList.cpp +++ b/Source/Engine/Renderer/RenderList.cpp @@ -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) diff --git a/Source/Engine/Renderer/RenderList.h b/Source/Engine/Renderer/RenderList.h index ebfdaf03d..5f2aecbd9 100644 --- a/Source/Engine/Renderer/RenderList.h +++ b/Source/Engine/Renderer/RenderList.h @@ -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: /// /// Environment probes to use for rendering reflections /// - Array EnvironmentProbes; + Array EnvironmentProbes; /// /// Decals registered for the rendering. diff --git a/Source/Engine/Renderer/Renderer.cpp b/Source/Engine/Renderer/Renderer.cpp index f3c4ac6d2..0ef39bb30 100644 --- a/Source/Engine/Renderer/Renderer.cpp +++ b/Source/Engine/Renderer/Renderer.cpp @@ -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;