Add random per-probe rotation for rays tracing in DDGI

This commit is contained in:
Wojtek Figat
2024-07-11 14:48:24 +02:00
parent dbda31d570
commit 352913ba14
9 changed files with 50 additions and 14 deletions

View File

@@ -46,6 +46,7 @@ GPU_CB_STRUCT(Data0 {
GlobalSignDistanceFieldPass::ConstantsData GlobalSDF; GlobalSignDistanceFieldPass::ConstantsData GlobalSDF;
GlobalSurfaceAtlasPass::ConstantsData GlobalSurfaceAtlas; GlobalSurfaceAtlasPass::ConstantsData GlobalSurfaceAtlas;
ShaderGBufferData GBuffer; ShaderGBufferData GBuffer;
Float4 RaysRotation;
float Padding0; float Padding0;
uint32 ProbesCount; uint32 ProbesCount;
float ResetBlend; float ResetBlend;
@@ -379,7 +380,7 @@ bool DynamicDiffuseGlobalIlluminationPass::RenderInner(RenderContext& renderCont
desc2 = GPUBufferDescription::Buffer(sizeof(GPUDispatchIndirectArgs) * Math::DivideAndRoundUp(probesCountCascade, DDGI_TRACE_RAYS_PROBES_COUNT_LIMIT), GPUBufferFlags::Argument | GPUBufferFlags::UnorderedAccess, PixelFormat::R32_UInt, nullptr, sizeof(uint32)); desc2 = GPUBufferDescription::Buffer(sizeof(GPUDispatchIndirectArgs) * Math::DivideAndRoundUp(probesCountCascade, DDGI_TRACE_RAYS_PROBES_COUNT_LIMIT), GPUBufferFlags::Argument | GPUBufferFlags::UnorderedAccess, PixelFormat::R32_UInt, nullptr, sizeof(uint32));
INIT_BUFFER(UpdateProbesInitArgs, "DDGI.UpdateProbesInitArgs"); INIT_BUFFER(UpdateProbesInitArgs, "DDGI.UpdateProbesInitArgs");
#undef INIT_BUFFER #undef INIT_BUFFER
LOG(Info, "Dynamic Diffuse Global Illumination memory usage: {0} MB, probes: {1}", memUsage / 1024 / 1024, probesCountTotal); LOG(Info, "Dynamic Diffuse Global Illumination probes: {0}, memory usage: {1} MB", probesCountTotal, memUsage / (1024 * 1024));
clear = true; clear = true;
} }
#if COMPILE_WITH_DEV_ENV #if COMPILE_WITH_DEV_ENV
@@ -465,14 +466,15 @@ bool DynamicDiffuseGlobalIlluminationPass::RenderInner(RenderContext& renderCont
ddgiData.Result.ProbesDistance = ddgiData.ProbesDistance->View(); ddgiData.Result.ProbesDistance = ddgiData.ProbesDistance->View();
ddgiData.Result.ProbesIrradiance = ddgiData.ProbesIrradiance->View(); ddgiData.Result.ProbesIrradiance = ddgiData.ProbesIrradiance->View();
Data0 data;
// Compute random rotation matrix for probe rays orientation (randomized every frame) // Compute random rotation matrix for probe rays orientation (randomized every frame)
Matrix3x3 raysRotationMatrix; Matrix3x3 raysRotationMatrix;
CalculateVolumeRandomRotation(raysRotationMatrix); CalculateVolumeRandomRotation(raysRotationMatrix);
Quaternion& raysRotation = *(Quaternion*)&ddgiData.Result.Constants.RaysRotation; Quaternion& raysRotation = *(Quaternion*)&data.RaysRotation;
Quaternion::RotationMatrix(raysRotationMatrix, raysRotation); Quaternion::RotationMatrix(raysRotationMatrix, raysRotation);
raysRotation.Conjugate(); raysRotation.Conjugate();
Data0 data;
data.DDGI = ddgiData.Result.Constants; data.DDGI = ddgiData.Result.Constants;
data.GlobalSDF = bindingDataSDF.Constants; data.GlobalSDF = bindingDataSDF.Constants;
data.GlobalSurfaceAtlas = bindingDataSurfaceAtlas.Constants; data.GlobalSurfaceAtlas = bindingDataSurfaceAtlas.Constants;
@@ -638,7 +640,6 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext,
auto& ddgiData = *renderBuffers->GetCustomBuffer<DDGICustomBuffer>(TEXT("DDGI")); auto& ddgiData = *renderBuffers->GetCustomBuffer<DDGICustomBuffer>(TEXT("DDGI"));
if (render && ddgiData.LastFrameUsed == Engine::FrameCount) if (render && ddgiData.LastFrameUsed == Engine::FrameCount)
render = false; render = false;
PROFILE_GPU_CPU("Dynamic Diffuse Global Illumination"); PROFILE_GPU_CPU("Dynamic Diffuse Global Illumination");
if (render) if (render)

View File

@@ -22,7 +22,6 @@ public:
float ProbeHistoryWeight; float ProbeHistoryWeight;
float RayMaxDistance; float RayMaxDistance;
float IndirectLightingIntensity; float IndirectLightingIntensity;
Float4 RaysRotation;
Float3 ViewPos; Float3 ViewPos;
uint32 RaysCount; uint32 RaysCount;
Float3 FallbackIrradiance; Float3 FallbackIrradiance;

View File

@@ -742,7 +742,7 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
return true; return true;
memUsage += surfaceAtlasData.ChunksBuffer->GetMemoryUsage(); memUsage += surfaceAtlasData.ChunksBuffer->GetMemoryUsage();
} }
LOG(Info, "Global Surface Atlas resolution: {0}, memory usage: {1} MB", resolution, memUsage / 1024 / 1024); LOG(Info, "Global Surface Atlas resolution: {0}, memory usage: {1} MB", resolution, memUsage / (1024 * 1024));
} }
for (SceneRendering* scene : renderContext.List->Scenes) for (SceneRendering* scene : renderContext.List->Scenes)
surfaceAtlasData.ListenSceneRendering(scene); surfaceAtlasData.ListenSceneRendering(scene);

