struct FSortedShadowMapAtlas
{
FShadowMapRenderTargetsRefCounted RenderTargets;
TArray<FProjectedShadowInfo*, SceneRenderingAllocator> Shadows;
};
struct FSortedShadowMaps
{
/** Visible shadows sorted by their shadow depth map render target. */
TArray<FSortedShadowMapAtlas,SceneRenderingAllocator> ShadowMapAtlases;
TArray<FSortedShadowMapAtlas,SceneRenderingAllocator> RSMAtlases;
TArray<FSortedShadowMapAtlas,SceneRenderingAllocator> ShadowMapCubemaps;
FSortedShadowMapAtlas PreshadowCache;
TArray<FSortedShadowMapAtlas,SceneRenderingAllocator> TranslucencyShadowMapAtlases;
void Release();
int64 ComputeMemorySize() const
{
int64 MemorySize = 0;
for (int i = 0; i < ShadowMapAtlases.Num(); i++)
{
MemorySize += ShadowMapAtlases[i].RenderTargets.ComputeMemorySize();
}
for (int i = 0; i < RSMAtlases.Num(); i++)
{
MemorySize += RSMAtlases[i].RenderTargets.ComputeMemorySize();
}
for (int i = 0; i < ShadowMapCubemaps.Num(); i++)
{
MemorySize += ShadowMapCubemaps[i].RenderTargets.ComputeMemorySize();
}
MemorySize += PreshadowCache.RenderTargets.ComputeMemorySize();
for (int i = 0; i < TranslucencyShadowMapAtlases.Num(); i++)
{
MemorySize += TranslucencyShadowMapAtlases[i].RenderTargets.ComputeMemorySize();
}
return MemorySize;
}
};
/**
* Information about a projected shadow.
*/
class FProjectedShadowInfo : public FRefCountedObject
{
public:
typedef TArray<const FPrimitiveSceneInfo*,SceneRenderingAllocator> PrimitiveArrayType;
/** The view to be used when rendering this shadow's depths. */
FViewInfo* ShadowDepthView;
TUniformBufferRef<FShadowDepthPassUniformParameters> ShadowDepthPassUniformBuffer;
TUniformBufferRef<FMobileShadowDepthPassUniformParameters> MobileShadowDepthPassUniformBuffer;
/** The depth or color targets this shadow was rendered to. */
FShadowMapRenderTargets RenderTargets;
EShadowDepthCacheMode CacheMode;
/** The main view this shadow must be rendered in, or NULL for a view independent shadow. */
FViewInfo* DependentView;
/** Index of the shadow into FVisibleLightInfo::AllProjectedShadows. */
int32 ShadowId;
/** A translation that is applied to world-space before transforming by one of the shadow matrices. */
FVector PreShadowTranslation;
/** The effective view matrix of the shadow, used as an override to the main view's view matrix when rendering the shadow depth pass. */
FMatrix ShadowViewMatrix;
/**
* Matrix used for rendering the shadow depth buffer.
* Note that this does not necessarily contain all of the shadow casters with CSM, since the vertex shader flattens them onto the near plane of the projection.
*/
FMatrix SubjectAndReceiverMatrix;
FMatrix ReceiverMatrix;
FMatrix InvReceiverMatrix;
float InvMaxSubjectDepth;
/**
* Subject depth extents, in world space units.
* These can be used to convert shadow depth buffer values back into world space units.
*/
float MaxSubjectZ;
float MinSubjectZ;
/** Frustum containing all potential shadow casters. */
FConvexVolume CasterFrustum;
FConvexVolume ReceiverFrustum;
float MinPreSubjectZ;
FSphere ShadowBounds;
FShadowCascadeSettings CascadeSettings;
/**
* X and Y position of the shadow in the appropriate depth buffer. These are only initialized after the shadow has been allocated.
* The actual contents of the shadowmap are at X + BorderSize, Y + BorderSize.
*/
uint32 X;
uint32 Y;
/**
* Resolution of the shadow, excluding the border.
* The full size of the region allocated to this shadow is therefore ResolutionX + 2 * BorderSize, ResolutionY + 2 * BorderSize.
*/
uint32 ResolutionX;
uint32 ResolutionY;
/** Size of the border, if any, used to allow filtering without clamping for shadows stored in an atlas. */
uint32 BorderSize;
/** The largest percent of either the width or height of any view. */
float MaxScreenPercent;
/** Fade Alpha per view. */
TArray<float, TInlineAllocator<2> > FadeAlphas;
/** Whether the shadow has been allocated in the shadow depth buffer, and its X and Y properties have been initialized. */
uint32 bAllocated : 1;
/** Whether the shadow's projection has been rendered. */
uint32 bRendered : 1;
/** Whether the shadow has been allocated in the preshadow cache, so its X and Y properties offset into the preshadow cache depth buffer. */
uint32 bAllocatedInPreshadowCache : 1;
/** Whether the shadow is in the preshadow cache and its depths are up to date. */
uint32 bDepthsCached : 1;
// redundant to LightSceneInfo->Proxy->GetLightType() == LightType_Directional, could be made ELightComponentType LightType
uint32 bDirectionalLight : 1;
/** Whether the shadow is a point light shadow that renders all faces of a cubemap in one pass. */
uint32 bOnePassPointLightShadow : 1;
/** Whether this shadow affects the whole scene or only a group of objects. */
uint32 bWholeSceneShadow : 1;
/** Whether the shadow needs to render reflective shadow maps. */
uint32 bReflectiveShadowmap : 1;
/** Whether this shadow should support casting shadows from translucent surfaces. */
uint32 bTranslucentShadow : 1;
/** Whether the shadow will be computed by ray tracing the distance field. */
uint32 bRayTracedDistanceField : 1;
/** Whether this is a per-object shadow that should use capsule shapes to shadow instead of the mesh's triangles. */
uint32 bCapsuleShadow : 1;
/** Whether the shadow is a preshadow or not. A preshadow is a per object shadow that handles the static environment casting on a dynamic receiver. */
uint32 bPreShadow : 1;
/** To not cast a shadow on the ground outside the object and having higher quality (useful for first person weapon). */
uint32 bSelfShadowOnly : 1;
/** Whether the shadow is a per object shadow or not. */
uint32 bPerObjectOpaqueShadow : 1;
/** Whether turn on back-lighting transmission. */
uint32 bTransmission : 1;
/** Whether turn on hair strands deep shadow. */
uint32 bHairStrandsDeepShadow : 1;
/** View projection matrices for each cubemap face, used by one pass point light shadows. */
TArray<FMatrix> OnePassShadowViewProjectionMatrices;
/** View matrices for each cubemap face, used by one pass point light shadows. */
TArray<FMatrix> OnePassShadowViewMatrices;
/** Controls fading out of per-object shadows in the distance to avoid casting super-sharp shadows far away. */
float PerObjectShadowFadeStart;
float InvPerObjectShadowFadeLength;
public:
// default constructor
FProjectedShadowInfo();
/**
* for a per-object shadow. e.g. translucent particle system or a dynamic object in a precomputed shadow situation
* @param InParentSceneInfo must not be 0
* @return success, if false the shadow project is invalid and the projection should nto be created
*/
bool SetupPerObjectProjection(
FLightSceneInfo* InLightSceneInfo,
const FPrimitiveSceneInfo* InParentSceneInfo,
const FPerObjectProjectedShadowInitializer& Initializer,
bool bInPreShadow,
uint32 InResolutionX,
uint32 MaxShadowResolutionY,
uint32 InBorderSize,
float InMaxScreenPercent,
bool bInTranslucentShadow
);
/** for a whole-scene shadow. */
void SetupWholeSceneProjection(
FLightSceneInfo* InLightSceneInfo,
FViewInfo* InDependentView,
const FWholeSceneProjectedShadowInitializer& Initializer,
uint32 InResolutionX,
uint32 InResolutionY,
uint32 InBorderSize,
bool bInReflectiveShadowMap
);
float GetShaderDepthBias() const { return ShaderDepthBias; }
float GetShaderSlopeDepthBias() const { return ShaderSlopeDepthBias; }
float GetShaderMaxSlopeDepthBias() const { return ShaderMaxSlopeDepthBias; }
float GetShaderReceiverDepthBias() const;
/**
* Renders the shadow subject depth.
*/
void RenderDepth(FRHICommandListImmediate& RHICmdList, class FSceneRenderer* SceneRenderer, FBeginShadowRenderPassFunction BeginShadowRenderPass, bool bDoParallelDispatch);
void SetStateForView(FRHICommandList& RHICmdList) const;
/** Set state for depth rendering */
void SetStateForDepth(FMeshPassProcessorRenderState& DrawRenderState) const;
void ClearDepth(FRHICommandList& RHICmdList, class FSceneRenderer* SceneRenderer, int32 NumColorTextures, FRHITexture** ColorTextures, FRHITexture* DepthTexture, bool bPerformClear);
/** Renders shadow maps for translucent primitives. */
void RenderTranslucencyDepths(FRHICommandList& RHICmdList, class FSceneRenderer* SceneRenderer);
static FRHIBlendState* GetBlendStateForProjection(
int32 ShadowMapChannel,
bool bIsWholeSceneDirectionalShadow,
bool bUseFadePlane,
bool bProjectingForForwardShading,
bool bMobileModulatedProjections);
FRHIBlendState* GetBlendStateForProjection(bool bProjectingForForwardShading, bool bMobileModulatedProjections) const;
/**
* Projects the shadow onto the scene for a particular view.
*/
void RenderProjection(FRHICommandListImmediate& RHICmdList, int32 ViewIndex, const class FViewInfo* View, const class FSceneRenderer* SceneRender, bool bProjectingForForwardShading, bool bMobile, const struct FHairStrandsVisibilityData* HairVisibilityData, const struct FHairStrandsMacroGroupDatas* HairMacroGroupData) const;
FRDGTextureRef BeginRenderRayTracedDistanceFieldProjection(
FRDGBuilder& GraphBuilder,
TRDGUniformBufferRef<FSceneTextureUniformParameters> SceneTexturesUniformBuffer,
const FViewInfo& View) const;
/** Renders ray traced distance field shadows. */
void RenderRayTracedDistanceFieldProjection(
FRDGBuilder& GraphBuilder,
TRDGUniformBufferRef<FSceneTextureUniformParameters> SceneTexturesUniformBuffer,
FRDGTextureRef ScreenShadowMaskTexture,
FRDGTextureRef SceneDepthTexture,
const FViewInfo& View,
FIntRect ScissorRect,
bool bProjectingForForwardShading) const;
/** Render one pass point light shadow projections. */
void RenderOnePassPointLightProjection(FRHICommandListImmediate& RHICmdList, int32 ViewIndex, const FViewInfo& View, bool bProjectingForForwardShading, const FHairStrandsVisibilityData* HairVisibilityData, const struct FHairStrandsMacroGroupDatas* HairMacroGroupData) const;
/**
* Renders the projected shadow's frustum wireframe with the given FPrimitiveDrawInterface.
*/
void RenderFrustumWireframe(FPrimitiveDrawInterface* PDI) const;
/**
* Adds a primitive to the shadow's subject list.
*/
void AddSubjectPrimitive(FPrimitiveSceneInfo* PrimitiveSceneInfo, TArray<FViewInfo>* ViewArray, ERHIFeatureLevel::Type FeatureLevel, bool bRecordShadowSubjectForMobileShading);
uint64 AddSubjectPrimitive_AnyThread(
const FPrimitiveSceneInfoCompact& PrimitiveSceneInfoCompact,
TArray<FViewInfo>* ViewArray,
ERHIFeatureLevel::Type FeatureLevel,
struct FAddSubjectPrimitiveStats& OutStats,
struct FAddSubjectPrimitiveOverflowedIndices& OverflowBuffer) const;
void PresizeSubjectPrimitiveArrays(struct FAddSubjectPrimitiveStats const& Stats);
void FinalizeAddSubjectPrimitive(
struct FAddSubjectPrimitiveOp const& Op,
TArray<FViewInfo>* ViewArray,
ERHIFeatureLevel::Type FeatureLevel,
struct FFinalizeAddSubjectPrimitiveContext& Context);
/**
* @return TRUE if this shadow info has any casting subject prims to render
*/
bool HasSubjectPrims() const;
/**
* Adds a primitive to the shadow's receiver list.
*/
void AddReceiverPrimitive(FPrimitiveSceneInfo* PrimitiveSceneInfo);
/** Gathers dynamic mesh elements for all the shadow's primitives arrays. */
void GatherDynamicMeshElements(FSceneRenderer& Renderer, class FVisibleLightInfo& VisibleLightInfo, TArray<const FSceneView*>& ReusedViewsArray,
FGlobalDynamicIndexBuffer& DynamicIndexBuffer, FGlobalDynamicVertexBuffer& DynamicVertexBuffer, FGlobalDynamicReadBuffer& DynamicReadBuffer);
void SetupMeshDrawCommandsForShadowDepth(FSceneRenderer& Renderer, FRHIUniformBuffer* PassUniformBuffer);
void SetupMeshDrawCommandsForProjectionStenciling(FSceneRenderer& Renderer);
/**
* @param View view to check visibility in
* @return true if this shadow info has any subject prims visible in the view
*/
bool SubjectsVisible(const FViewInfo& View) const;
/** Clears arrays allocated with the scene rendering allocator. */
void ClearTransientArrays();
/** Hash function. */
friend uint32 GetTypeHash(const FProjectedShadowInfo* ProjectedShadowInfo)
{
return PointerHash(ProjectedShadowInfo);
}
/** Returns a matrix that transforms a screen space position into shadow space. */
FMatrix GetScreenToShadowMatrix(const FSceneView& View) const
{
return GetScreenToShadowMatrix(View, X, Y, ResolutionX, ResolutionY);
}
/** Returns a matrix that transforms a screen space position into shadow space.
Additional parameters allow overriding of shadow's tile location.
Used with modulated shadows to reduce precision problems when calculating ScreenToShadow in pixel shader.
*/
FMatrix GetScreenToShadowMatrix(const FSceneView& View, uint32 TileOffsetX, uint32 TileOffsetY, uint32 TileResolutionX, uint32 TileResolutionY) const;
/** Returns a matrix that transforms a world space position into shadow space. */
FMatrix GetWorldToShadowMatrix(FVector4& ShadowmapMinMax, const FIntPoint* ShadowBufferResolutionOverride = nullptr) const;
/** Returns the resolution of the shadow buffer used for this shadow, based on the shadow's type. */
FIntPoint GetShadowBufferResolution() const
{
return RenderTargets.GetSize();
}
/** Computes and updates ShaderDepthBias and ShaderSlopeDepthBias */
void UpdateShaderDepthBias();
/** How large the soft PCF comparison should be, similar to DepthBias, before this was called TransitionScale and 1/Size */
float ComputeTransitionSize() const;
inline bool IsWholeSceneDirectionalShadow() const
{
return bWholeSceneShadow && CascadeSettings.ShadowSplitIndex >= 0 && bDirectionalLight;
}
inline bool IsWholeScenePointLightShadow() const
{
return bWholeSceneShadow && ( LightSceneInfo->Proxy->GetLightType() == LightType_Point || LightSceneInfo->Proxy->GetLightType() == LightType_Rect );
}
// 0 if Setup...() wasn't called yet
const FLightSceneInfo& GetLightSceneInfo() const { return *LightSceneInfo; }
const FLightSceneInfoCompact& GetLightSceneInfoCompact() const { return LightSceneInfoCompact; }
/**
* Parent primitive of the shadow group that created this shadow, if not a bWholeSceneShadow.
* 0 if Setup...() wasn't called yet
*/
const FPrimitiveSceneInfo* GetParentSceneInfo() const { return ParentSceneInfo; }
/** Creates a new view from the pool and caches it in ShadowDepthView for depth rendering. */
void SetupShadowDepthView(FRHICommandListImmediate& RHICmdList, FSceneRenderer* SceneRenderer);
FShadowDepthType GetShadowDepthType() const
{
return FShadowDepthType(bDirectionalLight, bOnePassPointLightShadow, bReflectiveShadowmap);
}
/**
* Setup uniformbuffers and update Primitive Shader Data
*/
void SetupShadowUniformBuffers(FRHICommandListImmediate& RHICmdList, FScene* Scene, FLightPropagationVolume* LPV = nullptr);
/**
* Ensure Cached Shadowmap is in EReadable state
*/
void TransitionCachedShadowmap(FRHICommandListImmediate& RHICmdList, FScene* Scene);
private:
// 0 if Setup...() wasn't called yet
const FLightSceneInfo* LightSceneInfo;
FLightSceneInfoCompact LightSceneInfoCompact;
/**
* Parent primitive of the shadow group that created this shadow, if not a bWholeSceneShadow.
* 0 if Setup...() wasn't called yet or for whole scene shadows
*/
const FPrimitiveSceneInfo* ParentSceneInfo;
/** dynamic shadow casting elements */
PrimitiveArrayType DynamicSubjectPrimitives;
/** For preshadows, this contains the receiver primitives to mask the projection to. */
PrimitiveArrayType ReceiverPrimitives;
/** Subject primitives with translucent relevance. */
PrimitiveArrayType SubjectTranslucentPrimitives;
/** Dynamic mesh elements for subject primitives. */
TArray<FMeshBatchAndRelevance,SceneRenderingAllocator> DynamicSubjectMeshElements;
/** Dynamic mesh elements for translucent subject primitives. */
TArray<FMeshBatchAndRelevance,SceneRenderingAllocator> DynamicSubjectTranslucentMeshElements;
TArray<const FStaticMeshBatch*, SceneRenderingAllocator> SubjectMeshCommandBuildRequests;
/** Number of elements of DynamicSubjectMeshElements meshes. */
int32 NumDynamicSubjectMeshElements;
/** Number of elements of SubjectMeshCommandBuildRequests meshes. */
int32 NumSubjectMeshCommandBuildRequestElements;
FMeshCommandOneFrameArray ShadowDepthPassVisibleCommands;
FParallelMeshDrawCommandPass ShadowDepthPass;
TArray<FShadowMeshDrawCommandPass, TInlineAllocator<2>> ProjectionStencilingPasses;
FDynamicMeshDrawCommandStorage DynamicMeshDrawCommandStorage;
FGraphicsMinimalPipelineStateSet GraphicsMinimalPipelineStateSet;
bool NeedsShaderInitialisation;
/**
* Bias during in shadowmap rendering, stored redundantly for better performance
* Set by UpdateShaderDepthBias(), get with GetShaderDepthBias(), -1 if not set
*/
float ShaderDepthBias;
float ShaderSlopeDepthBias;
float ShaderMaxSlopeDepthBias;
void CopyCachedShadowMap(FRHICommandList& RHICmdList, const FMeshPassProcessorRenderState& DrawRenderState, FSceneRenderer* SceneRenderer, const FViewInfo& View);
/**
* Renders the shadow subject depth, to a particular hacked view
*/
void RenderDepthInner(FRHICommandListImmediate& RHICmdList, class FSceneRenderer* SceneRenderer, FBeginShadowRenderPassFunction BeginShadowRenderPass, bool bDoParallelDispatch);
/**
* Modifies the passed in view for this shadow
*/
void ModifyViewForShadow(FRHICommandList& RHICmdList, FViewInfo* FoundView) const;
/**
* Finds a relevant view for a shadow
*/
FViewInfo* FindViewForShadow(FSceneRenderer* SceneRenderer) const;
void AddCachedMeshDrawCommandsForPass(
int32 PrimitiveIndex,
const FPrimitiveSceneInfo* InPrimitiveSceneInfo,
const FStaticMeshBatchRelevance& RESTRICT StaticMeshRelevance,
const FStaticMeshBatch& StaticMesh,
const FScene* Scene,
EMeshPass::Type PassType,
FMeshCommandOneFrameArray& VisibleMeshCommands,
TArray<const FStaticMeshBatch*, SceneRenderingAllocator>& MeshCommandBuildRequests,
int32& NumMeshCommandBuildRequestElements);
void AddCachedMeshDrawCommands_AnyThread(
const FScene* Scene,
const FStaticMeshBatchRelevance& RESTRICT StaticMeshRelevance,
int32 StaticMeshIdx,
int32& NumAcceptedStaticMeshes,
struct FAddSubjectPrimitiveResult& OutResult,
struct FAddSubjectPrimitiveStats& OutStats,
struct FAddSubjectPrimitiveOverflowedIndices& OverflowBuffer) const;
/** Will return if we should draw the static mesh for the shadow, and will perform lazy init of primitive if it wasn't visible */
bool ShouldDrawStaticMeshes(FViewInfo& InCurrentView, FPrimitiveSceneInfo* InPrimitiveSceneInfo);
bool ShouldDrawStaticMeshes_AnyThread(
FViewInfo& InCurrentView,
const FPrimitiveSceneInfoCompact& PrimitiveSceneInfoCompact,
bool bMayBeFading,
bool bNeedUpdateStaticMeshes,
struct FAddSubjectPrimitiveResult& OutResult,
struct FAddSubjectPrimitiveStats& OutStats,
struct FAddSubjectPrimitiveOverflowedIndices& OverflowBuffer) const;
void GetShadowTypeNameForDrawEvent(FString& TypeName) const;
/** Updates object buffers needed by ray traced distance field shadows. */
int32 UpdateShadowCastingObjectBuffers() const;
/** Gathers dynamic mesh elements for the given primitive array. */
void GatherDynamicMeshElementsArray(
FViewInfo* FoundView,
FSceneRenderer& Renderer,
FGlobalDynamicIndexBuffer& DynamicIndexBuffer,
FGlobalDynamicVertexBuffer& DynamicVertexBuffer,
FGlobalDynamicReadBuffer& DynamicReadBuffer,
const PrimitiveArrayType& PrimitiveArray,
const TArray<const FSceneView*>& ReusedViewsArray,
TArray<FMeshBatchAndRelevance,SceneRenderingAllocator>& OutDynamicMeshElements,
int32& OutNumDynamicSubjectMeshElements);
void SetupFrustumForProjection(const FViewInfo* View, TArray<FVector4, TInlineAllocator<8>>& OutFrustumVertices, bool& bOutCameraInsideShadowFrustum, FPlane* OutPlanes) const;
void SetupProjectionStencilMask(
FRHICommandListImmediate& RHICmdList,
const FViewInfo* View,
int32 ViewIndex,
const class FSceneRenderer* SceneRender,
const TArray<FVector4, TInlineAllocator<8>>& FrustumVertices,
bool bMobileModulatedProjections,
bool bCameraInsideShadowFrustum) const;
friend class FShadowDepthVS;
friend class FShadowDepthBasePS;
friend class FShadowVolumeBoundProjectionVS;
friend class FShadowProjectionPS;
};