Add HDR env probes support

This commit is contained in:
Wojciech Figat
2022-07-19 10:33:52 +02:00
parent b184650835
commit 0af86d8cb8
5 changed files with 37 additions and 21 deletions

View File

@@ -69,6 +69,12 @@ public:
API_FIELD(Attributes = "EditorOrder(1500), EditorDisplay(\"Quality\")") API_FIELD(Attributes = "EditorOrder(1500), EditorDisplay(\"Quality\")")
ProbeCubemapResolution DefaultProbeResolution = ProbeCubemapResolution::_128; ProbeCubemapResolution DefaultProbeResolution = ProbeCubemapResolution::_128;
/// <summary>
/// If checked, Environment Probes will use HDR texture format. Improves quality in very bright scenes at cost of higher memory usage.
/// </summary>
API_FIELD(Attributes = "EditorOrder(1502), EditorDisplay(\"Quality\")")
bool UeeHDRProbes = false;
/// <summary> /// <summary>
/// If checked, enables Global SDF rendering. This can be used in materials, shaders, and particles. /// If checked, enables Global SDF rendering. This can be used in materials, shaders, and particles.
/// </summary> /// </summary>

View File

@@ -533,7 +533,7 @@ GPUTexture* GPUTexture::ToStagingUpload() const
return staging; 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 // Validate texture is created
if (!IsAllocated()) if (!IsAllocated())
@@ -543,11 +543,14 @@ bool GPUTexture::Resize(int32 width, int32 height, int32 depth)
} }
auto desc = GetDescription(); auto desc = GetDescription();
if (format == PixelFormat::Unknown)
format = desc.Format;
// Skip if size won't change // 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; return false;
desc.Format = format;
desc.Width = width; desc.Width = width;
desc.Height = height; desc.Height = height;
desc.Depth = depth; desc.Depth = depth;

View File

@@ -486,11 +486,12 @@ public:
/// </summary> /// </summary>
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <param name="height">The height.</param> /// <param name="height">The height.</param>
/// <param name="format">The new texture format. Use Unknown to remain texture format unchanged.</param>
/// <returns>True if fails, otherwise false.</returns> /// <returns>True if fails, otherwise false.</returns>
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; const auto depth = IsAllocated() ? Depth() : 1;
return Resize(width, height, depth); return Resize(width, height, depth, format);
} }
/// <summary> /// <summary>
@@ -499,8 +500,9 @@ public:
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <param name="height">The height.</param> /// <param name="height">The height.</param>
/// <param name="depth">The depth.</param> /// <param name="depth">The depth.</param>
/// <param name="format">The new texture format. Use Unknown to remain texture format unchanged.</param>
/// <returns>True if fails, otherwise false.</returns> /// <returns>True if fails, otherwise false.</returns>
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: public:
/// <summary> /// <summary>

View File