View File

@@ -764,7 +764,7 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
} }
} }
uint64 memoryUsage = sdfData.Texture->GetMemoryUsage() + sdfData.TextureMip->GetMemoryUsage(); uint64 memoryUsage = sdfData.Texture->GetMemoryUsage() + sdfData.TextureMip->GetMemoryUsage();
LOG(Info, "Global SDF memory usage: {0} MB", memoryUsage / 1024 / 1024); LOG(Info, "Global SDF memory usage: {0} MB", memoryUsage / (1024 * 1024));
} }
if (sdfData.Origin != renderContext.View.Origin) if (sdfData.Origin != renderContext.View.Origin)
{ {

View File

@@ -32,7 +32,6 @@ struct DDGIData
float ProbeHistoryWeight; float ProbeHistoryWeight;
float RayMaxDistance; float RayMaxDistance;
float IndirectLightingIntensity; float IndirectLightingIntensity;
float4 RaysRotation;
float3 ViewPos; float3 ViewPos;
uint RaysCount; uint RaysCount;
float3 FallbackIrradiance; float3 FallbackIrradiance;

View File

@@ -11,6 +11,7 @@
#include "./Flax/Common.hlsl" #include "./Flax/Common.hlsl"
#include "./Flax/Math.hlsl" #include "./Flax/Math.hlsl"
#include "./Flax/Noise.hlsl"
#include "./Flax/Quaternion.hlsl" #include "./Flax/Quaternion.hlsl"
#include "./Flax/GlobalSignDistanceField.hlsl" #include "./Flax/GlobalSignDistanceField.hlsl"
#include "./Flax/GI/GlobalSurfaceAtlas.hlsl" #include "./Flax/GI/GlobalSurfaceAtlas.hlsl"
@@ -30,6 +31,7 @@ DDGIData DDGI;
GlobalSDFData GlobalSDF; GlobalSDFData GlobalSDF;
GlobalSurfaceAtlasData GlobalSurfaceAtlas; GlobalSurfaceAtlasData GlobalSurfaceAtlas;
GBufferData GBuffer; GBufferData GBuffer;
float4 RaysRotation;
float Padding0; float Padding0;
uint ProbesCount; uint ProbesCount;
float ResetBlend; float ResetBlend;
@@ -55,10 +57,19 @@ float3 GetSphericalFibonacci(float sampleIndex, float samplesCount)
} }
// Calculates a random normalized ray direction (based on the ray index and the current probes rotation phrase) // Calculates a random normalized ray direction (based on the ray index and the current probes rotation phrase)
float3 GetProbeRayDirection(DDGIData data, uint rayIndex) float3 GetProbeRayDirection(DDGIData data, uint rayIndex, uint raysCount, uint probeIndex, uint3 probeCoords)
{ {
float3 direction = GetSphericalFibonacci((float)rayIndex, (float)data.RaysCount); float4 rotation = RaysRotation;
return normalize(QuaternionRotate(data.RaysRotation, direction));
// Randomize rotation per-probe (otherwise all probes are in sync)
float3 probePos = (float3)probeCoords / (float3)data.ProbesCounts;
float3 randomAxis = normalize(Mod289(probePos));
float randomAngle = (float)probeIndex / (float)ProbesCount * (2.0f * PI);
rotation = QuaternionMultiply(rotation, QuaternionFromAxisAngle(randomAxis, randomAngle));
// Random rotation per-ray - relative to the per-frame rays rotation
float3 direction = GetSphericalFibonacci((float)rayIndex, (float)raysCount);
return normalize(QuaternionRotate(rotation, direction));
} }
// Calculates amount of rays to allocate for a probe // Calculates amount of rays to allocate for a probe
@@ -299,7 +310,7 @@ Texture2D<snorm float4> ProbesData : register(t7);
TextureCube Skybox : register(t8); TextureCube Skybox : register(t8);
ByteAddressBuffer ActiveProbes : register(t9); ByteAddressBuffer ActiveProbes : register(t9);
// Compute shader for tracing rays for probes using Global SDF and Global Surface Atlas. // Compute shader for tracing rays for probes using Global SDF and Global Surface Atlas (1 ray per-thread).
META_CS(true, FEATURE_LEVEL_SM5) META_CS(true, FEATURE_LEVEL_SM5)
META_PERMUTATION_1(DDGI_TRACE_RAYS_COUNT=96) META_PERMUTATION_1(DDGI_TRACE_RAYS_COUNT=96)
META_PERMUTATION_1(DDGI_TRACE_RAYS_COUNT=128) META_PERMUTATION_1(DDGI_TRACE_RAYS_COUNT=128)
@@ -320,7 +331,7 @@ void CS_TraceRays(uint3 DispatchThreadId : SV_DispatchThreadID)
if (probeState == DDGI_PROBE_STATE_INACTIVE || rayIndex >= probeRaysCount) if (probeState == DDGI_PROBE_STATE_INACTIVE || rayIndex >= probeRaysCount)
return; // Skip disabled probes or if current thread's ray is unused return; // Skip disabled probes or if current thread's ray is unused
float3 probePosition = DecodeDDGIProbePosition(DDGI, probeData, CascadeIndex, probeIndex, probeCoords); float3 probePosition = DecodeDDGIProbePosition(DDGI, probeData, CascadeIndex, probeIndex, probeCoords);
float3 probeRayDirection = GetProbeRayDirection(DDGI, rayIndex); float3 probeRayDirection = GetProbeRayDirection(DDGI, rayIndex, probeRaysCount, probeIndex, probeCoords);
// Trace ray with Global SDF // Trace ray with Global SDF
GlobalSDFTrace trace; GlobalSDFTrace trace;
@@ -428,7 +439,7 @@ void CS_UpdateProbes(uint3 GroupThreadId : SV_GroupThreadID, uint3 GroupId : SV_
float rayDistance = ProbesTrace[uint2(rayIndex, GroupId.x)].w; float rayDistance = ProbesTrace[uint2(rayIndex, GroupId.x)].w;
CachedProbesTraceDistance[rayIndex] = min(abs(rayDistance), distanceLimit); CachedProbesTraceDistance[rayIndex] = min(abs(rayDistance), distanceLimit);
#endif #endif
CachedProbesTraceDirection[rayIndex] = GetProbeRayDirection(DDGI, rayIndex); CachedProbesTraceDirection[rayIndex] = GetProbeRayDirection(DDGI, rayIndex, probeRaysCount, probeIndex, probeCoords);
} }
} }
GroupMemoryBarrierWithGroupSync(); GroupMemoryBarrierWithGroupSync();

