UE4阴影初始化【1】

开始位置:Runtime/Renderer/Private/DefferredShadingRenderer.cpp

void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList)
{
    bool bDoInitViewAftersPrepass = false;
	{
		SCOPED_GPU_STAT(RHICmdList, VisibilityCommands);
		bDoInitViewAftersPrepass = InitViews(RHICmdList, BasePassDepthStencilAccess, ILCTaskData)
}

bool FDeferredShadingSceneRenderer::InitViews(FRHICommandListImmediate& RHICmdList, FExclusiveDepthStencil::Type BasePassDepthStencilAccess, struct FILCUpdatePrimTaskData& ILCTaskData)
{
	SCOPED_NAMED_EVENT(FDeferredShadingSceneRenderer_InitViews, FColor::Emerald);
	SCOPE_CYCLE_COUNTER(STAT_InitViewsTime);
	CSV_SCOPED_TIMING_STAT_EXCLUSIVE(InitViews_Scene);
	check(RHICmdList.IsOutsideRenderPass());

	PreVisibilityFrameSetup(RHICmdList);

	RHICmdList.ImmediateFlush(EImmediateFlushType::DispatchToRHIThread);

	{
		// This is to init the ViewUniformBuffer before rendering for the Niagara compute shader.
		// This needs to run before ComputeViewVisibility() is called, but the views normally initialize the ViewUniformBuffer after that (at the end of this method).
		if (FXSystem && FXSystem->RequiresEarlyViewUniformBuffer() && Views.IsValidIndex(0))
		{
			Views[0].InitRHIResources();
			FXSystem->PostInitViews(RHICmdList, Views[0].ViewUniformBuffer, Views[0].AllowGPUParticleUpdate() && !ViewFamily.EngineShowFlags.HitProxies);
		}
	}
	
	FViewVisibleCommandsPerView ViewCommandsPerView;
	ViewCommandsPerView.SetNum(Views.Num());

	ComputeViewVisibility(RHICmdList, BasePassDepthStencilAccess, ViewCommandsPerView, DynamicIndexBufferForInitViews, DynamicVertexBufferForInitViews, DynamicReadBufferForInitViews);

	RHICmdList.ImmediateFlush(EImmediateFlushType::DispatchToRHIThread);

	// This has to happen before Scene->IndirectLightingCache.UpdateCache, since primitives in View.IndirectShadowPrimitives need ILC updates
	CreateIndirectCapsuleShadows();

	// This must happen before we start initialising and using views.
	UpdateSkyIrradianceGpuBuffer(RHICmdList);

	RHICmdList.ImmediateFlush(EImmediateFlushType::DispatchToRHIThread);

	// Initialise Sky/View resources before the view global uniform buffer is built.
	if (ShouldRenderSkyAtmosphere(Scene, ViewFamily.EngineShowFlags))
	{
		InitSkyAtmosphereForViews(RHICmdList);
	}

	PostVisibilityFrameSetup(ILCTaskData);
	RHICmdList.ImmediateFlush(EImmediateFlushType::DispatchToRHIThread);

	FVector AverageViewPosition(0);

	for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
	{		
		FViewInfo& View = Views[ViewIndex];
		AverageViewPosition += View.ViewMatrices.GetViewOrigin() / Views.Num();
	}

	bool bDoInitViewAftersPrepass = !!GDoInitViewsLightingAfterPrepass;

	if (!bDoInitViewAftersPrepass)
	{
		InitViewsPossiblyAfterPrepass(RHICmdList, ILCTaskData);
	}

	{
		QUICK_SCOPE_CYCLE_COUNTER(STAT_InitViews_InitRHIResources);
		// initialize per-view uniform buffer.
		for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
		{
			FViewInfo& View = Views[ViewIndex];

			if (View.ViewState)
			{
				if (!View.ViewState->ForwardLightingResources)
				{
					View.ViewState->ForwardLightingResources.Reset(new FForwardLightingViewResources());
				}

				View.ForwardLightingResources = View.ViewState->ForwardLightingResources.Get();
			}
			else
			{
				View.ForwardLightingResourcesStorage.Reset(new FForwardLightingViewResources());
				View.ForwardLightingResources = View.ForwardLightingResourcesStorage.Get();
			}

#if RHI_RAYTRACING
			View.IESLightProfileResource = View.ViewState ? &View.ViewState->IESLightProfileResources : nullptr;
#endif
			// Set the pre-exposure before initializing the constant buffers.
			if (View.ViewState)
			{
				View.ViewState->UpdatePreExposure(View);
			}

			// Initialize the view's RHI resources.
			View.InitRHIResources();
		}
	}

	SetupVolumetricFog();

	{
		QUICK_SCOPE_CYCLE_COUNTER(STAT_InitViews_OnStartRender);
		OnStartRender(RHICmdList);
	}

	return bDoInitViewAftersPrepass;
}

void FDeferredShadingSceneRenderer::InitViewsPossiblyAfterPrepass(FRHICommandListImmediate& RHICmdList, struct FILCUpdatePrimTaskData& ILCTaskData)
{
	SCOPED_NAMED_EVENT(FDeferredShadingSceneRenderer_InitViewsPossiblyAfterPrepass, FColor::Emerald);
	SCOPE_CYCLE_COUNTER(STAT_InitViewsPossiblyAfterPrepass);

	if (ViewFamily.EngineShowFlags.DynamicShadows 
		&& !IsSimpleForwardShadingEnabled(ShaderPlatform)
		&& !ViewFamily.EngineShowFlags.HitProxies)
	{
		// Setup dynamic shadows.
		InitDynamicShadows(RHICmdList, DynamicIndexBufferForInitShadows, DynamicVertexBufferForInitShadows, DynamicReadBufferForInitShadows);

		RHICmdList.ImmediateFlush(EImmediateFlushType::DispatchToRHIThread);
	}

	// If parallel ILC update is disabled, then process it in place.
	if (ViewFamily.EngineShowFlags.HitProxies == 0
		&& Scene->PrecomputedLightVolumes.Num() > 0
		&& !(GILCUpdatePrimTaskEnabled && FPlatformProcess::SupportsMultithreading()))
	{
		QUICK_SCOPE_CYCLE_COUNTER(STAT_PostVisibilityFrameSetup_IndirectLightingCache_Update);
		check(!ILCTaskData.TaskRef.IsValid());
		Scene->IndirectLightingCache.UpdateCache(Scene, *this, true);
	}

	// If we kicked off ILC update via task, wait and finalize.
	if (ILCTaskData.TaskRef.IsValid())
	{
		Scene->IndirectLightingCache.FinalizeCacheUpdates(Scene, *this, ILCTaskData);
	}

	{
		QUICK_SCOPE_CYCLE_COUNTER(STAT_InitViews_UpdatePrimitiveIndirectLightingCacheBuffers);
		// Now that the indirect lighting cache is updated, we can update the primitive precomputed lighting buffers.
		UpdatePrimitiveIndirectLightingCacheBuffers();
	}

	SeparateTranslucencyDimensions = UpdateTranslucencyTimers(RHICmdList, Views);

	SetupSceneReflectionCaptureBuffer(RHICmdList);
}


 InitDynamicShadows的主要过程,如下:

  • 根据view、场景光源、控制台变量初始化阴影相关标记。

  • 遍历场景所有光源(Scene->Lights),执行以下操作:

    • 如果光源没有开启阴影或阴影质量太小,或者光源在所有view都不可见,忽略之,不执行阴影投射。

    • 如果是点光源全景阴影,则将该光源组件名字加入Scene的UsedWholeScenePointLightNames列表中。

    • 如果符合全景阴影的创建条件,调用CreateWholeSceneProjectedShadow:

      • 初始化阴影数据,计算阴影所需的分辨率、过渡因子(FadeAlpha)等。
      • 若过渡因子太小(小于1/256),则直接返回。
      • 遍历光源的投射阴影数量,每次都执行分辨率计算、位置(SizeX、SizeY)计算、需创建的阴影图数量等。
        • 根据阴影图数量创建同等个数的FProjectedShadowInfo阴影实例,对每个阴影实例:
          • 设置全景投射参数(视锥体边界、变换矩阵、深度、深度偏移等)、过渡因子、缓存模式等。
          • 加入VisibleLightInfo.MemStackProjectedShadows列表;如果是单通道点光源阴影,填充阴影实例的cubemap6个面的数据(视图投影矩阵、包围盒、远近裁剪面等),并初始化锥体。
          • 对非光追距离场阴影,执行CPU侧裁剪。构建光源视图的凸面体,再遍历光源的移动图元列表,调用IntersectsConvexHulls让光源包围盒和图元包围盒求交测试,相交的那些图元才会添加到阴影实例的主体图元列表中。对光源的静态图元做相似的操作。
          • 最后将需要渲染的阴影实例加入VisibleLightInfo.AllProjectedShadows列表中。
    • 针对两类光源(移动和固定的光源、尚未构建的静态光源)创建CSM(级联阴影)。调用AddViewDependentWholeSceneShadowsForView创建视图关联的CSM:

      • 遍历所有view,针对每个view:
        • 如果不是主view,直接跳过后续步骤。
        • 获取视图相关的全景投影数量,创建同等数量的FProjectedShadowInfo阴影实例,给每个阴影实例设置全景投影参数,最后添加到阴影实例列表和待裁剪列表中。
    • 处理交互阴影(指光源和图元之间的影响,包含PerObject阴影、透明阴影、自阴影等),遍历光源的动态和静态图元,给每个图元调用SetupInteractionShadows设置交互阴影:

      • 处理光源附加根组件,设置相关标记。如果存在附加根组件,跳过后续步骤。
      • 如果需要创建阴影实例,则调用CreatePerObjectProjectedShadow创建逐物体阴影:
        • 遍历所有view,收集阴影相关的标记。
        • 如果本帧不可见且下一帧也没有潜在可见,则直接返回,跳过后续的阴影创建和设置。
        • 没有有效的阴影组图元,直接返回。
        • 计算阴影的各类数据(阴影视锥、分辨率、可见性标记、图集位置等)。
        • 若过渡因子(FadeAlpha)小于某个阈值(1.0/256.0),直接返回。
        • 符合阴影创建条件且是不透明阴影,则创和设置建阴影实例,加入VisibleLightInfo.MemStackProjectedShadows列表中。如果本帧可见则加入到阴影实例的主体图元列表,如果下一帧潜在可见则加入到VisibleLightInfo.OccludedPerObjectShadows的实例中。
        • 符合阴影创建条件且是半透明阴影,执行上步骤类似操作。
  • 调用InitProjectedShadowVisibility执行阴影可见性判定:

    • 遍历场景的所有光源,针对每个光源:
      • 分配视图内的投射阴影可见性和关联的容器。
      • 遍历可见光源所有的阴影实例,针对每个阴影实例:
        • 保存阴影索引。
        • 遍历所有view,针对每个view:
          • 处理视图关联的阴影,跳过那些不在视图视锥内的光源。
          • 计算主体图元的视图关联数据,断阴影是否被遮挡,设置阴影可见性标记。
          • 如果阴影可见且不是RSM,利用FViewElementPDI绘制阴影锥体。
  • 调用UpdatePreshadowCache清理旧的预计算阴影,尝试增加新的到缓存中:

    • 初始化纹理布局。
    • 遍历所有缓存的预阴影, 删除不在此帧渲染的实例。
    • 收集可以被缓存的PreShadow列表。
    • 对PreShadow从大到小排序(更大的PreShadow在渲染深度时会有更多的物体)。
    • 遍历所有未缓存的PreShadow,尝试从纹理布局中给PreShadow找空间,若找到,则设置相关数据并添加到Scene->CachedPreshadows列表中。
  • 调用GatherShadowPrimitives收集图元列表,以处理不同类型的阴影:

    • 如果没有PreShadow且没有视图关联的全景阴影(ViewDependentWholeSceneShadows),则直接返回。
    • 如果允许八叉树遍历(GUseOctreeForShadowCulling决定),利用八叉树遍历Scene->PrimitiveOctree,针对每个孩子节点:
      • 检查孩子节点是否至少在一个阴影(包含PreShadow和视图相关的全景阴影)内,如果是,则push到节点容器中。
      • 如果图元节点的元素大于0,从FMemStack创建一个FGatherShadowPrimitivesPacket实例,将该节点的相关数据存入其中,添加到FGatherShadowPrimitivesPacket实例列表中。
    • 如果是非八叉树遍历模式,则线性遍历图元,创建FGatherShadowPrimitivesPacket并加入到列表中。
    • 利用ParallelFor并行地过滤掉和阴影不相交的图元,收集和阴影相交的图元。
    • 收集最后阶段,将受阴影影响的图元加入阴影实例的SubjectPrimitive列表中,清理之前申请的资源。
  • 调用AllocateShadowDepthTargets分配阴影图所需的渲染纹理:

    • 初始化不同类型的指定了分配器的阴影列表。
    • 遍历所有光源,针对每个光源:
      • 遍历光源的所有阴影实例,针对每个阴影实例:
        • 检测阴影是否至少在一个view中可见。
        • 检测阴影缓存模式为可移动图元时的条件可见性。
        • 其它特殊的可见性判断。
        • 如果阴影可见,根据不同类型加入到不同的阴影实例列表中。
      • 排序级联阴影,因为在级联之间的混合要求是有序的。
      • 调用AllocateCSMDepthTargets分配CSM深度渲染纹理。
      • 处理PreShadow。
      • 依次分配点光源cubemap、RSM、缓存的聚光灯、逐物体、透明阴影的渲染纹理。
      • 更新透明阴影图的uniform buffer。
      • 删除完全没有被使用的阴影缓存。
  • 调用GatherShadowDynamicMeshElements收集阴影的动态网格元素:

    • 遍历所有阴影图图集(ShadowMapAtlases),收集每个图集内的所有阴影实例的网格元素。
    • 遍历所有RSM阴影图图集(RSMAtlases),收集每个图集内的所有阴影实例的网格元素。
    • 遍历所有点光源立方体阴影图(ShadowMapCubemaps),收集每个立方体阴影图内的所有阴影实例的网格元素。
    • 遍历所有PreShadow缓存的阴影图(PreshadowCache),收集阴影实例的网格元素。
    • 遍历所有透明物体阴影图图集(TranslucencyShadowMapAtlases),收集每个图集内的所有阴影实例的网格元素。

阴影初始化总结完了,由此可知阴影的处理非常非常复杂,涉及的逻辑和优化技术甚多。这里粗略总结一下阴影初始化阶段涉及的优化技巧

  • 利用物体(视图、光源、阴影、图元)的简单形状做相交测试,剔除不相交的阴影元素。
  • 利用各类标记(物体、视图、控制台、全局变量等等)及衍生标记,剔除不符合的阴影元素。
  • 利用中间数据(过渡因子、屏幕尺寸大小、深度值等等)剔除不符合的阴影元素。
  • 特殊数据结构(纹理布局、阴影图集、八叉树、连续线性数组)和遍历方式(并行、八叉树、线性)提升执行效果。
  • 充分利用缓存(PreShadowCache、潜在可见性等)减少渲染效果。
  • 对阴影类型进行排序,减少渲染状态切换,减少CPU和GPU交互数据,提升缓存命中率。
  • 不同粒度的遮挡剔除。
void FSceneRenderer::InitDynamicShadows(FRHICommandListImmediate& RHICmdList, FGlobalDynamicIndexBuffer& DynamicIndexBuffer, FGlobalDynamicVertexBuffer& DynamicVertexBuffer, FGlobalDynamicReadBuffer& DynamicReadBuffer)
{
	SCOPE_CYCLE_COUNTER(STAT_DynamicShadowSetupTime);
	CSV_SCOPED_TIMING_STAT_EXCLUSIVE(InitViews_Shadows);
	SCOPED_NAMED_EVENT(FSceneRenderer_InitDynamicShadows, FColor::Magenta);

	const bool bMobile = FeatureLevel < ERHIFeatureLevel::SM5;

	bool bStaticSceneOnly = false;

	for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
	{
		FViewInfo& View = Views[ViewIndex];
		bStaticSceneOnly = bStaticSceneOnly || View.bStaticSceneOnly;
	}

	const bool bProjectEnablePointLightShadows = Scene->ReadOnlyCVARCache.bEnablePointLightShadows && !bMobile; // Point light shadow is unsupported on mobile for now.
	const bool bProjectEnableMovableDirectionLightShadows = !bMobile || Scene->ReadOnlyCVARCache.bMobileAllowMovableDirectionalLights;
	const bool bProjectEnableMovableSpotLightShadows = !bMobile || Scene->ReadOnlyCVARCache.bMobileEnableMovableSpotlightsShadow;

	uint32 NumPointShadowCachesUpdatedThisFrame = 0;
	uint32 NumSpotShadowCachesUpdatedThisFrame = 0;

	TArray<FProjectedShadowInfo*,SceneRenderingAllocator> PreShadows;
	TArray<FProjectedShadowInfo*,SceneRenderingAllocator> ViewDependentWholeSceneShadows;
	TArray<FProjectedShadowInfo*,SceneRenderingAllocator> ViewDependentWholeSceneShadowsThatNeedCulling;
	{
		SCOPE_CYCLE_COUNTER(STAT_InitDynamicShadowsTime);
		CSV_SCOPED_TIMING_STAT_EXCLUSIVE(ShadowInitDynamic);

		for (TSparseArray<FLightSceneInfoCompact>::TConstIterator LightIt(Scene->Lights); LightIt; ++LightIt)
		{
			const FLightSceneInfoCompact& LightSceneInfoCompact = *LightIt;
			FLightSceneInfo* LightSceneInfo = LightSceneInfoCompact.LightSceneInfo;

			FScopeCycleCounter Context(LightSceneInfo->Proxy->GetStatId());

			FVisibleLightInfo& VisibleLightInfo = VisibleLightInfos[LightSceneInfo->Id];

			const FLightOcclusionType OcclusionType = GetLightOcclusionType(LightSceneInfoCompact);
			if (OcclusionType != FLightOcclusionType::Shadowmap)
				continue;

			// Only consider lights that may have shadows.
			if ((LightSceneInfoCompact.bCastStaticShadow || LightSceneInfoCompact.bCastDynamicShadow) && GetShadowQuality() > 0)
			{
				// see if the light is visible in any view
				bool bIsVisibleInAnyView = false;

				for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
				{
					// View frustums are only checked when lights have visible primitives or have modulated shadows,
					// so we don't need to check for that again here
					bIsVisibleInAnyView = LightSceneInfo->ShouldRenderLight(Views[ViewIndex]);

					if (bIsVisibleInAnyView) 
					{
						break;
					}
				}

				if (bIsVisibleInAnyView)
				{
					static const auto AllowStaticLightingVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.AllowStaticLighting"));
					const bool bAllowStaticLighting = (!AllowStaticLightingVar || AllowStaticLightingVar->GetValueOnRenderThread() != 0);
					const bool bPointLightShadow = LightSceneInfoCompact.LightType == LightType_Point || LightSceneInfoCompact.LightType == LightType_Rect;
					const bool bDirectionalLightShadow = LightSceneInfoCompact.LightType == LightType_Directional;
					const bool bSpotLightShadow = LightSceneInfoCompact.LightType == LightType_Spot;

					// Only create whole scene shadows for lights that don't precompute shadowing (movable lights)
					const bool bShouldCreateShadowForMovableLight = 
						LightSceneInfoCompact.bCastDynamicShadow
						&& (!LightSceneInfo->Proxy->HasStaticShadowing() || !bAllowStaticLighting);

					const bool bCreateShadowForMovableLight = 
						bShouldCreateShadowForMovableLight
						&& (!bPointLightShadow || bProjectEnablePointLightShadows)
						&& (!bDirectionalLightShadow || bProjectEnableMovableDirectionLightShadows)
						&& (!bSpotLightShadow || bProjectEnableMovableSpotLightShadows);

					// Also create a whole scene shadow for lights with precomputed shadows that are unbuilt
					const bool bShouldCreateShadowToPreviewStaticLight =
						LightSceneInfo->Proxy->HasStaticShadowing()
						&& LightSceneInfoCompact.bCastStaticShadow
						&& !LightSceneInfo->IsPrecomputedLightingValid();						

					const bool bCreateShadowToPreviewStaticLight = 
						bShouldCreateShadowToPreviewStaticLight						
						&& (!bPointLightShadow || bProjectEnablePointLightShadows)
						// Stationary point light and spot light shadow are unsupported on mobile
						&& (!bMobile || bDirectionalLightShadow);

					// Create a whole scene shadow for lights that want static shadowing but didn't get assigned to a valid shadowmap channel due to overlap
					const bool bShouldCreateShadowForOverflowStaticShadowing =
						LightSceneInfo->Proxy->HasStaticShadowing()
						&& !LightSceneInfo->Proxy->HasStaticLighting()
						&& LightSceneInfoCompact.bCastStaticShadow
						&& LightSceneInfo->IsPrecomputedLightingValid()
						&& LightSceneInfo->Proxy->GetShadowMapChannel() == INDEX_NONE;

					const bool bCreateShadowForOverflowStaticShadowing =
						bShouldCreateShadowForOverflowStaticShadowing
						&& (!bPointLightShadow || bProjectEnablePointLightShadows)
						// Stationary point light and spot light shadow are unsupported on mobile
						&& (!bMobile || bDirectionalLightShadow);

					const bool bPointLightWholeSceneShadow = (bShouldCreateShadowForMovableLight || bShouldCreateShadowForOverflowStaticShadowing || bShouldCreateShadowToPreviewStaticLight) && bPointLightShadow;
					if (bPointLightWholeSceneShadow)
					{						
						UsedWholeScenePointLightNames.Add(LightSceneInfoCompact.LightSceneInfo->Proxy->GetComponentName());
					}

					if (bCreateShadowForMovableLight || bCreateShadowToPreviewStaticLight || bCreateShadowForOverflowStaticShadowing)
					{
						// Try to create a whole scene projected shadow.
						CreateWholeSceneProjectedShadow(LightSceneInfo, NumPointShadowCachesUpdatedThisFrame, NumSpotShadowCachesUpdatedThisFrame);
					}

					// Allow movable and stationary lights to create CSM, or static lights that are unbuilt
					if ((!LightSceneInfo->Proxy->HasStaticLighting() && LightSceneInfoCompact.bCastDynamicShadow) || bCreateShadowToPreviewStaticLight)
					{
						static_assert(UE_ARRAY_COUNT(Scene->MobileDirectionalLights) == 3, "All array entries for MobileDirectionalLights must be checked");
						if( !bMobile ||
							((LightSceneInfo->Proxy->UseCSMForDynamicObjects() || LightSceneInfo->Proxy->IsMovable()) 
								// Mobile uses the scene's MobileDirectionalLights only for whole scene shadows.
								&& (LightSceneInfo == Scene->MobileDirectionalLights[0] || LightSceneInfo == Scene->MobileDirectionalLights[1] || LightSceneInfo == Scene->MobileDirectionalLights[2])))
						{
							AddViewDependentWholeSceneShadowsForView(ViewDependentWholeSceneShadows, ViewDependentWholeSceneShadowsThatNeedCulling, VisibleLightInfo, *LightSceneInfo);
						}

						if( !bMobile || (LightSceneInfo->Proxy->CastsModulatedShadows() && !LightSceneInfo->Proxy->UseCSMForDynamicObjects()))
						{
							Scene->FlushAsyncLightPrimitiveInteractionCreation();

							const TArray<FLightPrimitiveInteraction*>* InteractionShadowPrimitives = LightSceneInfo->GetInteractionShadowPrimitives(false);

							if (InteractionShadowPrimitives)
							{
								const int32 NumPrims = InteractionShadowPrimitives->Num();
								for (int32 Idx = 0; Idx < NumPrims; ++Idx)
								{
									SetupInteractionShadows(RHICmdList, (*InteractionShadowPrimitives)[Idx], VisibleLightInfo, bStaticSceneOnly, ViewDependentWholeSceneShadows, PreShadows);
								}
							}
							else
							{
								// Look for individual primitives with a dynamic shadow.
								for (FLightPrimitiveInteraction* Interaction = LightSceneInfo->GetDynamicInteractionOftenMovingPrimitiveList(false);
									Interaction;
									Interaction = Interaction->GetNextPrimitive()
									)
								{
									SetupInteractionShadows(RHICmdList, Interaction, VisibleLightInfo, bStaticSceneOnly, ViewDependentWholeSceneShadows, PreShadows);
								}

								for (FLightPrimitiveInteraction* Interaction = LightSceneInfo->GetDynamicInteractionStaticPrimitiveList(false);
									Interaction;
									Interaction = Interaction->GetNextPrimitive()
									)
								{
									SetupInteractionShadows(RHICmdList, Interaction, VisibleLightInfo, bStaticSceneOnly, ViewDependentWholeSceneShadows, PreShadows);
								}
							}
						}
					}
				}
			}
		}

		CSV_CUSTOM_STAT(LightCount, UpdatedShadowMaps, float(NumPointShadowCachesUpdatedThisFrame + NumSpotShadowCachesUpdatedThisFrame), ECsvCustomStatOp::Set);
		CSV_CUSTOM_STAT_GLOBAL(ShadowCacheUsageMB, (float(Scene->GetCachedWholeSceneShadowMapsSize()) / 1024) / 1024, ECsvCustomStatOp::Set);

		// Calculate visibility of the projected shadows.
		InitProjectedShadowVisibility(RHICmdList);
	}

	// Clear old preshadows and attempt to add new ones to the cache
	UpdatePreshadowCache(FSceneRenderTargets::Get(RHICmdList));

	// Gathers the list of primitives used to draw various shadow types
	GatherShadowPrimitives(PreShadows, ViewDependentWholeSceneShadowsThatNeedCulling, bStaticSceneOnly);

	AllocateShadowDepthTargets(RHICmdList);

	// Generate mesh element arrays from shadow primitive arrays
	GatherShadowDynamicMeshElements(DynamicIndexBuffer, DynamicVertexBuffer, DynamicReadBuffer);

}

参考:剖析虚幻渲染体系(05)- 光源和阴影 - 0向往0 - 博客园

enum class FLightOcclusionType : uint8
{
	Shadowmap,
	Raytraced,
};

FLightOcclusionType GetLightOcclusionType(const FLightSceneInfoCompact& LightInfo)
{
#if RHI_RAYTRACING
	return ShouldRenderRayTracingShadowsForLight(LightInfo) ? FLightOcclusionType::Raytraced : FLightOcclusionType::Shadowmap;
#else
	return FLightOcclusionType::Shadowmap;
#endif
}

bool ShouldRenderRayTracingShadowsForLight(const FLightSceneInfoCompact& LightInfo)
{
	return ShouldRenderRayTracingShadows() && LightInfo.bCastRaytracedShadow
		&& ShouldRenderRayTracingShadowsForLightType((ELightComponentType)LightInfo.LightType);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值