388 lines
13 KiB
HLSL
388 lines
13 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "../OctahedralCommon.ush"
|
|
|
|
struct FLumenCardData
|
|
{
|
|
// OBB in MeshCards space
|
|
float3x3 MeshCardsToLocalRotation;
|
|
float3 MeshCardsOrigin;
|
|
float3 MeshCardsExtent;
|
|
|
|
// OBB in world space
|
|
float3x3 WorldToLocalRotation;
|
|
float3 Origin;
|
|
float3 LocalExtent;
|
|
|
|
uint2 SizeInPages;
|
|
uint PageTableOffset;
|
|
|
|
uint2 HiResSizeInPages;
|
|
uint HiResPageTableOffset;
|
|
|
|
// Convert Card's uint ResLevel (card's resolution) to uint2 ResLevelXY (each side's resolution)
|
|
uint2 ResLevelToResLevelXYBias;
|
|
|
|
bool bVisible;
|
|
bool bHeightfield;
|
|
uint AxisAlignedDirection;
|
|
uint LightingChannelMask;
|
|
|
|
// Average world space texel size of always resident pages
|
|
float TexelSize;
|
|
};
|
|
|
|
#if USE_LUMEN_CARD_DATA_BUFFER
|
|
StructuredBuffer<float4> LumenCardDataBuffer;
|
|
#else
|
|
#define LumenCardDataBuffer LumenCardScene.CardData
|
|
#endif
|
|
|
|
// Stride of a single cards's data in float4's, must match C++
|
|
#define LUMEN_CARD_DATA_STRIDE 10
|
|
#define LUMEN_CARD_PAGE_DATA_STRIDE 5
|
|
|
|
// Heightfields are a special case and they always have only one card
|
|
#define LUMEN_HEIGHTFIELD_LOCAL_CARD_INDEX 0
|
|
|
|
// Fetch from scene card buffer
|
|
// Note: layout must match FLumenCardData in C++
|
|
FLumenCardData GetLumenCardData(uint CardId)
|
|
{
|
|
FLumenCardData CardData = (FLumenCardData)0;
|
|
|
|
uint BaseOffset = CardId * LUMEN_CARD_DATA_STRIDE;
|
|
float4 Vector0 = LumenCardDataBuffer[BaseOffset + 0];
|
|
float4 Vector1 = LumenCardDataBuffer[BaseOffset + 1];
|
|
float4 Vector2 = LumenCardDataBuffer[BaseOffset + 2];
|
|
float4 Vector3 = LumenCardDataBuffer[BaseOffset + 3];
|
|
float4 Vector4 = LumenCardDataBuffer[BaseOffset + 4];
|
|
float4 Vector5 = LumenCardDataBuffer[BaseOffset + 5];
|
|
float4 Vector6 = LumenCardDataBuffer[BaseOffset + 6];
|
|
float4 Vector7 = LumenCardDataBuffer[BaseOffset + 7];
|
|
float4 Vector8 = LumenCardDataBuffer[BaseOffset + 8];
|
|
float4 Vector9 = LumenCardDataBuffer[BaseOffset + 9];
|
|
|
|
float3 PositionHigh = Vector0.xyz;
|
|
float3 PositionLow = float3(Vector1.w, Vector2.w, Vector3.w);
|
|
|
|
CardData.WorldToLocalRotation[0] = Vector1.xyz;
|
|
CardData.WorldToLocalRotation[1] = Vector2.xyz;
|
|
CardData.WorldToLocalRotation[2] = Vector3.xyz;
|
|
CardData.Origin = DFHackToFloat(MakeDFVector3(PositionHigh, PositionLow)); // LUMEN_LWC_TODO
|
|
|
|
CardData.LocalExtent = abs(Vector4.xyz);
|
|
|
|
uint Packed4W = asuint(Vector4.w);
|
|
CardData.ResLevelToResLevelXYBias.x = (Packed4W >> 0) & 0xFF;
|
|
CardData.ResLevelToResLevelXYBias.y = (Packed4W >> 8) & 0xFF;
|
|
CardData.AxisAlignedDirection = (Packed4W >> 16) & 0xF;
|
|
CardData.LightingChannelMask = (Packed4W >> 20) & 0xF;
|
|
CardData.bVisible = (Packed4W >> 24) & 1;
|
|
CardData.bHeightfield = (Packed4W >> 25) & 1;
|
|
|
|
CardData.SizeInPages.x = (asuint(Vector5.x) >> 0) & 0xFFFF;
|
|
CardData.SizeInPages.y = (asuint(Vector5.x) >> 16) & 0xFFFF;
|
|
CardData.PageTableOffset = asuint(Vector5.y);
|
|
CardData.HiResSizeInPages.x = (asuint(Vector5.z) >> 0) & 0xFFFF;
|
|
CardData.HiResSizeInPages.y = (asuint(Vector5.z) >> 16) & 0xFFFF;
|
|
CardData.HiResPageTableOffset = asuint(Vector5.w);
|
|
|
|
CardData.MeshCardsToLocalRotation[0] = Vector6.xyz;
|
|
CardData.MeshCardsToLocalRotation[1] = Vector7.xyz;
|
|
CardData.MeshCardsToLocalRotation[2] = Vector8.xyz;
|
|
CardData.MeshCardsOrigin = float3(Vector6.w, Vector7.w, Vector8.w);
|
|
CardData.MeshCardsExtent = Vector9.xyz;
|
|
CardData.TexelSize = Vector9.w;
|
|
|
|
return CardData;
|
|
}
|
|
|
|
struct FLumenCardPageData
|
|
{
|
|
uint CardIndex;
|
|
bool bMapped;
|
|
|
|
uint ResLevelPageTableOffset;
|
|
uint2 ResLevelSizeInTiles;
|
|
|
|
float2 SizeInTexels;
|
|
float2 PhysicalAtlasCoord;
|
|
|
|
float4 CardUVRect;
|
|
float4 PhysicalAtlasUVRect;
|
|
float2 CardUVTexelScale;
|
|
float2 PhysicalAtlasUVTexelScale;
|
|
|
|
uint LastDirectLightingUpdateFrameIndex;
|
|
uint LastIndirectLightingUpdateFrameIndex;
|
|
|
|
// Increments each time the page has Radiosity updated, needs to be consecutive for the sample pattern
|
|
uint IndirectLightingTemporalIndex;
|
|
// Increments each time the page has direct lighting updated. Only used to rotate through the texels in a quad when using adaptive shadow rays currently
|
|
uint DirectLightingTemporalIndex;
|
|
};
|
|
|
|
RWStructuredBuffer<float4> RWLumenCardPageDataBuffer;
|
|
#if USE_RW_LUMEN_CARD_PAGE_DATA_BUFFER
|
|
#define LumenCardPageDataBuffer RWLumenCardPageDataBuffer
|
|
#else
|
|
#define LumenCardPageDataBuffer LumenCardScene.CardPageData
|
|
#endif
|
|
|
|
// Note: layout must match FLumenCardPageData in C++
|
|
FLumenCardPageData GetLumenCardPageData(uint CardPageId)
|
|
{
|
|
FLumenCardPageData CardPageData = (FLumenCardPageData) 0;
|
|
|
|
uint BaseOffset = CardPageId * LUMEN_CARD_PAGE_DATA_STRIDE;
|
|
float4 Vector0 = LumenCardPageDataBuffer[BaseOffset + 0];
|
|
float4 Vector1 = LumenCardPageDataBuffer[BaseOffset + 1];
|
|
float4 Vector2 = LumenCardPageDataBuffer[BaseOffset + 2];
|
|
float4 Vector3 = LumenCardPageDataBuffer[BaseOffset + 3];
|
|
float4 Vector4 = LumenCardPageDataBuffer[BaseOffset + 4];
|
|
|
|
CardPageData.CardIndex = asuint(Vector0.x);
|
|
CardPageData.ResLevelPageTableOffset = asuint(Vector0.y);
|
|
CardPageData.SizeInTexels = Vector0.zw;
|
|
CardPageData.CardUVRect = Vector1;
|
|
CardPageData.PhysicalAtlasUVRect = Vector2;
|
|
CardPageData.CardUVTexelScale = Vector3.xy;
|
|
CardPageData.ResLevelSizeInTiles = asuint(Vector3.zw);
|
|
|
|
CardPageData.LastDirectLightingUpdateFrameIndex = asuint(Vector4.x);
|
|
CardPageData.LastIndirectLightingUpdateFrameIndex = asuint(Vector4.y);
|
|
CardPageData.IndirectLightingTemporalIndex = asuint(Vector4.z);
|
|
CardPageData.DirectLightingTemporalIndex = asuint(Vector4.w);
|
|
|
|
// Derived properties
|
|
CardPageData.bMapped = CardPageData.SizeInTexels.x > 0;
|
|
CardPageData.PhysicalAtlasCoord = CardPageData.PhysicalAtlasUVRect.xy * LumenCardScene.PhysicalAtlasSize;
|
|
CardPageData.PhysicalAtlasUVTexelScale = LumenCardScene.InvPhysicalAtlasSize;
|
|
|
|
return CardPageData;
|
|
}
|
|
|
|
// Store only card page update data
|
|
void SetCardPageUpdateData(uint CardPageId, FLumenCardPageData CardPageData)
|
|
{
|
|
// Note: layout must match FLumenCardPageData in C++
|
|
|
|
uint4 Vector4;
|
|
Vector4.x = CardPageData.LastDirectLightingUpdateFrameIndex;
|
|
Vector4.y = CardPageData.LastIndirectLightingUpdateFrameIndex;
|
|
Vector4.z = CardPageData.IndirectLightingTemporalIndex;
|
|
Vector4.w = CardPageData.DirectLightingTemporalIndex;
|
|
|
|
uint BaseOffset = CardPageId * LUMEN_CARD_PAGE_DATA_STRIDE;
|
|
RWLumenCardPageDataBuffer[BaseOffset + 4] = asfloat(Vector4);
|
|
}
|
|
|
|
struct FCardVSToPS
|
|
{
|
|
float2 AtlasUV : ATTRIBUTE0;
|
|
float2 IndirectLightingAtlasUV : ATTRIBUTE1;
|
|
float2 CardUV : ATTRIBUTE2;
|
|
nointerpolation uint CardTileIndex : CARD_TILE_INDEX;
|
|
nointerpolation uint CardPageIndex : CARD_PAGE_INDEX;
|
|
};
|
|
|
|
// Stride of mesh cards data, must match C++
|
|
#define LUMEN_MESH_CARDS_DATA_STRIDE 6
|
|
#define LUMEN_INVALID_CARD_INDEX 0xFFFFFFFF
|
|
#define LUMEN_INVALID_HEIGHTFIELD_OBJECT_INDEX 0xFFFFFFFF
|
|
#define LUMEN_INVALID_MESH_CARDS_INDEX 0xFFFFFFFF
|
|
#define LUMEN_INVALID_SCENE_INSTANCE_INDEX 0xFFFFFFFF
|
|
|
|
struct FLumenMeshCardsData
|
|
{
|
|
float3 WorldOrigin;
|
|
float3x3 WorldToLocalRotation;
|
|
|
|
uint NumCards;
|
|
uint CardOffset;
|
|
|
|
bool bHeightfield;
|
|
bool bMostlyTwoSided;
|
|
|
|
uint CardLookup[6];
|
|
};
|
|
|
|
// Note: layout must match FLumenMeshCardsData in C++
|
|
FLumenMeshCardsData GetLumenMeshCardsData(uint MeshCardsId)
|
|
{
|
|
uint BaseOffset = MeshCardsId * LUMEN_MESH_CARDS_DATA_STRIDE;
|
|
|
|
FLumenMeshCardsData MeshCardsData;
|
|
|
|
float4 V0 = LumenCardScene.MeshCardsData[BaseOffset + 0];
|
|
float4 V1 = LumenCardScene.MeshCardsData[BaseOffset + 1];
|
|
float4 V2 = LumenCardScene.MeshCardsData[BaseOffset + 2];
|
|
float4 V3 = LumenCardScene.MeshCardsData[BaseOffset + 3];
|
|
|
|
float3 PositionHigh = V0.xyz;
|
|
float3 PositionLow = float3(V1.w, V2.w, V3.w);
|
|
|
|
MeshCardsData.WorldToLocalRotation[0] = V1.xyz;
|
|
MeshCardsData.WorldToLocalRotation[1] = V2.xyz;
|
|
MeshCardsData.WorldToLocalRotation[2] = V3.xyz;
|
|
MeshCardsData.WorldOrigin = DFHackToFloat(MakeDFVector3(PositionHigh, PositionLow)); // LUMEN_LWC_TODO
|
|
|
|
uint4 V4 = asuint(LumenCardScene.MeshCardsData[BaseOffset + 4]);
|
|
uint4 V5 = asuint(LumenCardScene.MeshCardsData[BaseOffset + 5]);
|
|
|
|
MeshCardsData.CardOffset = V4.x;
|
|
MeshCardsData.NumCards = V4.y & 0xFFFF;
|
|
MeshCardsData.bHeightfield = V4.y & 0x10000 ? true : false;
|
|
MeshCardsData.bMostlyTwoSided = V4.y & 0x20000 ? true : false;
|
|
MeshCardsData.CardLookup[0] = V4.z;
|
|
MeshCardsData.CardLookup[1] = V4.w;
|
|
MeshCardsData.CardLookup[2] = V5.x;
|
|
MeshCardsData.CardLookup[3] = V5.y;
|
|
MeshCardsData.CardLookup[4] = V5.z;
|
|
MeshCardsData.CardLookup[5] = V5.w;
|
|
|
|
return MeshCardsData;
|
|
}
|
|
|
|
// Stride of mesh cards data, must match C++
|
|
#define LUMEN_HEIGHTFIELD_DATA_STRIDE 3
|
|
|
|
struct FLumenHeightfieldData
|
|
{
|
|
FDFVector3 BoundsCenter; // World space AABB center
|
|
float3 BoundsExtent; // World space AABB extent
|
|
uint MeshCardsIndex;
|
|
bool bValid;
|
|
};
|
|
|
|
// Note: layout must match FLumenHeightfieldData in C++
|
|
FLumenHeightfieldData GetLumenHeightfieldData(uint HeightfieldId)
|
|
{
|
|
uint BaseOffset = HeightfieldId * LUMEN_HEIGHTFIELD_DATA_STRIDE;
|
|
|
|
FLumenHeightfieldData LumenHeightfield;
|
|
|
|
float4 V0 = LumenCardScene.HeightfieldData[BaseOffset + 0];
|
|
float4 V1 = LumenCardScene.HeightfieldData[BaseOffset + 1];
|
|
float4 V2 = LumenCardScene.HeightfieldData[BaseOffset + 2];
|
|
|
|
LumenHeightfield.BoundsCenter = MakeDFVector3(V0.xyz, V1.xyz);
|
|
LumenHeightfield.BoundsExtent = V2.xyz;
|
|
|
|
LumenHeightfield.MeshCardsIndex = asuint(V0.w);
|
|
LumenHeightfield.bValid = LumenHeightfield.MeshCardsIndex < LumenCardScene.NumMeshCards;
|
|
|
|
return LumenHeightfield;
|
|
}
|
|
|
|
float3 GetCardLocalPosition(float3 CardLocalExtent, float2 CardUV, float Depth)
|
|
{
|
|
CardUV.x = 1.0f - CardUV.x;
|
|
|
|
float3 LocalPosition;
|
|
LocalPosition.xy = CardLocalExtent.xy * (1.0f - 2.0f * CardUV);
|
|
LocalPosition.z = -(2.0f * Depth - 1.0f) * CardLocalExtent.z;
|
|
|
|
return LocalPosition;
|
|
}
|
|
|
|
void GetCardLocalBBox(FLumenCardPageData CardPage, FLumenCardData Card, float2 UVMin, float2 UVMax, float2 CardTileDepthRange, out float3 CardPageLocalCenter, out float3 CardPageLocalExtent)
|
|
{
|
|
float2 CardUVMin = lerp(CardPage.CardUVRect.xw, CardPage.CardUVRect.zy, UVMin);
|
|
float2 CardUVMax = lerp(CardPage.CardUVRect.xw, CardPage.CardUVRect.zy, UVMax);
|
|
float3 CardPageLocalBoxMin = GetCardLocalPosition(Card.LocalExtent, CardUVMin, CardTileDepthRange.y);
|
|
float3 CardPageLocalBoxMax = GetCardLocalPosition(Card.LocalExtent, CardUVMax, CardTileDepthRange.x);
|
|
|
|
CardPageLocalCenter = 0.5f * (CardPageLocalBoxMax + CardPageLocalBoxMin);
|
|
CardPageLocalExtent = 0.5f * (CardPageLocalBoxMax - CardPageLocalBoxMin);
|
|
}
|
|
|
|
void GetCardLocalBBox(FLumenCardPageData CardPage, FLumenCardData Card, float2 UVMin, float2 UVMax, out float3 CardPageLocalCenter, out float3 CardPageLocalExtent)
|
|
{
|
|
GetCardLocalBBox(CardPage, Card, UVMin, UVMax, float2(0, 1), CardPageLocalCenter, CardPageLocalExtent);
|
|
}
|
|
|
|
void GetCardPageLocalBBox(FLumenCardPageData CardPage, FLumenCardData Card, out float3 CardPageLocalCenter, out float3 CardPageLocalExtent)
|
|
{
|
|
GetCardLocalBBox(CardPage, Card, 0, 1, float2(0, 1), CardPageLocalCenter, CardPageLocalExtent);
|
|
}
|
|
|
|
float3 GetCardWorldPosition(FLumenCardData Card, float2 CardUV, float Depth)
|
|
{
|
|
float3 LocalPosition = GetCardLocalPosition(Card.LocalExtent, CardUV, Depth);
|
|
float3 WorldPosition = mul(Card.WorldToLocalRotation, LocalPosition) + Card.Origin;
|
|
return WorldPosition;
|
|
}
|
|
|
|
uint2 GetCardPageSizeInTexels(FLumenCardPageData CardPage, uint2 AtlasSize)
|
|
{
|
|
float2 AtlasSizeInUV = CardPage.PhysicalAtlasUVRect.zw - CardPage.PhysicalAtlasUVRect.xy;
|
|
return uint2(AtlasSizeInUV * AtlasSize);
|
|
}
|
|
|
|
float2 CardPageUVToCardUV(FLumenCardPageData CardPage, float2 CardPageUV)
|
|
{
|
|
float2 CardUV = lerp(CardPage.CardUVRect.xy, CardPage.CardUVRect.zw, CardPageUV);
|
|
return CardUV;
|
|
}
|
|
|
|
float2 CardPageUVToAtlasUV(FLumenCardPageData CardPage, float2 CardPageUV)
|
|
{
|
|
float2 AtlasUV = lerp(CardPage.PhysicalAtlasUVRect.xy, CardPage.PhysicalAtlasUVRect.zw, CardPageUV);
|
|
return AtlasUV;
|
|
}
|
|
|
|
float2 SamplePositonToCardUV(FLumenCardData Card, float2 LocalSamplePosition)
|
|
{
|
|
float2 CardUV = saturate(float2(+0.5f, -0.5f) * (LocalSamplePosition / Card.LocalExtent.xy) + 0.5f);
|
|
return CardUV;
|
|
}
|
|
|
|
uint GetMeshCardsIndexFromSceneInstanceIndex(uint SceneInstanceIndex)
|
|
{
|
|
const uint MeshCardsIndex = LumenCardScene.SceneInstanceIndexToMeshCardsIndexBuffer.Load(4 * SceneInstanceIndex);
|
|
return MeshCardsIndex;
|
|
}
|
|
|
|
struct FLumenSceneDebugData
|
|
{
|
|
bool bValid;
|
|
uint MeshIndex;
|
|
uint CardIndex;
|
|
uint CardPageIndex;
|
|
float2 PhysicalAtlasUV;
|
|
};
|
|
|
|
FLumenSceneDebugData InitLumenSceneDebugData()
|
|
{
|
|
FLumenSceneDebugData Out = (FLumenSceneDebugData)0;
|
|
Out.MeshIndex = LUMEN_INVALID_MESH_CARDS_INDEX;
|
|
Out.CardIndex = LUMEN_INVALID_CARD_INDEX;
|
|
Out.CardPageIndex = LUMEN_INVALID_CARD_INDEX;
|
|
Out.bValid = false;
|
|
return Out;
|
|
}
|
|
|
|
void WriteDebugData(FLumenSceneDebugData In, RWStructuredBuffer<uint> OutBuffer)
|
|
{
|
|
OutBuffer[0] = In.CardIndex;
|
|
OutBuffer[1] = In.CardPageIndex;
|
|
OutBuffer[2] = asuint(In.PhysicalAtlasUV.x);
|
|
OutBuffer[3] = asuint(In.PhysicalAtlasUV.y);
|
|
OutBuffer[4] = In.MeshIndex;
|
|
}
|
|
|
|
FLumenSceneDebugData ReadDebugData(StructuredBuffer<uint> InBuffer)
|
|
{
|
|
FLumenSceneDebugData Out;
|
|
Out.CardIndex = InBuffer[0];
|
|
Out.CardPageIndex = InBuffer[1];
|
|
Out.PhysicalAtlasUV = float2(asfloat(InBuffer[2]), asfloat(InBuffer[3]));
|
|
Out.MeshIndex = InBuffer[4];
|
|
|
|
Out.bValid = Out.CardIndex != LUMEN_INVALID_CARD_INDEX;
|
|
return Out;
|
|
} |