View File

@@ -3,6 +3,9 @@
#ifndef __MATH__ #ifndef __MATH__
#define __MATH__ #define __MATH__
#define RadiansToDegrees (180.0f / PI)
#define DegreesToRadians (PI / 180.0f)
uint NextPow2(uint value) uint NextPow2(uint value)
{ {
uint mask = (1 << firstbithigh(value)) - 1; uint mask = (1 << firstbithigh(value)) - 1;

View File

@@ -71,6 +71,24 @@ float2 rand2dTo2d(float2 value)
); );
} }
float rand3dTo1d(float3 value, float3 dotDir = float3(12.9898, 78.233, 37.719))
{
// https://www.ronja-tutorials.com/post/024-white-noise/
float3 smallValue = sin(value);
float random = dot(smallValue, dotDir);
return frac(sin(random) * 143758.5453);
}
float3 rand3dTo3d(float3 value)
{
// https://www.ronja-tutorials.com/post/024-white-noise/
return float3(
rand3dTo1d(value, float3(12.989, 78.233, 37.719)),
rand3dTo1d(value, float3(39.346, 11.135, 83.155)),
rand3dTo1d(value, float3(73.156, 52.235, 09.151))
);
}
// Classic Perlin noise // Classic Perlin noise
float PerlinNoise(float2 p) float PerlinNoise(float2 p)
{ {

View File

@@ -15,4 +15,9 @@ float3 QuaternionRotate(float4 q, float3 v)
return (v * (q.w * q.w - b2) + b * (dot(v, b) * 2.f) + cross(b, v) * (q.w * 2.f)); return (v * (q.w * q.w - b2) + b * (dot(v, b) * 2.f) + cross(b, v) * (q.w * 2.f));
} }
float4 QuaternionFromAxisAngle(float3 axis, float angle)
{
return float4(axis * sin(angle * 0.5f), cos(angle * 0.5f));
}
#endif #endif