Files
UnrealEngine/Engine/Shaders/Private/Lumen/LumenScene.usf
2025-05-18 13:04:45 +08:00

193 lines
6.1 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#include "../Common.ush"
#include "../ShaderPrint.ush"
#define MAX_LUMEN_VIEWS 2
#define LUMEN_INVALID_MESH_CARDS_INDEX 0xFFFFFFFF
#define FLOAT_32_MAX float(+3.402823466e+38f)
struct FLumenPrimitiveGroupData
{
float3 WorldSpaceBoundingBoxCenter;
float3 WorldSpaceBoundingBoxExtent;
uint MeshCardsIndex;
bool bValid;
bool bValidMeshCards;
bool bFarField;
bool bHeightfield;
bool bEmissiveLightSource;
};
// Stride of a single PrimitiveGroup in float4's, must match C++
#define LUMEN_PRIMITIVE_GROUP_DATA_STRIDE 2
// Layout must match FLumenPrimitiveGroup in C++
FLumenPrimitiveGroupData GetLumenPrimitiveGroupData(uint PrimitiveGroupId)
{
FLumenPrimitiveGroupData PrimitiveGroup = (FLumenPrimitiveGroupData)0;
const uint BaseOffset = PrimitiveGroupId * LUMEN_PRIMITIVE_GROUP_DATA_STRIDE;
const float4 V0 = LumenCardScene.PrimitiveGroupData[BaseOffset + 0];
const float4 V1 = LumenCardScene.PrimitiveGroupData[BaseOffset + 1];
PrimitiveGroup.WorldSpaceBoundingBoxCenter = V0.xyz;
PrimitiveGroup.WorldSpaceBoundingBoxExtent = V1.xyz;
PrimitiveGroup.MeshCardsIndex = asuint(V0.w);
const uint Flags = asuint(V1.w);
PrimitiveGroup.bValid = all(PrimitiveGroup.WorldSpaceBoundingBoxExtent > 0.0f);
PrimitiveGroup.bValidMeshCards = Flags & 0x01 ? true : false;
PrimitiveGroup.bFarField = Flags & 0x02 ? true : false;
PrimitiveGroup.bHeightfield = Flags & 0x04 ? true : false;
PrimitiveGroup.bEmissiveLightSource = Flags & 0x08 ? true : false;
return PrimitiveGroup;
}
RWStructuredBuffer<uint2> RWSceneAddOps;
uint MaxSceneAddOps;
RWStructuredBuffer<uint> RWSceneRemoveOps;
uint MaxSceneRemoveOps;
float4 WorldCameraOrigins[MAX_LUMEN_VIEWS];
uint NumCameraOrigins;
float CardMaxDistanceSq;
float CardTexelDensity;
float FarFieldCardMaxDistanceSq;
float FarFieldCardTexelDensity;
float MinCardResolution;
/**
* Loop over all Lumen Primitive Groups in order to find which ones should be visible and spawn mesh cards.
*/
[numthreads(THREADGROUP_SIZE, 1, 1)]
void LumenSceneUpdateCS(
uint3 GroupId : SV_GroupID,
uint3 GroupThreadId : SV_GroupThreadID,
uint3 DispatchThreadId : SV_DispatchThreadID)
{
const uint PrimitiveGroupIndex = DispatchThreadId.x;
if (PrimitiveGroupIndex < LumenCardScene.NumPrimitiveGroups)
{
FLumenPrimitiveGroupData PrimitiveGroup = GetLumenPrimitiveGroupData(PrimitiveGroupIndex);
if (PrimitiveGroup.bValid)
{
float DistanceSquared = FLOAT_32_MAX;
for (uint ViewIndex = 0; ViewIndex < NumCameraOrigins; ++ViewIndex)
{
DistanceSquared = ComputeSquaredDistanceFromBoxToPoint(PrimitiveGroup.WorldSpaceBoundingBoxCenter, PrimitiveGroup.WorldSpaceBoundingBoxExtent, WorldCameraOrigins[ViewIndex].xyz);
}
float PrimitiveGroupMaxCardExtent = max3(PrimitiveGroup.WorldSpaceBoundingBoxExtent.x, PrimitiveGroup.WorldSpaceBoundingBoxExtent.y, PrimitiveGroup.WorldSpaceBoundingBoxExtent.z);
float PrimitiveGroupMaxCardResolution = (CardTexelDensity * PrimitiveGroupMaxCardExtent) / sqrt(max(DistanceSquared, 1.0f)) + 0.01f;
float PrimitiveGroupMaxCardDistanceSq = CardMaxDistanceSq;
// Far field cards have constant resolution over entire range
if (PrimitiveGroup.bFarField)
{
PrimitiveGroupMaxCardDistanceSq = FarFieldCardMaxDistanceSq;
PrimitiveGroupMaxCardResolution = PrimitiveGroupMaxCardExtent * FarFieldCardTexelDensity;
}
if (DistanceSquared <= PrimitiveGroupMaxCardDistanceSq && PrimitiveGroupMaxCardResolution >= (PrimitiveGroup.bEmissiveLightSource ? 1.0f : MinCardResolution))
{
if (PrimitiveGroup.MeshCardsIndex == LUMEN_INVALID_MESH_CARDS_INDEX && PrimitiveGroup.bValidMeshCards)
{
uint ElementIndex = 0;
InterlockedAdd(RWSceneAddOps[0].x, 1, ElementIndex);
if (ElementIndex + 1 < MaxSceneAddOps)
{
RWSceneAddOps[ElementIndex + 1] = uint2(PrimitiveGroupIndex, asuint(DistanceSquared));
}
}
}
else if (PrimitiveGroup.MeshCardsIndex != LUMEN_INVALID_MESH_CARDS_INDEX)
{
uint ElementIndex = 0;
InterlockedAdd(RWSceneRemoveOps[0], 1, ElementIndex);
if (ElementIndex + 1 < MaxSceneRemoveOps)
{
RWSceneRemoveOps[ElementIndex + 1] = PrimitiveGroupIndex;
}
}
}
}
}
/**
* Visualize GPU side primitive groups data
*/
[numthreads(THREADGROUP_SIZE, 1, 1)]
void VisualizePrimitiveGroupsCS(
uint3 GroupId : SV_GroupID,
uint3 GroupThreadId : SV_GroupThreadID,
uint3 DispatchThreadId : SV_DispatchThreadID)
{
FShaderPrintContext Context = InitShaderPrintContext(true, float2(0.1, 0.1));
const uint PrimitiveGroupIndex = DispatchThreadId.x;
if (PrimitiveGroupIndex < LumenCardScene.NumPrimitiveGroups)
{
FLumenPrimitiveGroupData PrimitiveGroup = GetLumenPrimitiveGroupData(PrimitiveGroupIndex);
if (PrimitiveGroup.bValid && PrimitiveGroup.MeshCardsIndex != LUMEN_INVALID_MESH_CARDS_INDEX)
{
float3 BoxMin = PrimitiveGroup.WorldSpaceBoundingBoxCenter - PrimitiveGroup.WorldSpaceBoundingBoxExtent;
float3 BoxMax = PrimitiveGroup.WorldSpaceBoundingBoxCenter + PrimitiveGroup.WorldSpaceBoundingBoxExtent;
float4 BoxColor = float4(1, 1, 1, 1);
AddAABB(Context, BoxMin, BoxMax, BoxColor);
}
}
}
StructuredBuffer<uint2> SceneAddOps;
StructuredBuffer<uint> SceneRemoveOps;
/**
* Debug stats for debugging Lumen Scene and its GPU driven updates
*/
[numthreads(THREADGROUP_SIZE, 1, 1)]
void LumenSceneStatsCS(
uint3 GroupId : SV_GroupID,
uint3 GroupThreadId : SV_GroupThreadID,
uint3 DispatchThreadId : SV_DispatchThreadID)
{
FShaderPrintContext Context = InitShaderPrintContext(true, float2(0.1, 0.1));
if (all(DispatchThreadId == 0))
{
Print(Context, TEXT("NumPrimitiveGroups "));
Print(Context, LumenCardScene.NumPrimitiveGroups);
Newline(Context);
Print(Context, TEXT("NumMeshCards "));
Print(Context, LumenCardScene.NumMeshCards);
Newline(Context);
Print(Context, TEXT("NumCards "));
Print(Context, LumenCardScene.NumCards);
Newline(Context);
Print(Context, TEXT("AddOps "));
for (uint Index = 0; Index < 8; ++Index)
{
Print(Context, SceneAddOps[Index].x);
}
Newline(Context);
Print(Context, TEXT("RemoveOps "));
for (uint Index = 0; Index < 8; ++Index)
{
Print(Context, SceneRemoveOps[Index].x);
}
}
}