Add Global SDF quality setting and support for variable cascades count and resolution
This commit is contained in:
@@ -64,6 +64,14 @@ namespace FlaxEditor.Windows
|
|||||||
set => Graphics.VolumetricFogQuality = value;
|
set => Graphics.VolumetricFogQuality = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[DefaultValue(Quality.High)]
|
||||||
|
[EditorOrder(1280), EditorDisplay("Quality"), Tooltip("The Global SDF quality. Controls the volume texture resolution and amount of cascades to use.")]
|
||||||
|
public Quality GlobalSDFQuality
|
||||||
|
{
|
||||||
|
get => Graphics.GlobalSDFQuality;
|
||||||
|
set => Graphics.GlobalSDFQuality = value;
|
||||||
|
}
|
||||||
|
|
||||||
[DefaultValue(Quality.Medium)]
|
[DefaultValue(Quality.Medium)]
|
||||||
[EditorOrder(1300), EditorDisplay("Quality", "Shadows Quality"), Tooltip("The shadows quality.")]
|
[EditorOrder(1300), EditorDisplay("Quality", "Shadows Quality"), Tooltip("The shadows quality.")]
|
||||||
public Quality ShadowsQuality
|
public Quality ShadowsQuality
|
||||||
|
|||||||
@@ -13,4 +13,5 @@ void GraphicsSettings::Apply()
|
|||||||
Graphics::ShadowsQuality = ShadowsQuality;
|
Graphics::ShadowsQuality = ShadowsQuality;
|
||||||
Graphics::ShadowMapsQuality = ShadowMapsQuality;
|
Graphics::ShadowMapsQuality = ShadowMapsQuality;
|
||||||
Graphics::AllowCSMBlending = AllowCSMBlending;
|
Graphics::AllowCSMBlending = AllowCSMBlending;
|
||||||
|
Graphics::GlobalSDFQuality = GlobalSDFQuality;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,12 @@ public:
|
|||||||
API_FIELD(Attributes="EditorOrder(2000), EditorDisplay(\"Global SDF\")")
|
API_FIELD(Attributes="EditorOrder(2000), EditorDisplay(\"Global SDF\")")
|
||||||
bool EnableGlobalSDF = false;
|
bool EnableGlobalSDF = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Global SDF quality. Controls the volume texture resolution and amount of cascades to use.
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD(Attributes="EditorOrder(2005), DefaultValue(Quality.High), EditorDisplay(\"Quality\")")
|
||||||
|
Quality GlobalSDFQuality = Quality::High;
|
||||||
|
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If checked, the 'Generate SDF' option will be checked on model import options by default. Use it if your project uses Global SDF (eg. for Global Illumination or particles).
|
/// If checked, the 'Generate SDF' option will be checked on model import options by default. Use it if your project uses Global SDF (eg. for Global Illumination or particles).
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ Quality Graphics::VolumetricFogQuality = Quality::High;
|
|||||||
Quality Graphics::ShadowsQuality = Quality::Medium;
|
Quality Graphics::ShadowsQuality = Quality::Medium;
|
||||||
Quality Graphics::ShadowMapsQuality = Quality::Medium;
|
Quality Graphics::ShadowMapsQuality = Quality::Medium;
|
||||||
bool Graphics::AllowCSMBlending = false;
|
bool Graphics::AllowCSMBlending = false;
|
||||||
|
Quality Graphics::GlobalSDFQuality = Quality::High;
|
||||||
|
|
||||||
#if GRAPHICS_API_NULL
|
#if GRAPHICS_API_NULL
|
||||||
extern GPUDevice* CreateGPUDeviceNull();
|
extern GPUDevice* CreateGPUDeviceNull();
|
||||||
|
|||||||
@@ -53,6 +53,11 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD() static bool AllowCSMBlending;
|
API_FIELD() static bool AllowCSMBlending;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Global SDF quality. Controls the volume texture resolution and amount of cascades to use.
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD() static Quality GlobalSDFQuality;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -488,8 +488,7 @@ void MaterialParameter::Bind(BindMeta& meta) const
|
|||||||
GlobalSignDistanceFieldPass::BindingData bindingData;
|
GlobalSignDistanceFieldPass::BindingData bindingData;
|
||||||
if (GlobalSignDistanceFieldPass::Instance()->Get(meta.Buffers, bindingData))
|
if (GlobalSignDistanceFieldPass::Instance()->Get(meta.Buffers, bindingData))
|
||||||
Platform::MemoryClear(&bindingData, sizeof(bindingData));
|
Platform::MemoryClear(&bindingData, sizeof(bindingData));
|
||||||
for (int32 i = 0; i < 4; i++)
|
bindingData.BindCascades(meta.Context, _registerIndex);
|
||||||
meta.Context->BindSR(_registerIndex + i, bindingData.Cascades[i] ? bindingData.Cascades[i]->ViewVolume() : nullptr);
|
|
||||||
*((GlobalSignDistanceFieldPass::ConstantsData*)(meta.Constants.Get() + _offset)) = bindingData.Constants;
|
*((GlobalSignDistanceFieldPass::ConstantsData*)(meta.Constants.Get() + _offset)) = bindingData.Constants;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -456,10 +456,7 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext,
|
|||||||
{
|
{
|
||||||
PROFILE_GPU_CPU("Probes Classification");
|
PROFILE_GPU_CPU("Probes Classification");
|
||||||
uint32 threadGroups = Math::DivideAndRoundUp(probesCountCascade, DDGI_PROBE_CLASSIFY_GROUP_SIZE);
|
uint32 threadGroups = Math::DivideAndRoundUp(probesCountCascade, DDGI_PROBE_CLASSIFY_GROUP_SIZE);
|
||||||
for (int32 i = 0; i < 4; i++)
|
bindingDataSDF.BindCascades(context, 0);
|
||||||
{
|
|
||||||
context->BindSR(i, bindingDataSDF.Cascades[i]->ViewVolume());
|
|
||||||
}
|
|
||||||
context->BindUA(0, ddgiData.Result.ProbesState);
|
context->BindUA(0, ddgiData.Result.ProbesState);
|
||||||
for (int32 cascadeIndex = 0; cascadeIndex < cascadesCount; cascadeIndex++)
|
for (int32 cascadeIndex = 0; cascadeIndex < cascadesCount; cascadeIndex++)
|
||||||
{
|
{
|
||||||
@@ -501,11 +498,8 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext,
|
|||||||
|
|
||||||
// Global SDF with Global Surface Atlas software raytracing (thread X - per probe ray, thread Y - per probe)
|
// Global SDF with Global Surface Atlas software raytracing (thread X - per probe ray, thread Y - per probe)
|
||||||
ASSERT_LOW_LAYER((probeRaysCount % DDGI_TRACE_RAYS_GROUP_SIZE_X) == 0);
|
ASSERT_LOW_LAYER((probeRaysCount % DDGI_TRACE_RAYS_GROUP_SIZE_X) == 0);
|
||||||
for (int32 i = 0; i < 4; i++)
|
bindingDataSDF.BindCascades(context, 0);
|
||||||
{
|
bindingDataSDF.BindCascadeMips(context, 4);
|
||||||
context->BindSR(i, bindingDataSDF.Cascades[i]->ViewVolume());
|
|
||||||
context->BindSR(i + 4, bindingDataSDF.CascadeMips[i]->ViewVolume());
|
|
||||||
}
|
|
||||||
context->BindSR(8, bindingDataSurfaceAtlas.Chunks ? bindingDataSurfaceAtlas.Chunks->View() : nullptr);
|
context->BindSR(8, bindingDataSurfaceAtlas.Chunks ? bindingDataSurfaceAtlas.Chunks->View() : nullptr);
|
||||||
context->BindSR(9, bindingDataSurfaceAtlas.CulledObjects ? bindingDataSurfaceAtlas.CulledObjects->View() : nullptr);
|
context->BindSR(9, bindingDataSurfaceAtlas.CulledObjects ? bindingDataSurfaceAtlas.CulledObjects->View() : nullptr);
|
||||||
context->BindSR(10, bindingDataSurfaceAtlas.AtlasDepth->View());
|
context->BindSR(10, bindingDataSurfaceAtlas.AtlasDepth->View());
|
||||||
|
|||||||
@@ -753,11 +753,8 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
|
|||||||
context->BindSR(2, surfaceAtlasData.AtlasGBuffer2->View());
|
context->BindSR(2, surfaceAtlasData.AtlasGBuffer2->View());
|
||||||
context->BindSR(3, surfaceAtlasData.AtlasDepth->View());
|
context->BindSR(3, surfaceAtlasData.AtlasDepth->View());
|
||||||
context->BindSR(4, _objectsBuffer->GetBuffer()->View());
|
context->BindSR(4, _objectsBuffer->GetBuffer()->View());
|
||||||
for (int32 i = 0; i < 4; i++)
|
bindingDataSDF.BindCascades(context, 5);
|
||||||
{
|
bindingDataSDF.BindCascadeMips(context, 9);
|
||||||
context->BindSR(i + 5, bindingDataSDF.Cascades[i]->ViewVolume());
|
|
||||||
context->BindSR(i + 9, bindingDataSDF.CascadeMips[i]->ViewVolume());
|
|
||||||
}
|
|
||||||
context->BindCB(0, _cb0);
|
context->BindCB(0, _cb0);
|
||||||
Data0 data;
|
Data0 data;
|
||||||
data.ViewWorldPos = renderContext.View.Position;
|
data.ViewWorldPos = renderContext.View.Position;
|
||||||
@@ -921,11 +918,8 @@ void GlobalSurfaceAtlasPass::RenderDebug(RenderContext& renderContext, GPUContex
|
|||||||
context->UpdateCB(_cb0, &data);
|
context->UpdateCB(_cb0, &data);
|
||||||
context->BindCB(0, _cb0);
|
context->BindCB(0, _cb0);
|
||||||
}
|
}
|
||||||
for (int32 i = 0; i < 4; i++)
|
bindingDataSDF.BindCascades(context, 0);
|
||||||
{
|
bindingDataSDF.BindCascadeMips(context, 4);
|
||||||
context->BindSR(i, bindingDataSDF.Cascades[i]->ViewVolume());
|
|
||||||
context->BindSR(i + 4, bindingDataSDF.CascadeMips[i]->ViewVolume());
|
|
||||||
}
|
|
||||||
context->BindSR(8, bindingData.Chunks ? bindingData.Chunks->View() : nullptr);
|
context->BindSR(8, bindingData.Chunks ? bindingData.Chunks->View() : nullptr);
|
||||||
context->BindSR(9, bindingData.CulledObjects ? bindingData.CulledObjects->View() : nullptr);
|
context->BindSR(9, bindingData.CulledObjects ? bindingData.CulledObjects->View() : nullptr);
|
||||||
context->BindSR(10, bindingData.AtlasDepth->View());
|
context->BindSR(10, bindingData.AtlasDepth->View());
|
||||||
@@ -954,11 +948,8 @@ void GlobalSurfaceAtlasPass::RenderDebug(RenderContext& renderContext, GPUContex
|
|||||||
context->ResetRenderTarget();
|
context->ResetRenderTarget();
|
||||||
|
|
||||||
// Rebind resources
|
// Rebind resources
|
||||||
for (int32 i = 0; i < 4; i++)
|
bindingDataSDF.BindCascades(context, 0);
|
||||||
{
|
bindingDataSDF.BindCascadeMips(context, 4);
|
||||||
context->BindSR(i, bindingDataSDF.Cascades[i]->ViewVolume());
|
|
||||||
context->BindSR(i + 4, bindingDataSDF.CascadeMips[i]->ViewVolume());
|
|
||||||
}
|
|
||||||
context->BindSR(8, bindingData.Chunks ? bindingData.Chunks->View() : nullptr);
|
context->BindSR(8, bindingData.Chunks ? bindingData.Chunks->View() : nullptr);
|
||||||
context->BindSR(9, bindingData.CulledObjects ? bindingData.CulledObjects->View() : nullptr);
|
context->BindSR(9, bindingData.CulledObjects ? bindingData.CulledObjects->View() : nullptr);
|
||||||
context->BindSR(10, bindingData.AtlasDepth->View());
|
context->BindSR(10, bindingData.AtlasDepth->View());
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "Engine/Engine/Engine.h"
|
#include "Engine/Engine/Engine.h"
|
||||||
#include "Engine/Content/Content.h"
|
#include "Engine/Content/Content.h"
|
||||||
#include "Engine/Graphics/GPUDevice.h"
|
#include "Engine/Graphics/GPUDevice.h"
|
||||||
|
#include "Engine/Graphics/Graphics.h"
|
||||||
#include "Engine/Graphics/RenderTask.h"
|
#include "Engine/Graphics/RenderTask.h"
|
||||||
#include "Engine/Graphics/RenderBuffers.h"
|
#include "Engine/Graphics/RenderBuffers.h"
|
||||||
#include "Engine/Graphics/RenderTargetPool.h"
|
#include "Engine/Graphics/RenderTargetPool.h"
|
||||||
@@ -173,7 +174,8 @@ struct CascadeData
|
|||||||
class GlobalSignDistanceFieldCustomBuffer : public RenderBuffers::CustomBuffer, public ISceneRenderingListener
|
class GlobalSignDistanceFieldCustomBuffer : public RenderBuffers::CustomBuffer, public ISceneRenderingListener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CascadeData Cascades[4];
|
int32 Resolution = 0;
|
||||||
|
Array<CascadeData, FixedAllocation<4>> Cascades;
|
||||||
HashSet<ScriptingTypeHandle> ObjectTypes;
|
HashSet<ScriptingTypeHandle> ObjectTypes;
|
||||||
HashSet<GPUTexture*> SDFTextures;
|
HashSet<GPUTexture*> SDFTextures;
|
||||||
GlobalSignDistanceFieldPass::BindingData Result;
|
GlobalSignDistanceFieldPass::BindingData Result;
|
||||||
@@ -349,6 +351,18 @@ void GlobalSignDistanceFieldPass::Dispose()
|
|||||||
ChunksCache.SetCapacity(0);
|
ChunksCache.SetCapacity(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GlobalSignDistanceFieldPass::BindingData::BindCascades(GPUContext* context, int32 srvSlot)
|
||||||
|
{
|
||||||
|
for (int32 i = 0; i < 4; i++)
|
||||||
|
context->BindSR(srvSlot + i, Cascades[i] ? Cascades[i]->ViewVolume() : nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalSignDistanceFieldPass::BindingData::BindCascadeMips(GPUContext* context, int32 srvSlot)
|
||||||
|
{
|
||||||
|
for (int32 i = 0; i < 4; i++)
|
||||||
|
context->BindSR(srvSlot + i, CascadeMips[i] ? CascadeMips[i]->ViewVolume() : nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
bool GlobalSignDistanceFieldPass::Get(const RenderBuffers* buffers, BindingData& result)
|
bool GlobalSignDistanceFieldPass::Get(const RenderBuffers* buffers, BindingData& result)
|
||||||
{
|
{
|
||||||
auto* sdfData = buffers ? buffers->FindCustomBuffer<GlobalSignDistanceFieldCustomBuffer>(TEXT("GlobalSignDistanceField")) : nullptr;
|
auto* sdfData = buffers ? buffers->FindCustomBuffer<GlobalSignDistanceFieldCustomBuffer>(TEXT("GlobalSignDistanceField")) : nullptr;
|
||||||
@@ -379,49 +393,71 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
|
|||||||
sdfData.LastFrameUsed = currentFrame;
|
sdfData.LastFrameUsed = currentFrame;
|
||||||
PROFILE_GPU_CPU("Global SDF");
|
PROFILE_GPU_CPU("Global SDF");
|
||||||
|
|
||||||
// TODO: configurable via graphics settings
|
// Setup options
|
||||||
const int32 resolution = 256;
|
int32 resolution, cascadesCount;
|
||||||
|
switch (Graphics::GlobalSDFQuality)
|
||||||
|
{
|
||||||
|
case Quality::Low:
|
||||||
|
resolution = 128;
|
||||||
|
cascadesCount = 2;
|
||||||
|
break;
|
||||||
|
case Quality::Medium:
|
||||||
|
resolution = 128;
|
||||||
|
cascadesCount = 3;
|
||||||
|
break;
|
||||||
|
case Quality::High:
|
||||||
|
resolution = 192;
|
||||||
|
cascadesCount = 4;
|
||||||
|
break;
|
||||||
|
case Quality::Ultra:
|
||||||
|
default:
|
||||||
|
resolution = 256;
|
||||||
|
cascadesCount = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
const int32 resolutionMip = Math::DivideAndRoundUp(resolution, GLOBAL_SDF_RASTERIZE_MIP_FACTOR);
|
const int32 resolutionMip = Math::DivideAndRoundUp(resolution, GLOBAL_SDF_RASTERIZE_MIP_FACTOR);
|
||||||
// TODO: configurable via postFx settings
|
|
||||||
const int32 cascadesCount = 4; // in range 1-4
|
|
||||||
const float distance = true ? 20000.0f : 16000.0f; // TODO: switch based if using GI, then use GI range
|
const float distance = true ? 20000.0f : 16000.0f; // TODO: switch based if using GI, then use GI range
|
||||||
const float cascadesDistanceScales[] = { 1.0f, 2.0f, 4.0f, 8.0f };
|
const float cascadesDistanceScales[] = { 1.0f, 2.5f, 5.0f, 10.0f };
|
||||||
const float distanceExtent = distance / cascadesDistanceScales[cascadesCount - 1];
|
const float distanceExtent = distance / cascadesDistanceScales[cascadesCount - 1];
|
||||||
|
|
||||||
// Initialize buffers
|
// Initialize buffers
|
||||||
auto desc = GPUTextureDescription::New3D(resolution, resolution, resolution, GLOBAL_SDF_FORMAT, GPUTextureFlags::ShaderResource | GPUTextureFlags::UnorderedAccess, 1);
|
|
||||||
bool updated = false;
|
bool updated = false;
|
||||||
for (auto& cascade : sdfData.Cascades)
|
if (sdfData.Cascades.Count() != cascadesCount || sdfData.Resolution != resolution)
|
||||||
{
|
{
|
||||||
GPUTexture*& texture = cascade.Texture;
|
sdfData.Cascades.Resize(cascadesCount);
|
||||||
if (texture && texture->Width() != desc.Width)
|
sdfData.Resolution = resolution;
|
||||||
|
updated = true;
|
||||||
|
auto desc = GPUTextureDescription::New3D(resolution, resolution, resolution, GLOBAL_SDF_FORMAT, GPUTextureFlags::ShaderResource | GPUTextureFlags::UnorderedAccess, 1);
|
||||||
|
for (auto& cascade : sdfData.Cascades)
|
||||||
{
|
{
|
||||||
RenderTargetPool::Release(texture);
|
GPUTexture*& texture = cascade.Texture;
|
||||||
texture = nullptr;
|
if (texture && texture->Width() != desc.Width)
|
||||||
}
|
{
|
||||||
if (!texture)
|
RenderTargetPool::Release(texture);
|
||||||
{
|
texture = nullptr;
|
||||||
texture = RenderTargetPool::Get(desc);
|
}
|
||||||
if (!texture)
|
if (!texture)
|
||||||
return true;
|
{
|
||||||
updated = true;
|
texture = RenderTargetPool::Get(desc);
|
||||||
|
if (!texture)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
desc.Width = desc.Height = desc.Depth = resolutionMip;
|
||||||
desc = GPUTextureDescription::New3D(resolutionMip, resolutionMip, resolutionMip, GLOBAL_SDF_FORMAT, GPUTextureFlags::ShaderResource | GPUTextureFlags::UnorderedAccess, 1);
|
for (auto& cascade : sdfData.Cascades)
|
||||||
for (auto& cascade : sdfData.Cascades)
|
|
||||||
{
|
|
||||||
GPUTexture*& texture = cascade.Mip;
|
|
||||||
if (texture && texture->Width() != desc.Width)
|
|
||||||
{
|
{
|
||||||
RenderTargetPool::Release(texture);
|
GPUTexture*& texture = cascade.Mip;
|
||||||
texture = nullptr;
|
if (texture && texture->Width() != desc.Width)
|
||||||
}
|
{
|
||||||
if (!texture)
|
RenderTargetPool::Release(texture);
|
||||||
{
|
texture = nullptr;
|
||||||
texture = RenderTargetPool::Get(desc);
|
}
|
||||||
if (!texture)
|
if (!texture)
|
||||||
return true;
|
{
|
||||||
updated = true;
|
texture = RenderTargetPool::Get(desc);
|
||||||
|
if (!texture)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GPUTexture* tmpMip = nullptr;
|
GPUTexture* tmpMip = nullptr;
|
||||||
@@ -451,7 +487,7 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
|
|||||||
bool anyDraw = false;
|
bool anyDraw = false;
|
||||||
const uint64 cascadeFrequencies[] = { 2, 3, 5, 11 };
|
const uint64 cascadeFrequencies[] = { 2, 3, 5, 11 };
|
||||||
//const uint64 cascadeFrequencies[] = { 1, 1, 1, 1 };
|
//const uint64 cascadeFrequencies[] = { 1, 1, 1, 1 };
|
||||||
for (int32 cascadeIndex = 0; cascadeIndex < 4; cascadeIndex++)
|
for (int32 cascadeIndex = 0; cascadeIndex < cascadesCount; cascadeIndex++)
|
||||||
{
|
{
|
||||||
// Reduce frequency of the updates
|
// Reduce frequency of the updates
|
||||||
if (useCache && (Engine::FrameCount % cascadeFrequencies[cascadeIndex]) != 0)
|
if (useCache && (Engine::FrameCount % cascadeFrequencies[cascadeIndex]) != 0)
|
||||||
@@ -513,12 +549,13 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
|
|||||||
{
|
{
|
||||||
anyDraw = true;
|
anyDraw = true;
|
||||||
context->ResetSR();
|
context->ResetSR();
|
||||||
|
auto desc = GPUTextureDescription::New3D(resolution, resolution, resolution, GLOBAL_SDF_FORMAT, GPUTextureFlags::ShaderResource | GPUTextureFlags::UnorderedAccess, 1);
|
||||||
tmpMip = RenderTargetPool::Get(desc);
|
tmpMip = RenderTargetPool::Get(desc);
|
||||||
if (!tmpMip)
|
if (!tmpMip)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
ModelsRasterizeData data;
|
ModelsRasterizeData data;
|
||||||
data.CascadeCoordToPosMul = cascadeBounds.GetSize() / resolution;
|
data.CascadeCoordToPosMul = cascadeBounds.GetSize() / (float)resolution;
|
||||||
data.CascadeCoordToPosAdd = cascadeBounds.Minimum + cascadeVoxelSize * 0.5f;
|
data.CascadeCoordToPosAdd = cascadeBounds.Minimum + cascadeVoxelSize * 0.5f;
|
||||||
data.MaxDistance = cascadeMaxDistance;
|
data.MaxDistance = cascadeMaxDistance;
|
||||||
data.CascadeResolution = resolution;
|
data.CascadeResolution = resolution;
|
||||||
@@ -725,8 +762,7 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
|
|||||||
// Copy results
|
// Copy results
|
||||||
static_assert(ARRAY_COUNT(result.Cascades) == ARRAY_COUNT(sdfData.Cascades), "Invalid cascades count.");
|
static_assert(ARRAY_COUNT(result.Cascades) == ARRAY_COUNT(sdfData.Cascades), "Invalid cascades count.");
|
||||||
static_assert(ARRAY_COUNT(result.CascadeMips) == ARRAY_COUNT(sdfData.Cascades), "Invalid cascades count.");
|
static_assert(ARRAY_COUNT(result.CascadeMips) == ARRAY_COUNT(sdfData.Cascades), "Invalid cascades count.");
|
||||||
static_assert(ARRAY_COUNT(sdfData.Cascades) == 4, "Invalid cascades count.");
|
for (int32 cascadeIndex = 0; cascadeIndex < cascadesCount; cascadeIndex++)
|
||||||
for (int32 cascadeIndex = 0; cascadeIndex < 4; cascadeIndex++)
|
|
||||||
{
|
{
|
||||||
auto& cascade = sdfData.Cascades[cascadeIndex];
|
auto& cascade = sdfData.Cascades[cascadeIndex];
|
||||||
const float cascadeDistance = distanceExtent * cascadesDistanceScales[cascadeIndex];
|
const float cascadeDistance = distanceExtent * cascadesDistanceScales[cascadeIndex];
|
||||||
@@ -738,7 +774,15 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
|
|||||||
result.Cascades[cascadeIndex] = cascade.Texture;
|
result.Cascades[cascadeIndex] = cascade.Texture;
|
||||||
result.CascadeMips[cascadeIndex] = cascade.Mip;
|
result.CascadeMips[cascadeIndex] = cascade.Mip;
|
||||||
}
|
}
|
||||||
|
for (int32 cascadeIndex = cascadesCount; cascadeIndex < 4; cascadeIndex++)
|
||||||
|
{
|
||||||
|
result.Constants.CascadePosDistance[cascadeIndex] = result.Constants.CascadePosDistance[cascadesCount - 1];
|
||||||
|
result.Constants.CascadeVoxelSize.Raw[cascadeIndex] = result.Constants.CascadeVoxelSize.Raw[cascadesCount - 1];
|
||||||
|
result.Cascades[cascadeIndex] = nullptr;
|
||||||
|
result.CascadeMips[cascadeIndex] = nullptr;
|
||||||
|
}
|
||||||
result.Constants.Resolution = (float)resolution;
|
result.Constants.Resolution = (float)resolution;
|
||||||
|
result.Constants.CascadesCount = cascadesCount;
|
||||||
sdfData.Result = result;
|
sdfData.Result = result;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -765,11 +809,8 @@ void GlobalSignDistanceFieldPass::RenderDebug(RenderContext& renderContext, GPUC
|
|||||||
context->UpdateCB(_cb0, &data);
|
context->UpdateCB(_cb0, &data);
|
||||||
context->BindCB(0, _cb0);
|
context->BindCB(0, _cb0);
|
||||||
}
|
}
|
||||||
for (int32 i = 0; i < 4; i++)
|
bindingData.BindCascades(context, 0);
|
||||||
{
|
bindingData.BindCascadeMips(context, 4);
|
||||||
context->BindSR(i, bindingData.Cascades[i]->ViewVolume());
|
|
||||||
context->BindSR(i + 4, bindingData.CascadeMips[i]->ViewVolume());
|
|
||||||
}
|
|
||||||
context->SetState(_psDebug);
|
context->SetState(_psDebug);
|
||||||
context->SetRenderTarget(output->View());
|
context->SetRenderTarget(output->View());
|
||||||
context->SetViewportAndScissors(outputSize.X, outputSize.Y);
|
context->SetViewportAndScissors(outputSize.X, outputSize.Y);
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ public:
|
|||||||
{
|
{
|
||||||
Vector4 CascadePosDistance[4];
|
Vector4 CascadePosDistance[4];
|
||||||
Vector4 CascadeVoxelSize;
|
Vector4 CascadeVoxelSize;
|
||||||
Vector3 Padding;
|
Vector2 Padding;
|
||||||
|
uint32 CascadesCount;
|
||||||
float Resolution;
|
float Resolution;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -25,6 +26,9 @@ public:
|
|||||||
GPUTexture* Cascades[4];
|
GPUTexture* Cascades[4];
|
||||||
GPUTexture* CascadeMips[4];
|
GPUTexture* CascadeMips[4];
|
||||||
ConstantsData Constants;
|
ConstantsData Constants;
|
||||||
|
|
||||||
|
void BindCascades(GPUContext* context, int32 srvSlot);
|
||||||
|
void BindCascadeMips(GPUContext* context, int32 srvSlot);
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ void CS_TraceRays(uint3 DispatchThreadId : SV_DispatchThreadID)
|
|||||||
{
|
{
|
||||||
// Sample Global Surface Atlas to get the lighting at the hit location
|
// Sample Global Surface Atlas to get the lighting at the hit location
|
||||||
float3 hitPosition = hit.GetHitPosition(trace);
|
float3 hitPosition = hit.GetHitPosition(trace);
|
||||||
float surfaceThreshold = GetGlobalSurfaceAtlasThreshold(hit);
|
float surfaceThreshold = GetGlobalSurfaceAtlasThreshold(GlobalSDF, hit);
|
||||||
float4 surfaceColor = SampleGlobalSurfaceAtlas(GlobalSurfaceAtlas, GlobalSurfaceAtlasChunks, GlobalSurfaceAtlasCulledObjects, GlobalSurfaceAtlasDepth, GlobalSurfaceAtlasTex, hitPosition, -probeRayDirection, surfaceThreshold);
|
float4 surfaceColor = SampleGlobalSurfaceAtlas(GlobalSurfaceAtlas, GlobalSurfaceAtlasChunks, GlobalSurfaceAtlasCulledObjects, GlobalSurfaceAtlasDepth, GlobalSurfaceAtlasTex, hitPosition, -probeRayDirection, surfaceThreshold);
|
||||||
radiance = float4(surfaceColor.rgb, hit.HitTime);
|
radiance = float4(surfaceColor.rgb, hit.HitTime);
|
||||||
|
|
||||||
|
|||||||
@@ -293,7 +293,7 @@ float4 PS_Debug(Quad_VS2PS input) : SV_Target
|
|||||||
if (hit.IsHit())
|
if (hit.IsHit())
|
||||||
{
|
{
|
||||||
// Sample Global Surface Atlas at the hit location
|
// Sample Global Surface Atlas at the hit location
|
||||||
float surfaceThreshold = GetGlobalSurfaceAtlasThreshold(hit);
|
float surfaceThreshold = GetGlobalSurfaceAtlasThreshold(GlobalSDF, hit);
|
||||||
color = SampleGlobalSurfaceAtlas(GlobalSurfaceAtlas, GlobalSurfaceAtlasChunks, GlobalSurfaceAtlasCulledObjects, GlobalSurfaceAtlasDepth, GlobalSurfaceAtlasTex, hit.GetHitPosition(trace), -viewRay, surfaceThreshold).rgb;
|
color = SampleGlobalSurfaceAtlas(GlobalSurfaceAtlas, GlobalSurfaceAtlasChunks, GlobalSurfaceAtlasCulledObjects, GlobalSurfaceAtlasDepth, GlobalSurfaceAtlasTex, hit.GetHitPosition(trace), -viewRay, surfaceThreshold).rgb;
|
||||||
//color = hit.HitNormal * 0.5f + 0.5f;
|
//color = hit.HitNormal * 0.5f + 0.5f;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ struct GlobalSDFData
|
|||||||
{
|
{
|
||||||
float4 CascadePosDistance[4];
|
float4 CascadePosDistance[4];
|
||||||
float4 CascadeVoxelSize;
|
float4 CascadeVoxelSize;
|
||||||
float3 Padding;
|
float2 Padding;
|
||||||
|
uint CascadesCount;
|
||||||
float Resolution;
|
float Resolution;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -65,7 +66,7 @@ float SampleGlobalSDF(const GlobalSDFData data, Texture3D<float> tex[4], float3
|
|||||||
if (distance <= 0.0f)
|
if (distance <= 0.0f)
|
||||||
return GLOBAL_SDF_WORLD_SIZE;
|
return GLOBAL_SDF_WORLD_SIZE;
|
||||||
UNROLL
|
UNROLL
|
||||||
for (uint cascade = 0; cascade < 4; cascade++)
|
for (uint cascade = 0; cascade < data.CascadesCount; cascade++)
|
||||||
{
|
{
|
||||||
float4 cascadePosDistance = data.CascadePosDistance[cascade];
|
float4 cascadePosDistance = data.CascadePosDistance[cascade];
|
||||||
float cascadeMaxDistance = cascadePosDistance.w * 2;
|
float cascadeMaxDistance = cascadePosDistance.w * 2;
|
||||||
@@ -89,7 +90,7 @@ float3 SampleGlobalSDFGradient(const GlobalSDFData data, Texture3D<float> tex[4]
|
|||||||
if (data.CascadePosDistance[3].w <= 0.0f)
|
if (data.CascadePosDistance[3].w <= 0.0f)
|
||||||
return gradient;
|
return gradient;
|
||||||
UNROLL
|
UNROLL
|
||||||
for (uint cascade = 0; cascade < 4; cascade++)
|
for (uint cascade = 0; cascade < data.CascadesCount; cascade++)
|
||||||
{
|
{
|
||||||
float4 cascadePosDistance = data.CascadePosDistance[cascade];
|
float4 cascadePosDistance = data.CascadePosDistance[cascade];
|
||||||
float cascadeMaxDistance = cascadePosDistance.w * 2;
|
float cascadeMaxDistance = cascadePosDistance.w * 2;
|
||||||
@@ -124,7 +125,7 @@ GlobalSDFHit RayTraceGlobalSDF(const GlobalSDFData data, Texture3D<float> tex[4]
|
|||||||
float traceMaxDistance = min(trace.MaxDistance, data.CascadePosDistance[3].w * 2);
|
float traceMaxDistance = min(trace.MaxDistance, data.CascadePosDistance[3].w * 2);
|
||||||
float3 traceEndPosition = trace.WorldPosition + trace.WorldDirection * traceMaxDistance;
|
float3 traceEndPosition = trace.WorldPosition + trace.WorldDirection * traceMaxDistance;
|
||||||
UNROLL
|
UNROLL
|
||||||
for (uint cascade = 0; cascade < 4 && hit.HitTime < 0.0f; cascade++)
|
for (uint cascade = 0; cascade < data.CascadesCount && hit.HitTime < 0.0f; cascade++)
|
||||||
{
|
{
|
||||||
float4 cascadePosDistance = data.CascadePosDistance[cascade];
|
float4 cascadePosDistance = data.CascadePosDistance[cascade];
|
||||||
float cascadeMaxDistance = cascadePosDistance.w * 2;
|
float cascadeMaxDistance = cascadePosDistance.w * 2;
|
||||||
@@ -206,8 +207,8 @@ GlobalSDFHit RayTraceGlobalSDF(const GlobalSDFData data, Texture3D<float> tex[4]
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calculates the surface threshold for Global Surface Atlas sampling which matches the Global SDF trace to reduce artifacts
|
// Calculates the surface threshold for Global Surface Atlas sampling which matches the Global SDF trace to reduce artifacts
|
||||||
float GetGlobalSurfaceAtlasThreshold(GlobalSDFHit hit)
|
float GetGlobalSurfaceAtlasThreshold(const GlobalSDFData data, const GlobalSDFHit hit)
|
||||||
{
|
{
|
||||||
// Scale the threshold based on the hit cascade (less precision)
|
// Scale the threshold based on the hit cascade (less precision)
|
||||||
return hit.HitCascade * 20.0f + 25.0f;
|
return data.CascadeVoxelSize[hit.HitCascade] * 1.1f;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user