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 updatesCreateIndirectCapsuleShadows();// 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_RAYTRACINGView.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 PreShadows;TArray ViewDependentWholeSceneShadows;TArray ViewDependentWholeSceneShadowsThatNeedCulling;{SCOPE_CYCLE_COUNTER(STAT_InitDynamicShadowsTime);CSV_SCOPED_TIMING_STAT_EXCLUSIVE(ShadowInitDynamic);for (TSparseArray::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 viewbool 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 herebIsVisibleInAnyView = 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 unbuiltconst 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 overlapconst 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 unbuiltif ((!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* 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 cacheUpdatePreshadowCache(FSceneRenderTargets::Get(RHICmdList));// Gathers the list of primitives used to draw various shadow typesGatherShadowPrimitives(PreShadows, ViewDependentWholeSceneShadowsThatNeedCulling, bStaticSceneOnly);AllocateShadowDepthTargets(RHICmdList);// Generate mesh element arrays from shadow primitive arraysGatherShadowDynamicMeshElements(DynamicIndexBuffer, DynamicVertexBuffer, DynamicReadBuffer);}

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

enum class FLightOcclusionType : uint8
{Shadowmap,Raytraced,
};FLightOcclusionType GetLightOcclusionType(const FLightSceneInfoCompact& LightInfo)
{
#if RHI_RAYTRACINGreturn ShouldRenderRayTracingShadowsForLight(LightInfo) ? FLightOcclusionType::Raytraced : FLightOcclusionType::Shadowmap;
#elsereturn FLightOcclusionType::Shadowmap;
#endif
}bool ShouldRenderRayTracingShadowsForLight(const FLightSceneInfoCompact& LightInfo)
{return ShouldRenderRayTracingShadows() && LightInfo.bCastRaytracedShadow&& ShouldRenderRayTracingShadowsForLightType((ELightComponentType)LightInfo.LightType);
}


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部