@@ -17,12 +17,12 @@
#include "Engine/Engine/Time.h" #include "Engine/Engine/Time.h"
#include "Engine/Content/Assets/Shader.h" #include "Engine/Content/Assets/Shader.h"
#include "Engine/Content/AssetReference.h" #include "Engine/Content/AssetReference.h"
#include "Engine/Graphics/Graphics.h"
#include "Engine/Graphics/GPUContext.h" #include "Engine/Graphics/GPUContext.h"
#include "Engine/Graphics/Textures/GPUTexture.h" #include "Engine/Graphics/Textures/GPUTexture.h"
#include "Engine/Graphics/Textures/TextureData.h" #include "Engine/Graphics/Textures/TextureData.h"
#include "Engine/Graphics/RenderTask.h" #include "Engine/Graphics/RenderTask.h"
#include "Engine/Engine/Engine.h" #include "Engine/Engine/Engine.h"
#include "Engine/Graphics/Graphics.h"
/// <summary> /// <summary>
/// Custom task called after downloading probe texture data to save it. /// Custom task called after downloading probe texture data to save it.
@@ -202,6 +202,11 @@ int32 ProbesRenderer::Entry::GetResolution() const
return (int32)resolution; return (int32)resolution;
} }
PixelFormat ProbesRenderer::Entry::GetFormat() const
{
return GraphicsSettings::Get()->UeeHDRProbes ? PixelFormat::R11G11B10_Float : PixelFormat::R8G8B8A8_UNorm;
}
int32 ProbesRenderer::GetBakeQueueSize() int32 ProbesRenderer::GetBakeQueueSize()
{ {
return _probesToBake.Count(); return _probesToBake.Count();
@@ -245,7 +250,8 @@ bool ProbesRenderer::Init()
// Init rendering pipeline // Init rendering pipeline
_output = GPUDevice::Instance->CreateTexture(TEXT("Output")); _output = GPUDevice::Instance->CreateTexture(TEXT("Output"));
const int32 probeResolution = _current.GetResolution(); 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; return true;
_task = New<SceneRenderTask>(); _task = New<SceneRenderTask>();
auto task = _task; auto task = _task;
@@ -270,14 +276,14 @@ bool ProbesRenderer::Init()
view.MaxShadowsQuality = Quality::Low; view.MaxShadowsQuality = Quality::Low;
task->IsCameraCut = true; task->IsCameraCut = true;
task->Resize(probeResolution, probeResolution); task->Resize(probeResolution, probeResolution);
task->Render.Bind(onRender); task->Render.Bind(OnRender);
// Init render targets // Init render targets
_probe = GPUDevice::Instance->CreateTexture(TEXT("ProbesUpdate.Probe")); _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; return true;
_tmpFace = GPUDevice::Instance->CreateTexture(TEXT("ProbesUpdate.TmpFace")); _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; return true;
// Mark as ready // Mark as ready
@@ -400,7 +406,7 @@ bool fixFarPlaneTreeExecute(Actor* actor, const Vector3& position, float& farPla
return true; return true;
} }
void ProbesRenderer::onRender(RenderTask* task, GPUContext* context) void ProbesRenderer::OnRender(RenderTask* task, GPUContext* context)
{ {
ASSERT(_current.Type != EntryType::Invalid && _updateFrameNumber == 0); ASSERT(_current.Type != EntryType::Invalid && _updateFrameNumber == 0);
switch (_current.Type) switch (_current.Type)
@@ -426,6 +432,7 @@ void ProbesRenderer::onRender(RenderTask* task, GPUContext* context)
// Init // Init
float customCullingNear = -1; float customCullingNear = -1;
const int32 probeResolution = _current.GetResolution(); const int32 probeResolution = _current.GetResolution();
const PixelFormat probeFormat = _current.GetFormat();
if (_current.Type == EntryType::EnvProbe) if (_current.Type == EntryType::EnvProbe)
{ {
auto envProbe = (EnvironmentProbe*)_current.Actor.Get(); auto envProbe = (EnvironmentProbe*)_current.Actor.Get();
@@ -433,8 +440,9 @@ void ProbesRenderer::onRender(RenderTask* task, GPUContext* context)
float radius = envProbe->GetScaledRadius(); float radius = envProbe->GetScaledRadius();
float nearPlane = Math::Max(0.1f, envProbe->CaptureNearPlane); float nearPlane = Math::Max(0.1f, envProbe->CaptureNearPlane);
// Fix far plane distance // Adjust far plane distance
float farPlane = Math::Max(radius, nearPlane + 100.0f); float farPlane = Math::Max(radius, nearPlane + 100.0f);
farPlane *= farPlane < 10000 ? 10 : 4;
Function<bool(Actor*, const Vector3&, float&)> f(&fixFarPlaneTreeExecute); Function<bool(Actor*, const Vector3&, float&)> f(&fixFarPlaneTreeExecute);
SceneQuery::TreeExecute<const Vector3&, float&>(f, position, farPlane); SceneQuery::TreeExecute<const Vector3&, float&>(f, position, farPlane);
@@ -457,10 +465,10 @@ void ProbesRenderer::onRender(RenderTask* task, GPUContext* context)
_task->CameraCut(); _task->CameraCut();
// Resize buffers // 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 |= _task->Resize(probeResolution, probeResolution);
resizeFailed |= _probe->Resize(probeResolution, probeResolution);
resizeFailed |= _tmpFace->Resize(probeResolution, probeResolution);
if (resizeFailed) if (resizeFailed)
LOG(Error, "Failed to resize probe"); LOG(Error, "Failed to resize probe");

View File

@@ -2,6 +2,7 @@
#pragma once #pragma once
#include "Engine/Graphics/PixelFormat.h"
#include "Engine/Scripting/ScriptingObjectReference.h" #include "Engine/Scripting/ScriptingObjectReference.h"
#include "Engine/Level/Actor.h" #include "Engine/Level/Actor.h"
@@ -18,7 +19,6 @@ class RenderTask;
class ProbesRenderer class ProbesRenderer
{ {
public: public:
enum class EntryType enum class EntryType
{ {
Invalid = 0, Invalid = 0,
@@ -46,10 +46,10 @@ public:
bool UseTextureData() const; bool UseTextureData() const;
int32 GetResolution() const; int32 GetResolution() const;
PixelFormat GetFormat() const;
}; };
public: public:
/// <summary> /// <summary>
/// Minimum amount of time between two updated of probes /// Minimum amount of time between two updated of probes
/// </summary> /// </summary>
@@ -67,7 +67,6 @@ public:
static Delegate<const Entry&> OnFinishBake; static Delegate<const Entry&> OnFinishBake;
public: public:
/// <summary> /// <summary>
/// Checks if resources are ready to render probes (shaders or textures may be during loading). /// Checks if resources are ready to render probes (shaders or textures may be during loading).
/// </summary> /// </summary>
@@ -86,7 +85,6 @@ public:
static void Release(); static void Release();
public: public:
/// <summary> /// <summary>
/// Register probe to baking service. /// Register probe to baking service.
/// </summary> /// </summary>
@@ -102,6 +100,5 @@ public:
static void Bake(SkyLight* probe, float timeout = 0); static void Bake(SkyLight* probe, float timeout = 0);
private: private:
static void OnRender(RenderTask* task, GPUContext* context);
static void onRender(RenderTask* task, GPUContext* context);
}; };