// Copyright Epic Games, Inc. All Rights Reserved. /*============================================================================= LumenCardTiles.ush =============================================================================*/ #pragma once #include "/Engine/Shared/LumenDefinitions.h" #define CARD_TILE_SIZE 8 #define NULL_PACKED_CARD_TILE 0xFFFFFFFF struct FCardTileData { uint CardPageIndex; uint2 TileCoord; }; FCardTileData UnpackCardTileData(uint PackedTile) { FCardTileData TileData; TileData.CardPageIndex = PackedTile & 0xFFFFFF; TileData.TileCoord.x = (PackedTile >> 24) & 0xF; TileData.TileCoord.y = (PackedTile >> 28) & 0xF; return TileData; } uint PackCardTileData(FCardTileData CardTile) { uint PackedTile = CardTile.CardPageIndex; PackedTile |= (CardTile.TileCoord.x << 24); PackedTile |= (CardTile.TileCoord.y << 28); return PackedTile; } struct FLightTileForCompactionPass { uint LightIndex; uint ViewIndex; uint bHasShadowMask; uint CardTileIndex; uint CulledLightIndex; uint LightType; }; struct FLightTileForShadowMaskPass { uint LightIndex; uint ViewIndex; uint CardPageIndex; uint2 TileCoord; }; struct FLightTileForLightPass { uint LightIndex; uint ViewIndex; uint ShadowMaskIndex; }; FLightTileForCompactionPass UnpackLightTileForCompactionPass(uint2 PackedTile) { FLightTileForCompactionPass Tile; Tile.LightIndex = BitFieldExtractU32(PackedTile.x, 28, 0); Tile.ViewIndex = BitFieldExtractU32(PackedTile.x, 3, 28); Tile.bHasShadowMask = BitFieldExtractU32(PackedTile.x, 1, 31); Tile.CardTileIndex = BitFieldExtractU32(PackedTile.y, 24, 0); Tile.CulledLightIndex = BitFieldExtractU32(PackedTile.y, 6, 24); Tile.LightType = BitFieldExtractU32(PackedTile.y, 2, 30); return Tile; } FLightTileForShadowMaskPass UnpackLightTileForShadowMaskPass(uint2 PackedTile) { FLightTileForShadowMaskPass Tile; Tile.LightIndex = BitFieldExtractU32(PackedTile.x, 28, 0); Tile.ViewIndex = BitFieldExtractU32(PackedTile.x, 4, 28); Tile.CardPageIndex = BitFieldExtractU32(PackedTile.y, 24, 0); Tile.TileCoord.x = BitFieldExtractU32(PackedTile.y, 4, 24); Tile.TileCoord.y = BitFieldExtractU32(PackedTile.y, 4, 28); return Tile; } FLightTileForLightPass UnpackLightTileForLightPass(uint2 PackedTile) { FLightTileForLightPass Tile; Tile.LightIndex = BitFieldExtractU32(PackedTile.x, 28, 0); Tile.ViewIndex = BitFieldExtractU32(PackedTile.x, 4, 28); Tile.ShadowMaskIndex = PackedTile.y; return Tile; } uint2 PackLightTileForCompactionPass(FLightTileForCompactionPass Tile) { uint2 PackedTile; PackedTile.x = Tile.LightIndex | (Tile.ViewIndex << 28) | (Tile.bHasShadowMask << 31); PackedTile.y = Tile.CardTileIndex | (Tile.CulledLightIndex << 24) | (Tile.LightType << 30); return PackedTile; } uint2 PackLightTileForShadowMaskPass(FLightTileForShadowMaskPass Tile) { uint2 PackedTile; PackedTile.x = Tile.LightIndex | (Tile.ViewIndex << 28); PackedTile.y = Tile.CardPageIndex; PackedTile.y |= (Tile.TileCoord.x << 24); PackedTile.y |= (Tile.TileCoord.y << 28); return PackedTile; } uint2 PackLightTileForLightPass(FLightTileForLightPass Tile) { uint2 PackedTile; PackedTile.x = Tile.LightIndex | (Tile.ViewIndex << 28); PackedTile.y = Tile.ShadowMaskIndex; return PackedTile; } float4x4 FrustumTranslatedWorldToClip[LUMEN_MAX_VIEWS]; float4 PreViewTranslationHigh[LUMEN_MAX_VIEWS]; float4 PreViewTranslationLow[LUMEN_MAX_VIEWS]; float2 ViewExposure; FDFVector3 GetPreViewTranslation(uint ViewIndex) { return MakeDFVector3(PreViewTranslationHigh[ViewIndex].xyz, PreViewTranslationLow[ViewIndex].xyz); } uint GetCardViewIndex(FLumenCardPageData CardPage, FLumenCardData Card, float2 UVMin, float2 UVMax, float2 CardTileDepthRange, uint NumViews, bool bPrioritizeWhenInFrustum) { float3 CardPageLocalCenter; float3 CardPageLocalExtent; GetCardLocalBBox(CardPage, Card, UVMin, UVMax, CardTileDepthRange, CardPageLocalCenter, CardPageLocalExtent); uint ViewIndex = 0; if (NumViews > 1) { FDFVector3 PreViewTranslation0 = GetPreViewTranslation(0); FDFVector3 PreViewTranslation1 = GetPreViewTranslation(1); float3 CardTranslatedWorldOrigin0 = DFFastToTranslatedWorld(Card.Origin, PreViewTranslation0); float3 CardTranslatedWorldOrigin1 = DFFastToTranslatedWorld(Card.Origin, PreViewTranslation1); float View0Distance = length(CardTranslatedWorldOrigin0); float View1Distance = length(CardTranslatedWorldOrigin1); #define IN_FRUSTUM_DISTANCE 1 #if IN_FRUSTUM_DISTANCE float3 CardPageRotated = mul(Card.WorldToLocalRotation, CardPageLocalCenter); float3 CardPageTranslatedWorldCenter0 = CardPageRotated + CardTranslatedWorldOrigin0; float3 CardPageTranslatedWorldCenter1 = CardPageRotated + CardTranslatedWorldOrigin1; if (bPrioritizeWhenInFrustum) { float4 CardOriginClipSpace0 = mul(float4(CardPageTranslatedWorldCenter0, 1.0f), FrustumTranslatedWorldToClip[0]); if (all(CardOriginClipSpace0.xy >= CardOriginClipSpace0.w) && all(CardOriginClipSpace0.xy <= CardOriginClipSpace0.w) && CardOriginClipSpace0.z < 1.0f) { View0Distance = .5f * CardOriginClipSpace0.w; } float4 CardOriginClipSpace1 = mul(float4(CardPageTranslatedWorldCenter1, 1.0f), FrustumTranslatedWorldToClip[1]); if (all(CardOriginClipSpace1.xy >= CardOriginClipSpace1.w) && all(CardOriginClipSpace1.xy <= CardOriginClipSpace1.w) && CardOriginClipSpace1.z < 1.0f) { View1Distance = .5f * CardOriginClipSpace1.w; } } #endif ViewIndex = View0Distance < View1Distance ? 0 : 1; } return ViewIndex; }