// Copyright Epic Games, Inc. All Rights Reserved. /*============================================================================= LightSceneInfo.h: Light scene info definitions. =============================================================================*/ #pragma once #include "CoreTypes.h" #include "Math/Color.h" #include "Math/GenericOctree.h" #include "Math/GenericOctreePublic.h" #include "Math/UnrealMath.h" #include "PrimitiveSceneProxy.h" #include "SceneTypes.h" #include "SceneView.h" class FLightPrimitiveInteraction; class FLightSceneInfo; class FMobileMovableLocalLightShadowParameters; class FPrimitiveSceneInfoCompact; class FPrimitiveSceneProxy; class FScene; class FViewInfo; class FVisibleLightInfo; namespace ECastRayTracedShadow { enum Type : int; } /** * The information needed to cull a light-primitive interaction. */ class FLightSceneInfoCompact { public: // XYZ: origin, W:sphere radius VectorRegister BoundingSphereVector; FLinearColor Color; // must not be 0 FLightSceneInfo* LightSceneInfo; // e.g. LightType_Directional, LightType_Point or LightType_Spot uint32 LightType : LightType_NumBits; uint32 bCastDynamicShadow : 1; uint32 bCastStaticShadow : 1; uint32 bStaticLighting : 1; uint32 bAffectReflection : 1; uint32 bAffectGlobalIllumination : 1; uint32 bIsMovable : 1; uint32 bAllowMegaLights : 1; TEnumAsByte MegaLightsShadowMethod; TEnumAsByte CastRaytracedShadow; /** Initializes the compact scene info from the light's full scene info. */ void Init(FLightSceneInfo* InLightSceneInfo); /** Default constructor. */ FLightSceneInfoCompact(): LightSceneInfo(NULL) {} /** Initialization constructor. */ FLightSceneInfoCompact(FLightSceneInfo* InLightSceneInfo) { Init(InLightSceneInfo); } /** * Tests whether this light affects the given primitive. This checks both the primitive and light settings for light relevance * and also calls AffectsBounds. * * @param CompactPrimitiveSceneInfo - The primitive to test. * @return True if the light affects the primitive. */ bool AffectsPrimitive(const FBoxSphereBounds& PrimitiveBounds, const FPrimitiveSceneProxy* PrimitiveSceneProxy) const; }; /** Information for sorting lights. */ struct FSortedLightSceneInfo { union { struct { // Note: the order of these members controls the light sort order! // Currently bHandledByMegaLights is the MSB and LightType is LSB /** The type of light. */ uint32 LightType : LightType_NumBits; /** Whether the light uses a light function. */ uint32 bLightFunction : 1; /** Whether the light uses lighting channels. */ uint32 bUsesLightingChannels : 1; /** Whether the light casts shadows. */ uint32 bShadowed : 1; /** Whether the light is NOT a simple light - they always support tiled/clustered but may want to be selected separately. */ uint32 bIsNotSimpleLight : 1; /** * True if the light doesn't support clustered deferred, logic is inverted so that lights that DO support clustered deferred will sort first in list * Super-set of lights supporting tiled, so the tiled lights will end up in the first part of this range. */ uint32 bClusteredDeferredNotSupported : 1; /** Mega Lights must be sorted by GPU Scene Light Index - this field will only be set for MegaLights which don't rely on ordering of the other fields */ uint32 LightSceneId : LIGHT_ID_NUM_BITS; /** Whether the light should be handled by Mega Lights, these will be sorted to the end so they can be skipped */ uint32 bHandledByMegaLights : 1; } Fields; /** Sort key bits packed into an integer. */ uint32 Packed; static_assert(sizeof(Packed) >= sizeof(Fields), "SortKey Packed representation must include all bits in Fields"); } SortKey; const FLightSceneInfo* LightSceneInfo; int32 SimpleLightIndex; bool bIsCompatibleWithLightFunctionAtlas; /** Initialization constructor. */ explicit FSortedLightSceneInfo(const FLightSceneInfo* InLightSceneInfo) : LightSceneInfo(InLightSceneInfo), SimpleLightIndex(-1), bIsCompatibleWithLightFunctionAtlas(false) { SortKey.Packed = 0; SortKey.Fields.bIsNotSimpleLight = 1; } explicit FSortedLightSceneInfo(int32 InSimpleLightIndex) : LightSceneInfo(nullptr), SimpleLightIndex(InSimpleLightIndex), bIsCompatibleWithLightFunctionAtlas(false) { SortKey.Packed = 0; SortKey.Fields.bIsNotSimpleLight = 0; } }; /** * Stores info about sorted lights and ranges. * The sort-key in FSortedLightSceneInfo gives rise to the following order: * [SimpleLights,Clustered,UnbatchedLights,LumenLights] * Note that some shadowed lights can be included in the clustered pass when virtual shadow maps and one pass projection are used. */ struct FSortedLightSetSceneInfo { int32 SimpleLightsEnd; int32 ClusteredSupportedEnd; /** First light with shadow map or */ int32 UnbatchedLightStart; // First light handled by Mega Lights int32 MegaLightsLightStart; bool bHasRectLights = false; bool bHasLightFunctions = false; bool bHasLightChannels = false; bool bHasFirstPersonSelfShadowLights = false; FSimpleLightArray SimpleLights; TArray SortedLights; }; template <> struct TUseBitwiseSwap { enum { Value = false }; }; /** The type of the octree used by FScene to find lights. */ typedef TOctree2 FSceneLightOctree; struct FPersistentShadowStateKey { int32 AtlasIndex = -1; int32 ProjectionId = -1; int32 SubjectPrimitiveComponentIndex = -1; }; inline uint32 GetTypeHash(const FPersistentShadowStateKey& Key) { return HashCombine(HashCombine((uint32)Key.AtlasIndex, (uint32)Key.ProjectionId), (uint32)Key.SubjectPrimitiveComponentIndex); } inline bool operator==(const FPersistentShadowStateKey& A, const FPersistentShadowStateKey& B) { return A.AtlasIndex == B.AtlasIndex && A.ProjectionId == B.ProjectionId && A.SubjectPrimitiveComponentIndex == B.SubjectPrimitiveComponentIndex; } class FPersistentShadowState { public: FViewMatrices ViewMatrices; FIntRect HZBTestViewRect; TRefCountPtr HZB; // Direct HZB. nullptr for Atlas rendering. }; /** * The information used to render a light. This is the rendering thread's mirror of the game thread's ULightComponent. * FLightSceneInfo is internal to the renderer module and contains internal scene state. */ class FLightSceneInfo { friend class FLightPrimitiveInteraction; bool bRecordInteractionShadowPrimitives; TArray InteractionShadowPrimitives; /** The list of dynamic primitives affected by the light. */ FLightPrimitiveInteraction* DynamicInteractionOftenMovingPrimitiveList; FLightPrimitiveInteraction* DynamicInteractionStaticPrimitiveList; public: using FPersistentId = int32; /** The light's scene proxy. */ FLightSceneProxy* Proxy; ELightComponentType Type; /** If bVisible == true, this is the index of the primitive in Scene->Lights. */ FPersistentId Id; FORCEINLINE FPersistentId GetPersistentIndex() const { return Id; } /** The identifier for the primitive in Scene->PrimitiveOctree. */ FOctreeElementId2 OctreeId; /** Persistent shadow state used for HZB occlusion culling. */ TMap PrevPersistentShadows; TMap PersistentShadows; protected: /** * ShadowMap channel assigned in the forward renderer when a movable shadow casting light is added to the scene. * Used to pack shadow projections into channels of the light attenuation texture which is read in the base pass. */ int32 DynamicShadowMapChannel; /** True if the light is built. */ uint32 bPrecomputedLightingIsValid : 1; public: /** * True if the light is visible. * False if the light is invisible but still needed for previewing, which can only happen in the editor. */ uint32 bVisible : 1; /** * Whether to render light shaft bloom from this light. * For directional lights, the color around the light direction will be blurred radially and added back to the scene. * for point lights, the color on pixels closer than the light's SourceRadius will be blurred radially and added back to the scene. */ uint32 bEnableLightShaftBloom : 1; /** Scales the additive color. */ float BloomScale; /** Scene color must be larger than this to create bloom in the light shafts. */ float BloomThreshold; /** After exposure is applied, scene color brightness larger than BloomMaxBrightness will be rescaled down to BloomMaxBrightness. */ float BloomMaxBrightness; /** Multiplies against scene color to create the bloom color. */ FColor BloomTint; /** Number of dynamic interactions with statically lit primitives. */ int32 NumUnbuiltInteractions; /** Cached value from the light proxy's virtual function, since it is checked many times during shadow setup. */ bool bCreatePerObjectShadowsForDynamicObjects; /** The scene the light is in. */ FScene* Scene; /** Initialization constructor. */ FLightSceneInfo(FLightSceneProxy* InProxy, bool InbVisible); /** Adds the light to the scene. */ void AddToScene(); /** * Returns true if the light affects the primitive * @param LightSceneInfoCompact Compact representation of the light * @param PrimitiveSceneInfoCompact Compact representation of the primitive */ bool ShouldCreateLightPrimitiveInteraction(const FLightSceneInfoCompact& LightSceneInfoCompact, const FPrimitiveSceneInfoCompact& PrimitiveSceneInfoCompact); /** * If the light affects the primitive, create an interaction, and process children * @param LightSceneInfoCompact Compact representation of the light * @param PrimitiveSceneInfoCompact Compact representation of the primitive */ void CreateLightPrimitiveInteraction(const FLightSceneInfoCompact& LightSceneInfoCompact, const FPrimitiveSceneInfoCompact& PrimitiveSceneInfoCompact); /** Removes the light from the scene. */ void RemoveFromScene(); /** Detaches the light from the primitives it affects. */ void Detach(); /** Octree bounds setup. */ FBoxCenterAndExtent GetBoundingBox() const; bool ShouldRenderLight(const FViewInfo& View, bool bOffscreen = false) const; /** Encapsulates all View-Independent reasons to have this light render. */ bool ShouldRenderLightViewIndependent() const; /** Encapsulates all View-Independent reasons to render ViewIndependentWholeSceneShadows for this light */ bool ShouldRenderViewIndependentWholeSceneShadows() const; bool IsPrecomputedLightingValid() const; void SetDynamicShadowMapChannel(int32 NewChannel); int32 GetDynamicShadowMapChannel() const; const TArray* GetInteractionShadowPrimitives() const; FLightPrimitiveInteraction* GetDynamicInteractionOftenMovingPrimitiveList() const; FLightPrimitiveInteraction* GetDynamicInteractionStaticPrimitiveList() const; /** Hash function. */ friend uint32 GetTypeHash(const FLightSceneInfo* LightSceneInfo) { return (uint32)LightSceneInfo->Id; } bool SetupMobileMovableLocalLightShadowParameters(const FViewInfo& View, TConstArrayView VisibleLightInfos, FMobileMovableLocalLightShadowParameters& MobileMovableLocalLightShadowParameters) const; bool ShouldRecordShadowSubjectsForMobile() const; // Extra data such as shadow channel masks, light type and flags packed into a uint32. // Unpacked in shader using helper functions defined in LightData.ush uint32 PackExtraData(bool bAllowStaticLighting, bool bLightFunction, bool bMegaLight, bool bClusteredDeferredSupported) const; }; /** Defines how the light is stored in the scene's light octree. */ struct FLightOctreeSemantics { enum { MaxElementsPerLeaf = 16 }; enum { MinInclusiveElementsPerNode = 7 }; enum { MaxNodeDepth = 12 }; typedef TInlineAllocator> ElementAllocator; FORCEINLINE static FBoxCenterAndExtent GetBoundingBox(const FLightSceneInfoCompact& Element) { return Element.LightSceneInfo->GetBoundingBox(); } FORCEINLINE static bool AreElementsEqual(const FLightSceneInfoCompact& A,const FLightSceneInfoCompact& B) { return A.LightSceneInfo == B.LightSceneInfo; } FORCEINLINE static void SetElementId(const FLightSceneInfoCompact& Element,FOctreeElementId2 Id) { Element.LightSceneInfo->OctreeId = Id; } FORCEINLINE static void ApplyOffset(FLightSceneInfoCompact& Element, FVector Offset) { VectorRegister OffsetReg = VectorLoadFloat3_W0(&Offset); Element.BoundingSphereVector = VectorAdd(Element.BoundingSphereVector, OffsetReg); } };