Improve Global Surface Atlas objects surfaces sampling

This commit is contained in:
Wojciech Figat
2022-06-30 15:14:43 +02:00
parent db284c58a3
commit 27515585db
6 changed files with 48 additions and 61 deletions

Binary file not shown.

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

Binary file not shown.

View File

@@ -461,7 +461,7 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext,
ddgiData.Result.Constants.ProbesOriginAndSpacing[cascadeIndex] = Float4(cascade.ProbesOrigin, cascade.ProbesSpacing); ddgiData.Result.Constants.ProbesOriginAndSpacing[cascadeIndex] = Float4(cascade.ProbesOrigin, cascade.ProbesSpacing);
ddgiData.Result.Constants.ProbesScrollOffsets[cascadeIndex] = Int4(cascade.ProbeScrollOffsets, 0); ddgiData.Result.Constants.ProbesScrollOffsets[cascadeIndex] = Int4(cascade.ProbeScrollOffsets, 0);
} }
ddgiData.Result.Constants.RayMaxDistance = 10000.0f; // TODO: adjust to match perf/quality ratio (make it based on Global SDF and Global Surface Atlas distance) ddgiData.Result.Constants.RayMaxDistance = distance;
ddgiData.Result.Constants.ViewPos = renderContext.View.Position; ddgiData.Result.Constants.ViewPos = renderContext.View.Position;
ddgiData.Result.Constants.RaysCount = probeRaysCount; ddgiData.Result.Constants.RaysCount = probeRaysCount;
ddgiData.Result.Constants.ProbeHistoryWeight = probeHistoryWeight; ddgiData.Result.Constants.ProbeHistoryWeight = probeHistoryWeight;

View File

@@ -1232,19 +1232,20 @@ void GlobalSurfaceAtlasPass::RasterizeActor(Actor* actor, void* actorObject, con
_dirtyObjectsBuffer.Add(actorObject); _dirtyObjectsBuffer.Add(actorObject);
} }
Matrix3x3 worldToLocalRotation;
Matrix3x3::RotationQuaternion(object->Bounds.Transformation.Orientation.Conjugated(), worldToLocalRotation);
Float3 worldPosition = object->Bounds.Transformation.Translation;
Float3 worldExtents = object->Bounds.Extents * object->Bounds.Transformation.Scale;
// Write to objects buffer (this must match unpacking logic in HLSL) // Write to objects buffer (this must match unpacking logic in HLSL)
Matrix localToWorldBounds;
object->Bounds.Transformation.GetWorld(localToWorldBounds);
Matrix worldToLocalBounds;
Matrix::Invert(localToWorldBounds, worldToLocalBounds);
uint32 objectAddress = surfaceAtlasData.ObjectsBuffer.Data.Count() / sizeof(Float4); uint32 objectAddress = surfaceAtlasData.ObjectsBuffer.Data.Count() / sizeof(Float4);
auto* objectData = surfaceAtlasData.ObjectsBuffer.WriteReserve<Float4>(GLOBAL_SURFACE_ATLAS_OBJECT_DATA_STRIDE); auto* objectData = surfaceAtlasData.ObjectsBuffer.WriteReserve<Float4>(GLOBAL_SURFACE_ATLAS_OBJECT_DATA_STRIDE);
objectData[0] = *(Float4*)&actorObjectBounds; objectData[0] = *(Float4*)&actorObjectBounds;
objectData[1] = Float4::Zero; objectData[1] = Float4::Zero;
objectData[2] = Float4(worldToLocalBounds.M11, worldToLocalBounds.M12, worldToLocalBounds.M13, worldToLocalBounds.M41); objectData[2] = Float4(worldToLocalRotation.M11, worldToLocalRotation.M12, worldToLocalRotation.M13, worldPosition.X);
objectData[3] = Float4(worldToLocalBounds.M21, worldToLocalBounds.M22, worldToLocalBounds.M23, worldToLocalBounds.M42); objectData[3] = Float4(worldToLocalRotation.M21, worldToLocalRotation.M22, worldToLocalRotation.M23, worldPosition.Y);
objectData[4] = Float4(worldToLocalBounds.M31, worldToLocalBounds.M32, worldToLocalBounds.M33, worldToLocalBounds.M43); objectData[4] = Float4(worldToLocalRotation.M31, worldToLocalRotation.M32, worldToLocalRotation.M33, worldPosition.Z);
objectData[5] = Float4(object->Bounds.Extents, useVisibility ? 1.0f : 0.0f); objectData[5] = Float4(worldExtents, useVisibility ? 1.0f : 0.0f);
auto tileOffsets = reinterpret_cast<uint16*>(&objectData[1]); // xyz used for tile offsets packed into uint16 auto tileOffsets = reinterpret_cast<uint16*>(&objectData[1]); // xyz used for tile offsets packed into uint16
auto objectDataSize = reinterpret_cast<uint32*>(&objectData[1].W); // w used for object size (count of Float4s for object+tiles) auto objectDataSize = reinterpret_cast<uint32*>(&objectData[1].W); // w used for object size (count of Float4s for object+tiles)
*objectDataSize = GLOBAL_SURFACE_ATLAS_OBJECT_DATA_STRIDE; *objectDataSize = GLOBAL_SURFACE_ATLAS_OBJECT_DATA_STRIDE;

