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;
GlobalSurfaceAtlasPass::ConstantsData GlobalSurfaceAtlas;
ShaderGBufferData GBuffer;
Float4 RaysRotation;
float Padding0;
uint32 ProbesCount;
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));
INIT_BUFFER(UpdateProbesInitArgs, "DDGI.UpdateProbesInitArgs");
#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;
}
#if COMPILE_WITH_DEV_ENV
@@ -465,14 +466,15 @@ bool DynamicDiffuseGlobalIlluminationPass::RenderInner(RenderContext& renderCont
ddgiData.Result.ProbesDistance = ddgiData.ProbesDistance->View();
ddgiData.Result.ProbesIrradiance = ddgiData.ProbesIrradiance->View();
Data0 data;
// Compute random rotation matrix for probe rays orientation (randomized every frame)
Matrix3x3 raysRotationMatrix;
CalculateVolumeRandomRotation(raysRotationMatrix);
Quaternion& raysRotation = *(Quaternion*)&ddgiData.Result.Constants.RaysRotation;
Quaternion& raysRotation = *(Quaternion*)&data.RaysRotation;
Quaternion::RotationMatrix(raysRotationMatrix, raysRotation);
raysRotation.Conjugate();
Data0 data;
data.DDGI = ddgiData.Result.Constants;
data.GlobalSDF = bindingDataSDF.Constants;
data.GlobalSurfaceAtlas = bindingDataSurfaceAtlas.Constants;
@@ -638,7 +640,6 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext,
auto& ddgiData = *renderBuffers->GetCustomBuffer<DDGICustomBuffer>(TEXT("DDGI"));
if (render && ddgiData.LastFrameUsed == Engine::FrameCount)
render = false;
PROFILE_GPU_CPU("Dynamic Diffuse Global Illumination");
if (render)

View File

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

View File

@@ -742,7 +742,7 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
return true;
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)
surfaceAtlasData.ListenSceneRendering(scene);

View File

@@ -764,7 +764,7 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
}
}
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)
{

View File

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

View File

@@ -11,6 +11,7 @@
#include "./Flax/Common.hlsl"
#include "./Flax/Math.hlsl"
#include "./Flax/Noise.hlsl"
#include "./Flax/Quaternion.hlsl"
#include "./Flax/GlobalSignDistanceField.hlsl"
#include "./Flax/GI/GlobalSurfaceAtlas.hlsl"
@@ -30,6 +31,7 @@ DDGIData DDGI;
GlobalSDFData GlobalSDF;
GlobalSurfaceAtlasData GlobalSurfaceAtlas;
GBufferData GBuffer;
float4 RaysRotation;
float Padding0;
uint ProbesCount;
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)
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);
return normalize(QuaternionRotate(data.RaysRotation, direction));
float4 rotation = RaysRotation;
// 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
@@ -299,7 +310,7 @@ Texture2D<snorm float4> ProbesData : register(t7);
TextureCube Skybox : register(t8);
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_PERMUTATION_1(DDGI_TRACE_RAYS_COUNT=96)
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)
return; // Skip disabled probes or if current thread's ray is unused
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
GlobalSDFTrace trace;
@@ -428,7 +439,7 @@ void CS_UpdateProbes(uint3 GroupThreadId : SV_GroupThreadID, uint3 GroupId : SV_
float rayDistance = ProbesTrace[uint2(rayIndex, GroupId.x)].w;
CachedProbesTraceDistance[rayIndex] = min(abs(rayDistance), distanceLimit);
#endif
CachedProbesTraceDirection[rayIndex] = GetProbeRayDirection(DDGI, rayIndex);
CachedProbesTraceDirection[rayIndex] = GetProbeRayDirection(DDGI, rayIndex, probeRaysCount, probeIndex, probeCoords);
}
}
GroupMemoryBarrierWithGroupSync();

View File

@@ -3,6 +3,9 @@
#ifndef __MATH__
#define __MATH__
#define RadiansToDegrees (180.0f / PI)
#define DegreesToRadians (PI / 180.0f)
uint NextPow2(uint value)
{
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
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));
}
float4 QuaternionFromAxisAngle(float3 axis, float angle)
{
return float4(axis * sin(angle * 0.5f), cos(angle * 0.5f));
}
#endif