Refactor Global SDF to use a single texture for all cascades

This commit is contained in:
Wojciech Figat
2022-06-17 10:41:04 +02:00
parent bc8cc75ad8
commit 2e06d1ce2a
14 changed files with 204 additions and 194 deletions

BIN
Content/Shaders/GI/DDGI.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/GI/GlobalSurfaceAtlas.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

BIN
Content/Shaders/VolumetricFog.flax (Stored with Git LFS)

Binary file not shown.

View File

@@ -502,7 +502,7 @@ void MaterialParameter::Bind(BindMeta& meta) const
GlobalSignDistanceFieldPass::BindingData bindingData;
if (GlobalSignDistanceFieldPass::Instance()->Get(meta.Buffers, bindingData))
Platform::MemoryClear(&bindingData, sizeof(bindingData));
bindingData.BindCascades(meta.Context, _registerIndex);
meta.Context->BindSR(_registerIndex, bindingData.Texture ? bindingData.Texture->ViewVolume() : nullptr);
*((GlobalSignDistanceFieldPass::ConstantsData*)(meta.Constants.Get() + _offset)) = bindingData.Constants;
break;
}

View File

@@ -486,8 +486,8 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext,
{
PROFILE_GPU_CPU("Probes Classification");
uint32 threadGroups = Math::DivideAndRoundUp(probesCountCascade, DDGI_PROBE_CLASSIFY_GROUP_SIZE);
bindingDataSDF.BindCascades(context, 0);
bindingDataSDF.BindCascadeMips(context, 4);
context->BindSR(0, bindingDataSDF.Texture ? bindingDataSDF.Texture->ViewVolume() : nullptr);
context->BindSR(1, bindingDataSDF.TextureMip ? bindingDataSDF.TextureMip->ViewVolume() : nullptr);
context->BindUA(0, ddgiData.Result.ProbesState);
for (int32 cascadeIndex = 0; cascadeIndex < cascadesCount; cascadeIndex++)
{
@@ -529,14 +529,14 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext,
// 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);
bindingDataSDF.BindCascades(context, 0);
bindingDataSDF.BindCascadeMips(context, 4);
context->BindSR(8, bindingDataSurfaceAtlas.Chunks ? bindingDataSurfaceAtlas.Chunks->View() : nullptr);
context->BindSR(9, bindingDataSurfaceAtlas.CulledObjects ? bindingDataSurfaceAtlas.CulledObjects->View() : nullptr);
context->BindSR(10, bindingDataSurfaceAtlas.AtlasDepth->View());
context->BindSR(11, bindingDataSurfaceAtlas.AtlasLighting->View());
context->BindSR(12, ddgiData.Result.ProbesState);
context->BindSR(13, skybox);
context->BindSR(0, bindingDataSDF.Texture ? bindingDataSDF.Texture->ViewVolume() : nullptr);
context->BindSR(1, bindingDataSDF.TextureMip ? bindingDataSDF.TextureMip->ViewVolume() : nullptr);
context->BindSR(2, bindingDataSurfaceAtlas.Chunks ? bindingDataSurfaceAtlas.Chunks->View() : nullptr);
context->BindSR(3, bindingDataSurfaceAtlas.CulledObjects ? bindingDataSurfaceAtlas.CulledObjects->View() : nullptr);
context->BindSR(4, bindingDataSurfaceAtlas.AtlasDepth->View());
context->BindSR(5, bindingDataSurfaceAtlas.AtlasLighting->View());
context->BindSR(6, ddgiData.Result.ProbesState);
context->BindSR(7, skybox);
context->BindUA(0, ddgiData.ProbesTrace->View());
context->Dispatch(_csTraceRays, probeRaysCount / DDGI_TRACE_RAYS_GROUP_SIZE_X, probesBatchSize, 1);
context->ResetUA();

View File

@@ -754,8 +754,8 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
context->BindSR(2, surfaceAtlasData.AtlasGBuffer2->View());
context->BindSR(3, surfaceAtlasData.AtlasDepth->View());
context->BindSR(4, _objectsBuffer->GetBuffer()->View());
bindingDataSDF.BindCascades(context, 5);
bindingDataSDF.BindCascadeMips(context, 9);
context->BindSR(5, bindingDataSDF.Texture ? bindingDataSDF.Texture->ViewVolume() : nullptr);
context->BindSR(6, bindingDataSDF.TextureMip ? bindingDataSDF.TextureMip->ViewVolume() : nullptr);
context->BindCB(0, _cb0);
Data0 data;
data.ViewWorldPos = renderContext.View.Position;
@@ -927,12 +927,12 @@ void GlobalSurfaceAtlasPass::RenderDebug(RenderContext& renderContext, GPUContex
context->UpdateCB(_cb0, &data);
context->BindCB(0, _cb0);
}
bindingDataSDF.BindCascades(context, 0);
bindingDataSDF.BindCascadeMips(context, 4);
context->BindSR(8, bindingData.Chunks ? bindingData.Chunks->View() : nullptr);
context->BindSR(9, bindingData.CulledObjects ? bindingData.CulledObjects->View() : nullptr);
context->BindSR(10, bindingData.AtlasDepth->View());
context->BindSR(12, skybox);
context->BindSR(0, bindingDataSDF.Texture ? bindingDataSDF.Texture->ViewVolume() : nullptr);
context->BindSR(1, bindingDataSDF.TextureMip ? bindingDataSDF.TextureMip->ViewVolume() : nullptr);
context->BindSR(2, bindingData.Chunks ? bindingData.Chunks->View() : nullptr);
context->BindSR(3, bindingData.CulledObjects ? bindingData.CulledObjects->View() : nullptr);
context->BindSR(4, bindingData.AtlasDepth->View());
context->BindSR(6, skybox);
context->SetState(_psDebug);
{
Float2 outputSizeThird = outputSize * 0.333f;
@@ -943,7 +943,7 @@ void GlobalSurfaceAtlasPass::RenderDebug(RenderContext& renderContext, GPUContex
context->SetRenderTarget(tempBuffer->View());
// Full screen - direct light
context->BindSR(11, bindingData.AtlasLighting->View());
context->BindSR(5, bindingData.AtlasLighting->View());
context->SetViewport(outputSize.X, outputSize.Y);
context->SetScissor(Rectangle(0, 0, outputSizeTwoThird.X, outputSize.Y));
context->DrawFullscreenTriangle();
@@ -957,12 +957,12 @@ void GlobalSurfaceAtlasPass::RenderDebug(RenderContext& renderContext, GPUContex
context->ResetRenderTarget();
// Rebind resources
bindingDataSDF.BindCascades(context, 0);
bindingDataSDF.BindCascadeMips(context, 4);
context->BindSR(8, bindingData.Chunks ? bindingData.Chunks->View() : nullptr);
context->BindSR(9, bindingData.CulledObjects ? bindingData.CulledObjects->View() : nullptr);
context->BindSR(10, bindingData.AtlasDepth->View());
context->BindSR(12, skybox);
context->BindSR(0, bindingDataSDF.Texture ? bindingDataSDF.Texture->ViewVolume() : nullptr);
context->BindSR(1, bindingDataSDF.TextureMip ? bindingDataSDF.TextureMip->ViewVolume() : nullptr);
context->BindSR(2, bindingData.Chunks ? bindingData.Chunks->View() : nullptr);
context->BindSR(3, bindingData.CulledObjects ? bindingData.CulledObjects->View() : nullptr);
context->BindSR(4, bindingData.AtlasDepth->View());
context->BindSR(6, skybox);
context->BindCB(0, _cb0);
context->SetState(_psDebug);
context->SetRenderTarget(output->View());
@@ -972,17 +972,17 @@ void GlobalSurfaceAtlasPass::RenderDebug(RenderContext& renderContext, GPUContex
context->UpdateCB(_cb0, &data);
// Bottom left - diffuse
context->BindSR(11, bindingData.AtlasGBuffer0->View());
context->BindSR(5, bindingData.AtlasGBuffer0->View());
context->SetViewportAndScissors(Viewport(outputSizeTwoThird.X, 0, outputSizeThird.X, outputSizeThird.Y));
context->DrawFullscreenTriangle();
// Bottom middle - normals
context->BindSR(11, bindingData.AtlasGBuffer1->View());
context->BindSR(5, bindingData.AtlasGBuffer1->View());
context->SetViewportAndScissors(Viewport(outputSizeTwoThird.X, outputSizeThird.Y, outputSizeThird.X, outputSizeThird.Y));
context->DrawFullscreenTriangle();
// Bottom right - roughness/metalness/ao
context->BindSR(11, bindingData.AtlasGBuffer2->View());
context->BindSR(5, bindingData.AtlasGBuffer2->View());
context->SetViewportAndScissors(Viewport(outputSizeTwoThird.X, outputSizeTwoThird.Y, outputSizeThird.X, outputSizeThird.Y));
context->DrawFullscreenTriangle();
}

View File

@@ -61,14 +61,18 @@ PACK_STRUCT(struct ModelsRasterizeData
Int3 ChunkCoord;
float MaxDistance;
Float3 CascadeCoordToPosMul;
int ObjectsCount;
int32 ObjectsCount;
Float3 CascadeCoordToPosAdd;
int32 CascadeResolution;
float Padding0;
int32 CascadeIndex;
float CascadeVoxelSize;
int32 CascadeMipResolution;
int32 CascadeMipFactor;
uint32 Objects[GLOBAL_SDF_RASTERIZE_MODEL_MAX_COUNT];
uint32 GenerateMipTexResolution;
uint32 GenerateMipCoordScale;
uint32 GenerateMipTexOffsetX;
uint32 GenerateMipMipOffsetX;
});
struct RasterizeModel
@@ -125,8 +129,6 @@ uint32 GetHash(const RasterizeChunkKey& key)
struct CascadeData
{
GPUTexture* Texture = nullptr;
GPUTexture* Mip = nullptr;
Vector3 Position;
float VoxelSize;
BoundingBox Bounds;
@@ -163,18 +165,14 @@ struct CascadeData
}
}
}
~CascadeData()
{
RenderTargetPool::Release(Texture);
RenderTargetPool::Release(Mip);
}
};
class GlobalSignDistanceFieldCustomBuffer : public RenderBuffers::CustomBuffer, public ISceneRenderingListener
{
public:
int32 Resolution = 0;
GPUTexture* Texture = nullptr;
GPUTexture* TextureMip = nullptr;
Array<CascadeData, FixedAllocation<4>> Cascades;
HashSet<ScriptingTypeHandle> ObjectTypes;
HashSet<GPUTexture*> SDFTextures;
@@ -187,6 +185,8 @@ public:
e.Item->Deleted.Unbind<GlobalSignDistanceFieldCustomBuffer, &GlobalSignDistanceFieldCustomBuffer::OnSDFTextureDeleted>(this);
e.Item->ResidentMipsChanged.Unbind<GlobalSignDistanceFieldCustomBuffer, &GlobalSignDistanceFieldCustomBuffer::OnSDFTextureResidentMipsChanged>(this);
}
RenderTargetPool::Release(Texture);
RenderTargetPool::Release(TextureMip);
}
void OnSDFTextureDeleted(ScriptingObject* object)
@@ -300,8 +300,7 @@ bool GlobalSignDistanceFieldPass::setupResources()
_csRasterizeModel1 = shader->GetCS("CS_RasterizeModel", 1);
_csRasterizeHeightfield = shader->GetCS("CS_RasterizeHeightfield");
_csClearChunk = shader->GetCS("CS_ClearChunk");
_csGenerateMip0 = shader->GetCS("CS_GenerateMip", 0);
_csGenerateMip1 = shader->GetCS("CS_GenerateMip", 1);
_csGenerateMip = shader->GetCS("CS_GenerateMip");
// Init buffer
if (!_objectsBuffer)
@@ -329,8 +328,7 @@ void GlobalSignDistanceFieldPass::OnShaderReloading(Asset* obj)
_csRasterizeModel1 = nullptr;
_csRasterizeHeightfield = nullptr;
_csClearChunk = nullptr;
_csGenerateMip0 = nullptr;
_csGenerateMip1 = nullptr;
_csGenerateMip = nullptr;
_cb0 = nullptr;
_cb1 = nullptr;
invalidateResources();
@@ -351,18 +349,6 @@ void GlobalSignDistanceFieldPass::Dispose()
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)
{
auto* sdfData = buffers ? buffers->FindCustomBuffer<GlobalSignDistanceFieldCustomBuffer>(TEXT("GlobalSignDistanceField")) : nullptr;
@@ -428,14 +414,13 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
sdfData.Cascades.Resize(cascadesCount);
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)
auto desc = GPUTextureDescription::New3D(resolution * cascadesCount, resolution, resolution, GLOBAL_SDF_FORMAT, GPUTextureFlags::ShaderResource | GPUTextureFlags::UnorderedAccess, 1);
{
GPUTexture*& texture = cascade.Texture;
GPUTexture*& texture = sdfData.Texture;
if (texture && texture->Width() != desc.Width)
{
RenderTargetPool::Release(texture);
texture = nullptr;
sdfData.Texture = nullptr;
}
if (!texture)
{
@@ -444,10 +429,11 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
return true;
}
}
desc.Width = desc.Height = desc.Depth = resolutionMip;
desc.Width = resolutionMip * cascadesCount;
desc.Height = desc.Depth = resolutionMip;
for (auto& cascade : sdfData.Cascades)
{
GPUTexture*& texture = cascade.Mip;
GPUTexture*& texture = sdfData.TextureMip;
if (texture && texture->Width() != desc.Width)
{
RenderTargetPool::Release(texture);
@@ -469,10 +455,12 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
{
cascade.NonEmptyChunks.Clear();
cascade.StaticChunks.Clear();
context->ClearUA(cascade.Texture, Float4::One);
context->ClearUA(cascade.Mip, Float4::One);
}
LOG(Info, "Global SDF memory usage: {0} MB", (sdfData.Cascades[0].Texture->GetMemoryUsage() + sdfData.Cascades[0].Mip->GetMemoryUsage()) * ARRAY_COUNT(sdfData.Cascades) / 1024 / 1024);
uint64 memoryUsage = sdfData.Texture->GetMemoryUsage();
context->ClearUA(sdfData.Texture, Float4::One);
memoryUsage += sdfData.TextureMip->GetMemoryUsage();
context->ClearUA(sdfData.TextureMip, Float4::One);
LOG(Info, "Global SDF memory usage: {0} MB", memoryUsage / 1024 / 1024);
}
for (SceneRendering* scene : renderContext.List->Scenes)
sdfData.ListenSceneRendering(scene);
@@ -498,6 +486,8 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
bool anyDraw = false;
const uint64 cascadeFrequencies[] = { 2, 3, 5, 11 };
//const uint64 cascadeFrequencies[] = { 1, 1, 1, 1 };
GPUTextureView* textureView = sdfData.Texture->ViewVolume();
GPUTextureView* textureMipView = sdfData.TextureMip->ViewVolume();
for (int32 cascadeIndex = 0; cascadeIndex < cascadesCount; cascadeIndex++)
{
// Reduce frequency of the updates
@@ -514,8 +504,6 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
BoundingBox cascadeBounds(center - cascadeDistance, center + cascadeDistance);
// TODO: add scene detail scale factor to PostFx settings (eg. to increase or decrease scene details and quality)
const float minObjectRadius = Math::Max(20.0f, cascadeVoxelSize * 0.5f); // Skip too small objects for this cascade
GPUTextureView* cascadeView = cascade.Texture->ViewVolume();
GPUTextureView* cascadeMipView = cascade.Mip->ViewVolume();
// Clear cascade before rasterization
{
@@ -539,6 +527,8 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
_objectsBufferCount = 0;
_voxelSize = cascadeVoxelSize;
_cascadeBounds = cascadeBounds;
_cascadeBounds.Minimum += 0.1f; // Adjust to prevent overflowing chunk keys (cascade bounds are used for clamping object bounds)
_cascadeBounds.Maximum -= 0.1f; // Adjust to prevent overflowing chunk keys (cascade bounds are used for clamping object bounds)
_cascadeIndex = cascadeIndex;
_sdfData = &sdfData;
{
@@ -560,10 +550,6 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
{
anyDraw = true;
context->ResetSR();
auto desc = GPUTextureDescription::New3D(resolution, resolution, resolution, GLOBAL_SDF_FORMAT, GPUTextureFlags::ShaderResource | GPUTextureFlags::UnorderedAccess, 1);
tmpMip = RenderTargetPool::Get(desc);
if (!tmpMip)
return true;
}
ModelsRasterizeData data;
data.CascadeCoordToPosMul = (Float3)cascadeBounds.GetSize() / (float)resolution;
@@ -571,9 +557,10 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
data.MaxDistance = cascadeMaxDistance;
data.CascadeResolution = resolution;
data.CascadeMipResolution = resolutionMip;
data.CascadeIndex = cascadeIndex;
data.CascadeMipFactor = GLOBAL_SDF_RASTERIZE_MIP_FACTOR;
data.CascadeVoxelSize = cascadeVoxelSize;
context->BindUA(0, cascadeView);
context->BindUA(0, textureView);
context->BindCB(1, _cb1);
const int32 chunkDispatchGroups = GLOBAL_SDF_RASTERIZE_CHUNK_SIZE / GLOBAL_SDF_RASTERIZE_GROUP_SIZE;
bool anyChunkDispatch = false;
@@ -738,25 +725,55 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
if (updated || anyChunkDispatch)
{
PROFILE_GPU_CPU("Generate Mip");
context->UpdateCB(_cb1, &data);
context->ResetUA();
context->BindSR(0, cascadeView);
context->BindUA(0, cascadeMipView);
const int32 mipDispatchGroups = Math::DivideAndRoundUp(resolutionMip, GLOBAL_SDF_MIP_GROUP_SIZE);
static_assert((GLOBAL_SDF_MIP_FLOODS % 2) == 1, "Invalid Global SDF mip flood iterations count.");
int32 floodFillIterations = chunks.Count() == 0 ? 1 : GLOBAL_SDF_MIP_FLOODS;
context->Dispatch(_csGenerateMip0, mipDispatchGroups, mipDispatchGroups, mipDispatchGroups);
context->UnBindSR(0);
if (!tmpMip)
{
// Use temporary texture to flood fill mip
auto desc = GPUTextureDescription::New3D(resolutionMip, resolutionMip, resolutionMip, GLOBAL_SDF_FORMAT, GPUTextureFlags::ShaderResource | GPUTextureFlags::UnorderedAccess, 1);
tmpMip = RenderTargetPool::Get(desc);
if (!tmpMip)
return true;
}
GPUTextureView* tmpMipView = tmpMip->ViewVolume();
// Tex -> Mip
// TODO: use push constants on DX12/Vulkan to provide those 4 uints to the shader
data.GenerateMipTexResolution = data.CascadeResolution;
data.GenerateMipCoordScale = data.CascadeMipFactor;
data.GenerateMipTexOffsetX = data.CascadeIndex * data.CascadeResolution;
data.GenerateMipMipOffsetX = data.CascadeIndex * data.CascadeMipResolution;
context->UpdateCB(_cb1, &data);
context->BindSR(0, textureView);
context->BindUA(0, textureMipView);
context->Dispatch(_csGenerateMip, mipDispatchGroups, mipDispatchGroups, mipDispatchGroups);
data.GenerateMipTexResolution = data.CascadeMipResolution;
data.GenerateMipCoordScale = 1;
for (int32 i = 1; i < floodFillIterations; i++)
{
context->ResetUA();
context->BindSR(0, cascadeMipView);
context->BindUA(0, tmpMipView);
context->Dispatch(_csGenerateMip1, mipDispatchGroups, mipDispatchGroups, mipDispatchGroups);
Swap(tmpMipView, cascadeMipView);
if ((i & 1) == 1)
{
// Mip -> Tmp
context->BindSR(0, textureMipView);
context->BindUA(0, tmpMipView);
data.GenerateMipTexOffsetX = data.CascadeIndex * data.CascadeMipResolution;
data.GenerateMipMipOffsetX = 0;
}
else
{
// Tmp -> Mip
context->BindSR(0, tmpMipView);
context->BindUA(0, textureMipView);
data.GenerateMipTexOffsetX = 0;
data.GenerateMipMipOffsetX = data.CascadeIndex * data.CascadeMipResolution;
}
context->UpdateCB(_cb1, &data);
context->Dispatch(_csGenerateMip, mipDispatchGroups, mipDispatchGroups, mipDispatchGroups);
}
if (floodFillIterations % 2 == 0)
Swap(tmpMipView, cascadeMipView);
}
}
@@ -771,26 +788,22 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
}
// Copy results
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.");
result.Texture = sdfData.Texture;
result.TextureMip = sdfData.TextureMip;
for (int32 cascadeIndex = 0; cascadeIndex < cascadesCount; cascadeIndex++)
{
auto& cascade = sdfData.Cascades[cascadeIndex];
const float cascadeDistance = distanceExtent * cascadesDistanceScales[cascadeIndex];
const float cascadeMaxDistance = cascadeDistance * 2;
const float cascadeVoxelSize = cascadeMaxDistance / resolution;
const float cascadeVoxelSize = cascadeMaxDistance / (float)resolution;
const Vector3 center = cascade.Position;
result.Constants.CascadePosDistance[cascadeIndex] = Vector4(center, cascadeDistance);
result.Constants.CascadeVoxelSize.Raw[cascadeIndex] = cascadeVoxelSize;
result.Cascades[cascadeIndex] = cascade.Texture;
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.CascadesCount = cascadesCount;
@@ -820,8 +833,8 @@ void GlobalSignDistanceFieldPass::RenderDebug(RenderContext& renderContext, GPUC
context->UpdateCB(_cb0, &data);
context->BindCB(0, _cb0);
}
bindingData.BindCascades(context, 0);
bindingData.BindCascadeMips(context, 4);
context->BindSR(0, bindingData.Texture ? bindingData.Texture->ViewVolume() : nullptr);
context->BindSR(1, bindingData.TextureMip ? bindingData.TextureMip->ViewVolume() : nullptr);
context->SetState(_psDebug);
context->SetRenderTarget(output->View());
context->SetViewportAndScissors(outputSize.X, outputSize.Y);

View File

@@ -23,12 +23,9 @@ public:
// Binding data for the GPU.
struct BindingData
{
GPUTexture* Cascades[4];
GPUTexture* CascadeMips[4];
GPUTexture* Texture;
GPUTexture* TextureMip;
ConstantsData Constants;
void BindCascades(GPUContext* context, int32 srvSlot);
void BindCascadeMips(GPUContext* context, int32 srvSlot);
};
private:
@@ -39,8 +36,7 @@ private:
GPUShaderProgramCS* _csRasterizeModel1 = nullptr;
GPUShaderProgramCS* _csRasterizeHeightfield = nullptr;
GPUShaderProgramCS* _csClearChunk = nullptr;
GPUShaderProgramCS* _csGenerateMip0 = nullptr;
GPUShaderProgramCS* _csGenerateMip1 = nullptr;
GPUShaderProgramCS* _csGenerateMip = nullptr;
GPUConstantBuffer* _cb0 = nullptr;
GPUConstantBuffer* _cb1 = nullptr;

View File

@@ -170,8 +170,7 @@ const Char* ShaderGraphUtilities::GenerateShaderResources(TextWriterUnicode& wri
format = TEXT("Texture3D {0} : register(t{1});");
break;
case MaterialParameterType::GlobalSDF:
format = TEXT("Texture3D<float> {0}_Tex[4] : register(t{1});");
registers = 4;
format = TEXT("Texture3D<float> {0}_Tex : register(t{1});");
zeroOffset = false;
break;
}

View File

@@ -60,8 +60,8 @@ float3 GetProbeRayDirection(DDGIData data, uint rayIndex)
RWTexture2D<float4> RWProbesState : register(u0);
Texture3D<float> GlobalSDFTex[4] : register(t0);
Texture3D<float> GlobalSDFMip[4] : register(t4);
Texture3D<float> GlobalSDFTex : register(t0);
Texture3D<float> GlobalSDFMip : register(t1);
// Compute shader for updating probes state between active and inactive.
META_CS(true, FEATURE_LEVEL_SM5)
@@ -138,14 +138,14 @@ void CS_Classify(uint3 DispatchThreadId : SV_DispatchThreadID)
RWTexture2D<float4> RWProbesTrace : register(u0);
Texture3D<float> GlobalSDFTex[4] : register(t0);
Texture3D<float> GlobalSDFMip[4] : register(t4);
ByteAddressBuffer GlobalSurfaceAtlasChunks : register(t8);
Buffer<float4> GlobalSurfaceAtlasCulledObjects : register(t9);
Texture2D GlobalSurfaceAtlasDepth : register(t10);
Texture2D GlobalSurfaceAtlasTex : register(t11);
Texture2D<float4> ProbesState : register(t12);
TextureCube Skybox : register(t13);
Texture3D<float> GlobalSDFTex : register(t0);
Texture3D<float> GlobalSDFMip : register(t1);
ByteAddressBuffer GlobalSurfaceAtlasChunks : register(t2);
Buffer<float4> GlobalSurfaceAtlasCulledObjects : register(t3);
Texture2D GlobalSurfaceAtlasDepth : register(t4);
Texture2D GlobalSurfaceAtlasTex : register(t5);
Texture2D<float4> ProbesState : register(t6);
TextureCube Skybox : register(t7);
// Compute shader for tracing rays for probes using Global SDF and Global Surface Atlas.
META_CS(true, FEATURE_LEVEL_SM5)

View File

@@ -75,8 +75,8 @@ Texture2D<float4> ProbesState : register(t5);
Texture2D<float4> ProbesDistance : register(t6);
Texture2D<float4> ProbesIrradiance : register(t7);
#else
Texture3D<float> GlobalSDFTex[4] : register(t5);
Texture3D<float> GlobalSDFMip[4] : register(t9);
Texture3D<float> GlobalSDFTex : register(t5);
Texture3D<float> GlobalSDFMip : register(t6);
#endif
// Pixel shader for Global Surface Atlas shading with direct light contribution
@@ -265,13 +265,13 @@ void CS_CullObjects(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_Disp
#ifdef _PS_Debug
Texture3D<float> GlobalSDFTex[4] : register(t0);
Texture3D<float> GlobalSDFMip[4] : register(t4);
ByteAddressBuffer GlobalSurfaceAtlasChunks : register(t8);
Buffer<float4> GlobalSurfaceAtlasCulledObjects : register(t9);
Texture2D GlobalSurfaceAtlasDepth : register(t10);
Texture2D GlobalSurfaceAtlasTex : register(t11);
TextureCube Skybox : register(t12);
Texture3D<float> GlobalSDFTex : register(t0);
Texture3D<float> GlobalSDFMip : register(t1);
ByteAddressBuffer GlobalSurfaceAtlasChunks : register(t2);
Buffer<float4> GlobalSurfaceAtlasCulledObjects : register(t3);
Texture2D GlobalSurfaceAtlasDepth : register(t4);
Texture2D GlobalSurfaceAtlasTex : register(t5);
TextureCube Skybox : register(t6);
// Pixel shader for Global Surface Atlas debug drawing
META_PS(true, FEATURE_LEVEL_SM5)

View File

@@ -59,20 +59,27 @@ struct GlobalSDFHit
}
};
void GetGlobalSDFCascadeUV(const GlobalSDFData data, uint cascade, float3 worldPosition, out float cascadeMaxDistance, out float3 cascadeUV, out float3 textureUV)
{
float4 cascadePosDistance = data.CascadePosDistance[cascade];
float3 posInCascade = worldPosition - cascadePosDistance.xyz;
cascadeMaxDistance = cascadePosDistance.w * 2;
cascadeUV = saturate(posInCascade / cascadeMaxDistance + 0.5f);
textureUV = float3(((float)cascade + cascadeUV.x) / (float)data.CascadesCount, cascadeUV.y, cascadeUV.z); // cascades are placed next to each other on X axis
}
// Samples the Global SDF and returns the distance to the closest surface (in world units) at the given world location.
float SampleGlobalSDF(const GlobalSDFData data, Texture3D<float> tex[4], float3 worldPosition)
float SampleGlobalSDF(const GlobalSDFData data, Texture3D<float> tex, float3 worldPosition)
{
float distance = data.CascadePosDistance[3].w * 2.0f;
if (distance <= 0.0f)
return GLOBAL_SDF_WORLD_SIZE;
UNROLL
for (uint cascade = 0; cascade < data.CascadesCount; cascade++)
{
float4 cascadePosDistance = data.CascadePosDistance[cascade];
float cascadeMaxDistance = cascadePosDistance.w * 2;
float3 posInCascade = worldPosition - cascadePosDistance.xyz;
float3 cascadeUV = posInCascade / cascadeMaxDistance + 0.5f;
float cascadeDistance = tex[cascade].SampleLevel(SamplerLinearClamp, cascadeUV, 0);
float cascadeMaxDistance;
float3 cascadeUV, textureUV;
GetGlobalSDFCascadeUV(data, cascade, worldPosition, cascadeMaxDistance, cascadeUV, textureUV);
float cascadeDistance = tex.SampleLevel(SamplerLinearClamp, textureUV, 0);
if (cascadeDistance < 1.0f && !any(cascadeUV < 0) && !any(cascadeUV > 1))
{
distance = cascadeDistance * cascadeMaxDistance;
@@ -83,29 +90,27 @@ float SampleGlobalSDF(const GlobalSDFData data, Texture3D<float> tex[4], float3
}
// Samples the Global SDF and returns the gradient vector (derivative) at the given world location. Normalize it to get normal vector.
float3 SampleGlobalSDFGradient(const GlobalSDFData data, Texture3D<float> tex[4], float3 worldPosition, out float distance)
float3 SampleGlobalSDFGradient(const GlobalSDFData data, Texture3D<float> tex, float3 worldPosition, out float distance)
{
float3 gradient = float3(0, 0.00001f, 0);
distance = GLOBAL_SDF_WORLD_SIZE;
if (data.CascadePosDistance[3].w <= 0.0f)
return gradient;
UNROLL
for (uint cascade = 0; cascade < data.CascadesCount; cascade++)
{
float4 cascadePosDistance = data.CascadePosDistance[cascade];
float cascadeMaxDistance = cascadePosDistance.w * 2;
float3 posInCascade = worldPosition - cascadePosDistance.xyz;
float3 cascadeUV = posInCascade / cascadeMaxDistance + 0.5f;
float cascadeDistance = tex[cascade].SampleLevel(SamplerLinearClamp, cascadeUV, 0);
float cascadeMaxDistance;
float3 cascadeUV, textureUV;
GetGlobalSDFCascadeUV(data, cascade, worldPosition, cascadeMaxDistance, cascadeUV, textureUV);
float cascadeDistance = tex.SampleLevel(SamplerLinearClamp, textureUV, 0);
if (cascadeDistance < 0.9f && !any(cascadeUV < 0) && !any(cascadeUV > 1))
{
float texelOffset = 1.0f / data.Resolution;
float xp = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x + texelOffset, cascadeUV.y, cascadeUV.z), 0).x;
float xn = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x - texelOffset, cascadeUV.y, cascadeUV.z), 0).x;
float yp = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x, cascadeUV.y + texelOffset, cascadeUV.z), 0).x;
float yn = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x, cascadeUV.y - texelOffset, cascadeUV.z), 0).x;
float zp = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x, cascadeUV.y, cascadeUV.z + texelOffset), 0).x;
float zn = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x, cascadeUV.y, cascadeUV.z - texelOffset), 0).x;
float xp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x + texelOffset, textureUV.y, textureUV.z), 0).x;
float xn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x - texelOffset, textureUV.y, textureUV.z), 0).x;
float yp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y + texelOffset, textureUV.z), 0).x;
float yn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y - texelOffset, textureUV.z), 0).x;
float zp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y, textureUV.z + texelOffset), 0).x;
float zn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y, textureUV.z - texelOffset), 0).x;
gradient = float3(xp - xn, yp - yn, zp - zn) * cascadeMaxDistance;
distance = cascadeDistance * cascadeMaxDistance;
break;
@@ -115,7 +120,7 @@ float3 SampleGlobalSDFGradient(const GlobalSDFData data, Texture3D<float> tex[4]
}
// Samples the Global SDF and returns the gradient vector (derivative) at the given world location. Normalize it to get normal vector.
float3 SampleGlobalSDFGradient(const GlobalSDFData data, Texture3D<float> tex[4], Texture3D<float> mips[4], float3 worldPosition, out float distance)
float3 SampleGlobalSDFGradient(const GlobalSDFData data, Texture3D<float> tex, Texture3D<float> mip, float3 worldPosition, out float distance)
{
float3 gradient = float3(0, 0.00001f, 0);
distance = GLOBAL_SDF_WORLD_SIZE;
@@ -123,28 +128,26 @@ float3 SampleGlobalSDFGradient(const GlobalSDFData data, Texture3D<float> tex[4]
return gradient;
float chunkSizeDistance = (float)GLOBAL_SDF_RASTERIZE_CHUNK_SIZE / data.Resolution; // Size of the chunk in SDF distance (0-1)
float chunkMarginDistance = (float)GLOBAL_SDF_RASTERIZE_CHUNK_MARGIN / data.Resolution; // Size of the chunk margin in SDF distance (0-1)
UNROLL
for (uint cascade = 0; cascade < data.CascadesCount; cascade++)
{
float4 cascadePosDistance = data.CascadePosDistance[cascade];
float cascadeMaxDistance = cascadePosDistance.w * 2;
float3 posInCascade = worldPosition - cascadePosDistance.xyz;
float3 cascadeUV = posInCascade / cascadeMaxDistance + 0.5f;
float cascadeDistance = mips[cascade].SampleLevel(SamplerLinearClamp, cascadeUV, 0);
float cascadeMaxDistance;
float3 cascadeUV, textureUV;
GetGlobalSDFCascadeUV(data, cascade, worldPosition, cascadeMaxDistance, cascadeUV, textureUV);
float cascadeDistance = mip.SampleLevel(SamplerLinearClamp, textureUV, 0);
if (cascadeDistance < chunkSizeDistance && !any(cascadeUV < 0) && !any(cascadeUV > 1))
{
float cascadeDistanceTex = tex[cascade].SampleLevel(SamplerLinearClamp, cascadeUV, 0);
float cascadeDistanceTex = tex.SampleLevel(SamplerLinearClamp, textureUV, 0);
if (cascadeDistanceTex < chunkMarginDistance * 2)
{
cascadeDistance = cascadeDistanceTex;
}
float texelOffset = 1.0f / data.Resolution;
float xp = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x + texelOffset, cascadeUV.y, cascadeUV.z), 0).x;
float xn = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x - texelOffset, cascadeUV.y, cascadeUV.z), 0).x;
float yp = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x, cascadeUV.y + texelOffset, cascadeUV.z), 0).x;
float yn = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x, cascadeUV.y - texelOffset, cascadeUV.z), 0).x;
float zp = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x, cascadeUV.y, cascadeUV.z + texelOffset), 0).x;
float zn = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x, cascadeUV.y, cascadeUV.z - texelOffset), 0).x;
float xp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x + texelOffset, textureUV.y, textureUV.z), 0).x;
float xn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x - texelOffset, textureUV.y, textureUV.z), 0).x;
float yp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y + texelOffset, textureUV.z), 0).x;
float yn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y - texelOffset, textureUV.z), 0).x;
float zp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y, textureUV.z + texelOffset), 0).x;
float zn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y, textureUV.z - texelOffset), 0).x;
gradient = float3(xp - xn, yp - yn, zp - zn) * cascadeMaxDistance;
distance = cascadeDistance * cascadeMaxDistance;
break;
@@ -154,7 +157,7 @@ float3 SampleGlobalSDFGradient(const GlobalSDFData data, Texture3D<float> tex[4]
}
// Ray traces the Global SDF.
GlobalSDFHit RayTraceGlobalSDF(const GlobalSDFData data, Texture3D<float> tex[4], Texture3D<float> mips[4], const GlobalSDFTrace trace)
GlobalSDFHit RayTraceGlobalSDF(const GlobalSDFData data, Texture3D<float> tex, Texture3D<float> mip, const GlobalSDFTrace trace)
{
GlobalSDFHit hit = (GlobalSDFHit)0;
hit.HitTime = -1.0f;
@@ -163,7 +166,6 @@ GlobalSDFHit RayTraceGlobalSDF(const GlobalSDFData data, Texture3D<float> tex[4]
float nextIntersectionStart = 0.0f;
float traceMaxDistance = min(trace.MaxDistance, data.CascadePosDistance[3].w * 2);
float3 traceEndPosition = trace.WorldPosition + trace.WorldDirection * traceMaxDistance;
UNROLL
for (uint cascade = 0; cascade < data.CascadesCount && hit.HitTime < 0.0f; cascade++)
{
float4 cascadePosDistance = data.CascadePosDistance[cascade];
@@ -195,13 +197,14 @@ GlobalSDFHit RayTraceGlobalSDF(const GlobalSDFData data, Texture3D<float> tex[4]
{
float3 stepPosition = trace.WorldPosition + trace.WorldDirection * stepTime;
// Sample SDF
float3 posInCascade = stepPosition - cascadePosDistance.xyz;
float3 cascadeUV = posInCascade / cascadeMaxDistance + 0.5f;
float stepDistance = mips[cascade].SampleLevel(SamplerLinearClamp, cascadeUV, 0);
// Sample SDF
float cascadeMaxDistance;
float3 cascadeUV, textureUV;
GetGlobalSDFCascadeUV(data, cascade, stepPosition, cascadeMaxDistance, cascadeUV, textureUV);
float stepDistance = mip.SampleLevel(SamplerLinearClamp, textureUV, 0);
if (stepDistance < chunkSizeDistance)
{
float stepDistanceTex = tex[cascade].SampleLevel(SamplerLinearClamp, cascadeUV, 0);
float stepDistanceTex = tex.SampleLevel(SamplerLinearClamp, textureUV, 0);
if (stepDistanceTex < chunkMarginDistance * 2)
{
stepDistance = stepDistanceTex;
@@ -226,12 +229,12 @@ GlobalSDFHit RayTraceGlobalSDF(const GlobalSDFData data, Texture3D<float> tex[4]
{
// Calculate hit normal from SDF gradient
float texelOffset = 1.0f / data.Resolution;
float xp = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x + texelOffset, cascadeUV.y, cascadeUV.z), 0).x;
float xn = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x - texelOffset, cascadeUV.y, cascadeUV.z), 0).x;
float yp = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x, cascadeUV.y + texelOffset, cascadeUV.z), 0).x;
float yn = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x, cascadeUV.y - texelOffset, cascadeUV.z), 0).x;
float zp = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x, cascadeUV.y, cascadeUV.z + texelOffset), 0).x;
float zn = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x, cascadeUV.y, cascadeUV.z - texelOffset), 0).x;
float xp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x + texelOffset, textureUV.y, textureUV.z), 0).x;
float xn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x - texelOffset, textureUV.y, textureUV.z), 0).x;
float yp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y + texelOffset, textureUV.z), 0).x;
float yn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y - texelOffset, textureUV.z), 0).x;
float zp = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y, textureUV.z + texelOffset), 0).x;
float zn = tex.SampleLevel(SamplerLinearClamp, float3(textureUV.x, textureUV.y, textureUV.z - texelOffset), 0).x;
hit.HitNormal = normalize(float3(xp - xn, yp - yn, zp - zn));
}
break;