View File

@@ -414,10 +414,6 @@ void CS_UpdateProbes(uint3 GroupThreadId : SV_GroupThreadID, uint3 GroupId : SV_
// Reduce flickering during rapid brightness changes // Reduce flickering during rapid brightness changes
//result.rgb = previous + (irradianceDelta * 0.25f); //result.rgb = previous + (irradianceDelta * 0.25f);
} }
float3 resultDelta = (1.0f - historyWeight) * irradianceDelta;
if (Max3(result.rgb) < Max3(previous))
resultDelta = min(max(abs(resultDelta), 1.0f / 1024.0f), abs(irradianceDelta)) * sign(resultDelta);
//result = float4(previous + resultDelta, 1.0f);
result = float4(lerp(result.rgb, previous.rgb, historyWeight), 1.0f); result = float4(lerp(result.rgb, previous.rgb, historyWeight), 1.0f);
#else #else
result = float4(lerp(result.rg, previous.rg, historyWeight), 0.0f, 1.0f); result = float4(lerp(result.rg, previous.rg, historyWeight), 0.0f, 1.0f);

View File

@@ -23,8 +23,9 @@ struct GlobalSurfaceObject
{ {
float3 BoundsPosition; float3 BoundsPosition;
float BoundsRadius; float BoundsRadius;
float4x4 WorldToLocal; float3x3 WorldToLocalRotation;
float3 Extent; float3 WorldPosition;
float3 WorldExtents;
bool UseVisibility; bool UseVisibility;
uint TileOffsets[6]; uint TileOffsets[6];
uint DataSize; // count of float4s for object+tiles uint DataSize; // count of float4s for object+tiles
@@ -54,11 +55,11 @@ GlobalSurfaceObject LoadGlobalSurfaceAtlasObject(Buffer<float4> objects, uint ob
GlobalSurfaceObject object = (GlobalSurfaceObject)0; GlobalSurfaceObject object = (GlobalSurfaceObject)0;
object.BoundsPosition = vector0.xyz; object.BoundsPosition = vector0.xyz;
object.BoundsRadius = vector0.w; object.BoundsRadius = vector0.w;
object.WorldToLocal[0] = float4(vector2.xyz, 0.0f); object.WorldToLocalRotation[0] = vector2.xyz;
object.WorldToLocal[1] = float4(vector3.xyz, 0.0f); object.WorldToLocalRotation[1] = vector3.xyz;
object.WorldToLocal[2] = float4(vector4.xyz, 0.0f); object.WorldToLocalRotation[2] = vector4.xyz;
object.WorldToLocal[3] = float4(vector2.w, vector3.w, vector4.w, 1.0f); object.WorldPosition = float3(vector2.w, vector3.w, vector4.w);
object.Extent = vector5.xyz; object.WorldExtents = vector5.xyz;
object.UseVisibility = vector5.w > 0.5f; object.UseVisibility = vector5.w > 0.5f;
uint vector1x = asuint(vector1.x); uint vector1x = asuint(vector1.x);
uint vector1y = asuint(vector1.y); uint vector1y = asuint(vector1.y);
@@ -198,47 +199,36 @@ float4 SampleGlobalSurfaceAtlas(const GlobalSurfaceAtlasData data, ByteAddressBu
float4 objectBounds = LoadGlobalSurfaceAtlasObjectBounds(objects, objectAddress); float4 objectBounds = LoadGlobalSurfaceAtlasObjectBounds(objects, objectAddress);
if (distance(objectBounds.xyz, worldPosition) > objectBounds.w) if (distance(objectBounds.xyz, worldPosition) > objectBounds.w)
continue; continue;
GlobalSurfaceObject object = LoadGlobalSurfaceAtlasObject(objects, objectAddress);
float3 localPosition = mul(float4(worldPosition, 1), object.WorldToLocal).xyz;
float3 localExtent = object.Extent + surfaceThreshold;
if (any(localPosition > localExtent) || any(localPosition < -localExtent))
continue;
// Remove the scale vector from the transformation matrix // Cull point vs box
float3x3 worldToLocal = (float3x3)object.WorldToLocal; GlobalSurfaceObject object = LoadGlobalSurfaceAtlasObject(objects, objectAddress);
float scaleX = length(worldToLocal[0]); float3 localPosition = mul(worldPosition - object.WorldPosition, object.WorldToLocalRotation);
float scaleY = length(worldToLocal[1]); float3 localExtents = object.WorldExtents + surfaceThreshold;
float scaleZ = length(worldToLocal[2]); if (any(abs(localPosition) > localExtents))
float3 invScale = float3( continue;
scaleX > 0.00001f ? 1.0f / scaleX : 0.0f,
scaleY > 0.00001f ? 1.0f / scaleY : 0.0f,
scaleZ > 0.00001f ? 1.0f / scaleZ : 0.0f);
worldToLocal[0] *= invScale.x;
worldToLocal[1] *= invScale.y;
worldToLocal[2] *= invScale.z;
// Sample tiles based on the directionality // Sample tiles based on the directionality
#if GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD_ENABLED #if GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD_ENABLED
float3 localNormal = normalize(mul(worldNormal, worldToLocal)); float3 localNormal = mul(worldNormal, object.WorldToLocalRotation);
float3 localNormalSq = localNormal * localNormal; float3 localNormalSq = localNormal * localNormal;
uint tileOffset = object.TileOffsets[localNormal.x > 0.0f ? 0 : 1]; uint tileOffset = object.TileOffsets[localNormal.x > 0.0f ? 0 : 1];
if (localNormalSq.x > GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD * GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD && tileOffset != 0) if (localNormalSq.x > GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD * GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD && tileOffset != 0)
{ {
GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(objects, objectAddress + tileOffset); GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(objects, objectAddress + tileOffset);
result += SampleGlobalSurfaceAtlasTile(data, object, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold); result += SampleGlobalSurfaceAtlasTile(data, object, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold);
} }
tileOffset = object.TileOffsets[localNormal.y > 0.0f ? 2 : 3]; tileOffset = object.TileOffsets[localNormal.y > 0.0f ? 2 : 3];
if (localNormalSq.y > GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD * GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD && tileOffset != 0) if (localNormalSq.y > GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD * GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD && tileOffset != 0)
{ {
GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(objects, objectAddress + tileOffset); GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(objects, objectAddress + tileOffset);
result += SampleGlobalSurfaceAtlasTile(data, object, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold); result += SampleGlobalSurfaceAtlasTile(data, object, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold);
} }
tileOffset = object.TileOffsets[localNormal.z > 0.0f ? 4 : 5]; tileOffset = object.TileOffsets[localNormal.z > 0.0f ? 4 : 5];
if (localNormalSq.z > GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD * GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD && tileOffset != 0) if (localNormalSq.z > GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD * GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD && tileOffset != 0)
{ {
GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(objects, objectAddress + tileOffset); GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(objects, objectAddress + tileOffset);
result += SampleGlobalSurfaceAtlasTile(data, object, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold); result += SampleGlobalSurfaceAtlasTile(data, object, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold);
} }
#else #else
uint tileOffset = object.TileOffsets[0]; uint tileOffset = object.TileOffsets[0];
if (tileOffset != 0) if (tileOffset != 0)