From 0af86d8cb8c0249c5a0ff556d6e7634ea4cfe8e5 Mon Sep 17 00:00:00 2001 From: Wojciech Figat Date: Tue, 19 Jul 2022 10:33:52 +0200 Subject: [PATCH] Add HDR env probes support --- Source/Engine/Core/Config/GraphicsSettings.h | 6 ++++ .../Engine/Graphics/Textures/GPUTexture.cpp | 7 +++-- Source/Engine/Graphics/Textures/GPUTexture.h | 8 ++++-- Source/Engine/Renderer/ProbesRenderer.cpp | 28 ++++++++++++------- Source/Engine/Renderer/ProbesRenderer.h | 9 ++---- 5 files changed, 37 insertions(+), 21 deletions(-) diff --git a/Source/Engine/Core/Config/GraphicsSettings.h b/Source/Engine/Core/Config/GraphicsSettings.h index eab796109..891061bf5 100644 --- a/Source/Engine/Core/Config/GraphicsSettings.h +++ b/Source/Engine/Core/Config/GraphicsSettings.h @@ -69,6 +69,12 @@ public: API_FIELD(Attributes = "EditorOrder(1500), EditorDisplay(\"Quality\")") ProbeCubemapResolution DefaultProbeResolution = ProbeCubemapResolution::_128; + /// + /// If checked, Environment Probes will use HDR texture format. Improves quality in very bright scenes at cost of higher memory usage. + /// + API_FIELD(Attributes = "EditorOrder(1502), EditorDisplay(\"Quality\")") + bool UeeHDRProbes = false; + /// /// If checked, enables Global SDF rendering. This can be used in materials, shaders, and particles. /// diff --git a/Source/Engine/Graphics/Textures/GPUTexture.cpp b/Source/Engine/Graphics/Textures/GPUTexture.cpp index b7aa53dba..167dfab60 100644 --- a/Source/Engine/Graphics/Textures/GPUTexture.cpp +++ b/Source/Engine/Graphics/Textures/GPUTexture.cpp @@ -533,7 +533,7 @@ GPUTexture* GPUTexture::ToStagingUpload() const return staging; } -bool GPUTexture::Resize(int32 width, int32 height, int32 depth) +bool GPUTexture::Resize(int32 width, int32 height, int32 depth, PixelFormat format) { // Validate texture is created if (!IsAllocated()) @@ -543,11 +543,14 @@ bool GPUTexture::Resize(int32 width, int32 height, int32 depth) } auto desc = GetDescription(); + if (format == PixelFormat::Unknown) + format = desc.Format; // Skip if size won't change - if (desc.Width == width && desc.Height == height && desc.Depth == depth) + if (desc.Width == width && desc.Height == height && desc.Depth == depth && desc.Format == format) return false; + desc.Format = format; desc.Width = width; desc.Height = height; desc.Depth = depth; diff --git a/Source/Engine/Graphics/Textures/GPUTexture.h b/Source/Engine/Graphics/Textures/GPUTexture.h index 35fad9238..bb1aa1eb2 100644 --- a/Source/Engine/Graphics/Textures/GPUTexture.h +++ b/Source/Engine/Graphics/Textures/GPUTexture.h @@ -486,11 +486,12 @@ public: /// /// The width. /// The height. + /// The new texture format. Use Unknown to remain texture format unchanged. /// True if fails, otherwise false. - API_FUNCTION() bool Resize(int32 width, int32 height) + API_FUNCTION() bool Resize(int32 width, int32 height, PixelFormat format = PixelFormat::Unknown) { const auto depth = IsAllocated() ? Depth() : 1; - return Resize(width, height, depth); + return Resize(width, height, depth, format); } /// @@ -499,8 +500,9 @@ public: /// The width. /// The height. /// The depth. + /// The new texture format. Use Unknown to remain texture format unchanged. /// True if fails, otherwise false. - API_FUNCTION() bool Resize(int32 width, int32 height, int32 depth); + API_FUNCTION() bool Resize(int32 width, int32 height, int32 depth, PixelFormat format = PixelFormat::Unknown); public: /// diff --git a/Source/Engine/Renderer/ProbesRenderer.cpp b/Source/Engine/Renderer/ProbesRenderer.cpp index 9c27f8c57..51791edd3 100644 --- a/Source/Engine/Renderer/ProbesRenderer.cpp +++ b/Source/Engine/Renderer/ProbesRenderer.cpp @@ -17,12 +17,12 @@ #include "Engine/Engine/Time.h" #include "Engine/Content/Assets/Shader.h" #include "Engine/Content/AssetReference.h" +#include "Engine/Graphics/Graphics.h" #include "Engine/Graphics/GPUContext.h" #include "Engine/Graphics/Textures/GPUTexture.h" #include "Engine/Graphics/Textures/TextureData.h" #include "Engine/Graphics/RenderTask.h" #include "Engine/Engine/Engine.h" -#include "Engine/Graphics/Graphics.h" /// /// Custom task called after downloading probe texture data to save it. @@ -202,6 +202,11 @@ int32 ProbesRenderer::Entry::GetResolution() const return (int32)resolution; } +PixelFormat ProbesRenderer::Entry::GetFormat() const +{ + return GraphicsSettings::Get()->UeeHDRProbes ? PixelFormat::R11G11B10_Float : PixelFormat::R8G8B8A8_UNorm; +} + int32 ProbesRenderer::GetBakeQueueSize() { return _probesToBake.Count(); @@ -245,7 +250,8 @@ bool ProbesRenderer::Init() // Init rendering pipeline _output = GPUDevice::Instance->CreateTexture(TEXT("Output")); const int32 probeResolution = _current.GetResolution(); - if (_output->Init(GPUTextureDescription::New2D(probeResolution, probeResolution, PixelFormat::R8G8B8A8_UNorm))) + const PixelFormat probeFormat = _current.GetFormat(); + if (_output->Init(GPUTextureDescription::New2D(probeResolution, probeResolution, probeFormat))) return true; _task = New(); auto task = _task; @@ -270,14 +276,14 @@ bool ProbesRenderer::Init() view.MaxShadowsQuality = Quality::Low; task->IsCameraCut = true; task->Resize(probeResolution, probeResolution); - task->Render.Bind(onRender); + task->Render.Bind(OnRender); // Init render targets _probe = GPUDevice::Instance->CreateTexture(TEXT("ProbesUpdate.Probe")); - if (_probe->Init(GPUTextureDescription::NewCube(probeResolution, _output->Format(), GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget | GPUTextureFlags::PerMipViews, 0))) + if (_probe->Init(GPUTextureDescription::NewCube(probeResolution, probeFormat, GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget | GPUTextureFlags::PerMipViews, 0))) return true; _tmpFace = GPUDevice::Instance->CreateTexture(TEXT("ProbesUpdate.TmpFace")); - if (_tmpFace->Init(GPUTextureDescription::New2D(probeResolution, probeResolution, 0, _output->Format(), GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget | GPUTextureFlags::PerMipViews))) + if (_tmpFace->Init(GPUTextureDescription::New2D(probeResolution, probeResolution, 0, probeFormat, GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget | GPUTextureFlags::PerMipViews))) return true; // Mark as ready @@ -400,7 +406,7 @@ bool fixFarPlaneTreeExecute(Actor* actor, const Vector3& position, float& farPla return true; } -void ProbesRenderer::onRender(RenderTask* task, GPUContext* context) +void ProbesRenderer::OnRender(RenderTask* task, GPUContext* context) { ASSERT(_current.Type != EntryType::Invalid && _updateFrameNumber == 0); switch (_current.Type) @@ -426,6 +432,7 @@ void ProbesRenderer::onRender(RenderTask* task, GPUContext* context) // Init float customCullingNear = -1; const int32 probeResolution = _current.GetResolution(); + const PixelFormat probeFormat = _current.GetFormat(); if (_current.Type == EntryType::EnvProbe) { auto envProbe = (EnvironmentProbe*)_current.Actor.Get(); @@ -433,8 +440,9 @@ void ProbesRenderer::onRender(RenderTask* task, GPUContext* context) float radius = envProbe->GetScaledRadius(); float nearPlane = Math::Max(0.1f, envProbe->CaptureNearPlane); - // Fix far plane distance + // Adjust far plane distance float farPlane = Math::Max(radius, nearPlane + 100.0f); + farPlane *= farPlane < 10000 ? 10 : 4; Function f(&fixFarPlaneTreeExecute); SceneQuery::TreeExecute(f, position, farPlane); @@ -457,10 +465,10 @@ void ProbesRenderer::onRender(RenderTask* task, GPUContext* context) _task->CameraCut(); // Resize buffers - bool resizeFailed = _output->Resize(probeResolution, probeResolution); + bool resizeFailed = _output->Resize(probeResolution, probeResolution, probeFormat); + resizeFailed |= _probe->Resize(probeResolution, probeResolution, probeFormat); + resizeFailed |= _tmpFace->Resize(probeResolution, probeResolution, probeFormat); resizeFailed |= _task->Resize(probeResolution, probeResolution); - resizeFailed |= _probe->Resize(probeResolution, probeResolution); - resizeFailed |= _tmpFace->Resize(probeResolution, probeResolution); if (resizeFailed) LOG(Error, "Failed to resize probe"); diff --git a/Source/Engine/Renderer/ProbesRenderer.h b/Source/Engine/Renderer/ProbesRenderer.h index 26cc4351d..3cd1f40bd 100644 --- a/Source/Engine/Renderer/ProbesRenderer.h +++ b/Source/Engine/Renderer/ProbesRenderer.h @@ -2,6 +2,7 @@ #pragma once +#include "Engine/Graphics/PixelFormat.h" #include "Engine/Scripting/ScriptingObjectReference.h" #include "Engine/Level/Actor.h" @@ -18,7 +19,6 @@ class RenderTask; class ProbesRenderer { public: - enum class EntryType { Invalid = 0, @@ -46,10 +46,10 @@ public: bool UseTextureData() const; int32 GetResolution() const; + PixelFormat GetFormat() const; }; public: - /// /// Minimum amount of time between two updated of probes /// @@ -67,7 +67,6 @@ public: static Delegate OnFinishBake; public: - /// /// Checks if resources are ready to render probes (shaders or textures may be during loading). /// @@ -86,7 +85,6 @@ public: static void Release(); public: - /// /// Register probe to baking service. /// @@ -102,6 +100,5 @@ public: static void Bake(SkyLight* probe, float timeout = 0); private: - - static void onRender(RenderTask* task, GPUContext* context); + static void OnRender(RenderTask* task, GPUContext* context); };