Add random per-probe rotation for rays tracing in DDGI
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -22,7 +22,6 @@ public:
|
||||
float ProbeHistoryWeight;
|
||||
float RayMaxDistance;
|
||||
float IndirectLightingIntensity;
|
||||
Float4 RaysRotation;
|
||||
Float3 ViewPos;
|
||||
uint32 RaysCount;
|
||||
Float3 FallbackIrradiance;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -32,7 +32,6 @@ struct DDGIData
|
||||
float ProbeHistoryWeight;
|
||||
float RayMaxDistance;
|
||||
float IndirectLightingIntensity;
|
||||
float4 RaysRotation;
|
||||
float3 ViewPos;
|
||||
uint RaysCount;
|
||||
float3 FallbackIrradiance;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user