View File

@@ -37,11 +37,15 @@ float3 CascadeCoordToPosMul;
int ObjectsCount;
float3 CascadeCoordToPosAdd;
int CascadeResolution;
float Padding0;
int CascadeIndex;
float CascadeVoxelSize;
int CascadeMipResolution;
int CascadeMipFactor;
uint4 Objects[GLOBAL_SDF_RASTERIZE_MODEL_MAX_COUNT / 4];
uint GenerateMipTexResolution;
uint GenerateMipCoordScale;
uint GenerateMipTexOffsetX;
uint GenerateMipMipOffsetX;
META_CB_END
float CombineDistanceToSDF(float sdf, float distanceToSDF)
@@ -97,10 +101,11 @@ META_CS(true, FEATURE_LEVEL_SM5)
META_PERMUTATION_1(READ_SDF=0)
META_PERMUTATION_1(READ_SDF=1)
[numthreads(GLOBAL_SDF_RASTERIZE_GROUP_SIZE, GLOBAL_SDF_RASTERIZE_GROUP_SIZE, GLOBAL_SDF_RASTERIZE_GROUP_SIZE)]
void CS_RasterizeModel(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_DispatchThreadID, uint3 GroupThreadId : SV_GroupThreadID)
void CS_RasterizeModel(uint3 DispatchThreadId : SV_DispatchThreadID)
{
uint3 voxelCoord = ChunkCoord + DispatchThreadId;
float3 voxelWorldPos = voxelCoord * CascadeCoordToPosMul + CascadeCoordToPosAdd;
voxelCoord.x += CascadeIndex * CascadeResolution;
float minDistance = MaxDistance;
#if READ_SDF
minDistance *= GlobalSDFTex[voxelCoord];
@@ -123,10 +128,11 @@ Texture2D<float4> ObjectsTextures[GLOBAL_SDF_RASTERIZE_HEIGHTFIELD_MAX_COUNT] :
// Compute shader for rasterizing heightfield into Global SDF
META_CS(true, FEATURE_LEVEL_SM5)
[numthreads(GLOBAL_SDF_RASTERIZE_GROUP_SIZE, GLOBAL_SDF_RASTERIZE_GROUP_SIZE, GLOBAL_SDF_RASTERIZE_GROUP_SIZE)]
void CS_RasterizeHeightfield(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_DispatchThreadID, uint3 GroupThreadId : SV_GroupThreadID)
void CS_RasterizeHeightfield(uint3 DispatchThreadId : SV_DispatchThreadID)
{
uint3 voxelCoord = ChunkCoord + DispatchThreadId;
float3 voxelWorldPos = voxelCoord * CascadeCoordToPosMul + CascadeCoordToPosAdd;
voxelCoord.x += CascadeIndex * CascadeResolution;
float minDistance = MaxDistance * GlobalSDFTex[voxelCoord];
float thickness = CascadeVoxelSize * -8;
for (uint i = 0; i < ObjectsCount; i++)
@@ -167,9 +173,10 @@ RWTexture3D<float> GlobalSDFTex : register(u0);
// Compute shader for clearing Global SDF chunk
META_CS(true, FEATURE_LEVEL_SM5)
[numthreads(GLOBAL_SDF_RASTERIZE_GROUP_SIZE, GLOBAL_SDF_RASTERIZE_GROUP_SIZE, GLOBAL_SDF_RASTERIZE_GROUP_SIZE)]
void CS_ClearChunk(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_DispatchThreadID, uint3 GroupThreadId : SV_GroupThreadID)
void CS_ClearChunk(uint3 DispatchThreadId : SV_DispatchThreadID)
{
uint3 voxelCoord = ChunkCoord + DispatchThreadId;
voxelCoord.x += CascadeIndex * CascadeResolution;
GlobalSDFTex[voxelCoord] = 1.0f;
}
@@ -182,21 +189,13 @@ Texture3D<float> GlobalSDFTex : register(t0);
float SampleSDF(uint3 voxelCoordMip, int3 offset)
{
#if SAMPLE_MIP
// Sampling Global SDF Mip
float resolution = CascadeMipResolution;
#else
// Sampling Global SDF Tex
voxelCoordMip *= CascadeMipFactor;
float resolution = CascadeResolution;
#endif
// Sample SDF
voxelCoordMip = (uint3)clamp((int3)voxelCoordMip + offset, 0, resolution - 1);
voxelCoordMip = (uint3)clamp((int3)voxelCoordMip * GenerateMipCoordScale + offset, 0, GenerateMipTexResolution - 1);
voxelCoordMip.x += GenerateMipTexOffsetX;
float result = GlobalSDFTex[voxelCoordMip].r;
// Extend by distance to the sampled texel location
float distanceInWorldUnits = length(offset) * (MaxDistance / resolution);
float distanceInWorldUnits = length(offset) * (MaxDistance / (float)GenerateMipTexResolution);
float distanceToVoxel = distanceInWorldUnits / MaxDistance;
result = CombineDistanceToSDF(result, distanceToVoxel);
@@ -205,10 +204,8 @@ float SampleSDF(uint3 voxelCoordMip, int3 offset)
// Compute shader for generating mip for Global SDF (uses flood fill algorithm)
META_CS(true, FEATURE_LEVEL_SM5)
META_PERMUTATION_1(SAMPLE_MIP=0)
META_PERMUTATION_1(SAMPLE_MIP=1)
[numthreads(GLOBAL_SDF_MIP_GROUP_SIZE, GLOBAL_SDF_MIP_GROUP_SIZE, GLOBAL_SDF_MIP_GROUP_SIZE)]
void CS_GenerateMip(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_DispatchThreadID, uint3 GroupThreadId : SV_GroupThreadID)
void CS_GenerateMip(uint3 DispatchThreadId : SV_DispatchThreadID)
{
uint3 voxelCoordMip = DispatchThreadId;
float minDistance = SampleSDF(voxelCoordMip, int3(0, 0, 0));
@@ -221,6 +218,7 @@ void CS_GenerateMip(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_Disp
minDistance = min(minDistance, SampleSDF(voxelCoordMip, int3(0, -1, 0)));
minDistance = min(minDistance, SampleSDF(voxelCoordMip, int3(0, 0, -1)));
voxelCoordMip.x += GenerateMipMipOffsetX;
GlobalSDFMip[voxelCoordMip] = minDistance;
}
@@ -228,8 +226,8 @@ void CS_GenerateMip(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_Disp
#ifdef _PS_Debug
Texture3D<float> GlobalSDFTex[4] : register(t0);
Texture3D<float> GlobalSDFMip[4] : register(t4);
Texture3D<float> GlobalSDFTex : register(t0);
Texture3D<float> GlobalSDFMip : register(t1);
// Pixel shader for Global SDF debug drawing
META_PS(true, FEATURE_LEVEL_SM5)
@@ -241,6 +239,7 @@ float4 PS_Debug(Quad_VS2PS input) : SV_Target
float mip = 0;
uint cascade = 0;
float distance01 = GlobalSDFTex[cascade].SampleLevel(SamplerLinearClamp, float3(input.TexCoord, zSlice), mip).x;
//float distance01 = GlobalSDFTex[cascade].SampleLevel(SamplerLinearClamp, float3((input.TexCoord.x + cascade) / (float)GlobalSDF.CascadesCount, input.TexCoord.y, zSlice), mip).x;
//float distance01 = GlobalSDFMip[cascade].SampleLevel(SamplerLinearClamp, float3(input.TexCoord, zSlice), mip).x;
float distance = distance01 * GlobalSDF.CascadePosDistance[cascade].w;
if (abs(distance) < 1)