From 14077c156068962ba4386bfc273f0aaab96aeac6 Mon Sep 17 00:00:00 2001 From: BlueRose <378100977@qq.com> Date: Tue, 10 Dec 2024 19:12:19 +0800 Subject: [PATCH] vault backup: 2024-12-10 19:12:19 --- .../渲染功能/阴影控制/ToonShadow.md | 167 +++++++++++++++++- 1 file changed, 165 insertions(+), 2 deletions(-) diff --git a/03-UnrealEngine/卡通渲染相关资料/渲染功能/阴影控制/ToonShadow.md b/03-UnrealEngine/卡通渲染相关资料/渲染功能/阴影控制/ToonShadow.md index 22f210f..86fa718 100644 --- a/03-UnrealEngine/卡通渲染相关资料/渲染功能/阴影控制/ToonShadow.md +++ b/03-UnrealEngine/卡通渲染相关资料/渲染功能/阴影控制/ToonShadow.md @@ -6,6 +6,8 @@ tags: rating: ⭐ --- # 阴影 +- [剖析虚幻渲染体系(05)- 光源和阴影](https://www.cnblogs.com/timlly/p/14817455.html) + ## 阴影类型 - **Static Shadow** - **Cascading Shadow Map** @@ -32,7 +34,168 @@ PS. UE5.3中相关逻辑移动到***CreateDynamicShadows()*** 中了。InitDynam - AddViewDependentWholeSceneShadowsForView() - SetupInteractionShadows() - ***CreatePerObjectProjectedShadow()*** +- InitProjectedShadowVisibility() +丛越文章中的注释: +```c++ +void FSceneRenderer::InitDynamicShadows(FRHICommandListImmediate& RHICmdList, FGlobalDynamicIndexBuffer& DynamicIndexBuffer, FGlobalDynamicVertexBuffer& DynamicVertexBuffer, FGlobalDynamicReadBuffer& DynamicReadBuffer) +{ + // 初始化各类标记和数量. + 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; + uint32 NumPointShadowCachesUpdatedThisFrame = 0; + uint32 NumSpotShadowCachesUpdatedThisFrame = 0; + + // 预计算阴影. + TArray<FProjectedShadowInfo*,SceneRenderingAllocator> PreShadows; + // 视图关联的全景阴影. + TArray<FProjectedShadowInfo*,SceneRenderingAllocator> ViewDependentWholeSceneShadows; + // 视图关联的需要裁剪的全景阴影. + TArray<FProjectedShadowInfo*,SceneRenderingAllocator> ViewDependentWholeSceneShadowsThatNeedCulling; + { + // 遍历所有光源, 将不同类型的光源加入不同类型的待渲染的阴影列表中. + 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]; + + // LightOcclusionType有阴影图和光追两种, 如果非阴影图类型, 则忽略. + const FLightOcclusionType OcclusionType = GetLightOcclusionType(LightSceneInfoCompact); + if (OcclusionType != FLightOcclusionType::Shadowmap) + continue; + + // 如果光源没有开启阴影或阴影质量太小, 则忽略阴影图. + if ((LightSceneInfoCompact.bCastStaticShadow || LightSceneInfoCompact.bCastDynamicShadow) && GetShadowQuality() > 0) + { + // 检测该光源是否在某个view里可见, 如果不可见, 则忽略. + bool bIsVisibleInAnyView = false; + for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) + { + 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; + + // 对不预计算阴影的移动光源只创建全景阴影(whole scene shadow). + const bool bShouldCreateShadowForMovableLight = + LightSceneInfoCompact.bCastDynamicShadow + && (!LightSceneInfo->Proxy->HasStaticShadowing() || !bAllowStaticLighting); + + const bool bCreateShadowForMovableLight = + bShouldCreateShadowForMovableLight + && (!bPointLightShadow || bProjectEnablePointLightShadows); + + // 对带有预计算阴影的尚未构建的光源创建全景阴影. + const bool bShouldCreateShadowToPreviewStaticLight = + LightSceneInfo->Proxy->HasStaticShadowing() + && LightSceneInfoCompact.bCastStaticShadow + && !LightSceneInfo->IsPrecomputedLightingValid(); + + const bool bCreateShadowToPreviewStaticLight = + bShouldCreateShadowToPreviewStaticLight + && (!bPointLightShadow || bProjectEnablePointLightShadows); + + // 对需要静态阴影但由于重叠导致没有有效阴影图的光源创建全景阴影. + const bool bShouldCreateShadowForOverflowStaticShadowing = + LightSceneInfo->Proxy->HasStaticShadowing() + && !LightSceneInfo->Proxy->HasStaticLighting() + && LightSceneInfoCompact.bCastStaticShadow + && LightSceneInfo->IsPrecomputedLightingValid() + && LightSceneInfo->Proxy->GetShadowMapChannel() == INDEX_NONE; + + const bool bCreateShadowForOverflowStaticShadowing = + bShouldCreateShadowForOverflowStaticShadowing + && (!bPointLightShadow || bProjectEnablePointLightShadows); + + // 添加点光源的全景阴影. + const bool bPointLightWholeSceneShadow = (bShouldCreateShadowForMovableLight || bShouldCreateShadowForOverflowStaticShadowing || bShouldCreateShadowToPreviewStaticLight) && bPointLightShadow; + if (bPointLightWholeSceneShadow) + { + UsedWholeScenePointLightNames.Add(LightSceneInfoCompact.LightSceneInfo->Proxy->GetComponentName()); + } + + // 创建光源的全景阴影. + if (bCreateShadowForMovableLight || bCreateShadowToPreviewStaticLight || bCreateShadowForOverflowStaticShadowing) + { + CreateWholeSceneProjectedShadow(LightSceneInfo, NumPointShadowCachesUpdatedThisFrame, NumSpotShadowCachesUpdatedThisFrame); + } + + // 允许移动和固定的光源创建CSM(级联阴影), 或者是尚未构建的静态光源. + if ((!LightSceneInfo->Proxy->HasStaticLighting() && LightSceneInfoCompact.bCastDynamicShadow) || bCreateShadowToPreviewStaticLight) + { + // 增加视图关联的全景阴影. + if( !bMobile || + ((LightSceneInfo->Proxy->UseCSMForDynamicObjects() || LightSceneInfo->Proxy->IsMovable()) + && (LightSceneInfo == Scene->MobileDirectionalLights[0] || LightSceneInfo == Scene->MobileDirectionalLights[1] || LightSceneInfo == Scene->MobileDirectionalLights[2]))) + { + AddViewDependentWholeSceneShadowsForView(ViewDependentWholeSceneShadows, ViewDependentWholeSceneShadowsThatNeedCulling, VisibleLightInfo, *LightSceneInfo); + } + + // 处理交互阴影, 此处的交互是指光源和图元之间的影响. 包含PerObject阴影、透明阴影、自阴影等. + if( !bMobile || (LightSceneInfo->Proxy->CastsModulatedShadows() && !LightSceneInfo->Proxy->UseCSMForDynamicObjects())) + { + Scene->FlushAsyncLightPrimitiveInteractionCreation(); + + // 处理动态图元的交互阴影. + 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); + } + } + } + } + } + } + + // 计算投射阴影的可见性. + InitProjectedShadowVisibility(RHICmdList); + } + + // 清理旧的预计算阴影, 尝试增加新的到缓存中. + UpdatePreshadowCache(FSceneRenderTargets::Get(RHICmdList)); + + // 收集图元列表, 以绘制不同类型的阴影. + GatherShadowPrimitives(PreShadows, ViewDependentWholeSceneShadowsThatNeedCulling, bStaticSceneOnly); + + // 分配阴影深度渲染纹理. + AllocateShadowDepthTargets(RHICmdList); + + // 收集阴影的动态网格元素, 跟之前剖析的GatherDynamicMeshElements类似. + GatherShadowDynamicMeshElements(DynamicIndexBuffer, DynamicVertexBuffer, DynamicReadBuffer); +} +``` + + +### 阴影渲染 # 阴影偏移 @@ -41,8 +204,8 @@ PS. UE5.3中相关逻辑移动到***CreateDynamicShadows()*** 中了。InitDynam - CustomDepth # 相关Paas -1. ShadowDepths -2. Lights +1. ShadowDepths => RenderShadowDepthMaps() +2. Lights => RenderLights() 1. DirectLighting 1. UnbatchedLights 1. ShadowProjectionOnOpaque