PassProcessor注册:
- Engine/Source/Runtime/Renderer/Private/BasePassRendering.cpp
- 透明的5个PassProcessor都继承BassPassProcessor。
- 透明物质绘制,也是走的basepasspixelshader。
REGISTER_MESHPASSPROCESSOR_AND_PSOCOLLECTOR(BasePass, CreateBasePassProcessor, EShadingPath::Deferred, EMeshPass::BasePass, EMeshPassFlags::CachedMeshCommands | EMeshPassFlags::MainView);
REGISTER_MESHPASSPROCESSOR_AND_PSOCOLLECTOR(TranslucencyStandardPass, CreateTranslucencyStandardPassProcessor, EShadingPath::Deferred, EMeshPass::TranslucencyStandard, EMeshPassFlags::MainView);
REGISTER_MESHPASSPROCESSOR_AND_PSOCOLLECTOR(TranslucencyAfterDOFPass, CreateTranslucencyAfterDOFProcessor, EShadingPath::Deferred, EMeshPass::TranslucencyAfterDOF, EMeshPassFlags::MainView);
REGISTER_MESHPASSPROCESSOR_AND_PSOCOLLECTOR(TranslucencyAfterDOFModulatePass, CreateTranslucencyAfterDOFModulateProcessor, EShadingPath::Deferred, EMeshPass::TranslucencyAfterDOFModulate, EMeshPassFlags::MainView);
REGISTER_MESHPASSPROCESSOR_AND_PSOCOLLECTOR(TranslucencyAfterMotionBlurPass, CreateTranslucencyAfterMotionBlurProcessor, EShadingPath::Deferred, EMeshPass::TranslucencyAfterMotionBlur, EMeshPassFlags::MainView);
REGISTER_MESHPASSPROCESSOR_AND_PSOCOLLECTOR(TranslucencyAllPass, CreateTranslucencyAllPassProcessor, EShadingPath::Deferred, EMeshPass::TranslucencyAll, EMeshPassFlags::MainView);
FMeshPassProcessor* CreateTranslucencyAfterDOFProcessor(ERHIFeatureLevel::Type FeatureLevel, const FScene* Scene, const FSceneView* InViewIfDynamicMeshCommand, FMeshPassDrawListContext* InDrawListContext)
{FMeshPassProcessorRenderState PassDrawRenderState;PassDrawRenderState.SetDepthStencilState(TStaticDepthStencilState<false, CF_DepthNearOrEqual>::GetRHI());const FBasePassMeshProcessor::EFlags Flags = FBasePassMeshProcessor::EFlags::CanUseDepthStencil;return new FBasePassMeshProcessor(EMeshPass::TranslucencyAfterDOF, Scene, FeatureLevel, InViewIfDynamicMeshCommand, PassDrawRenderState, InDrawListContext, Flags, ETranslucencyPass::TPT_TranslucencyAfterDOF);
}
绘制准备
FSceneRenderer::ComputeViewVisibility -> FSceneRenderer::SetupMeshPass
void FSceneRenderer::SetupMeshPass(FViewInfo& View, FExclusiveDepthStencil::Type BasePassDepthStencilAccess, FViewCommands& ViewCommands, FInstanceCullingManager& InstanceCullingManager)
{SCOPE_CYCLE_COUNTER(STAT_SetupMeshPass);const EShadingPath ShadingPath = Scene->GetShadingPath();for (int32 PassIndex = 0; PassIndex < EMeshPass::Num; PassIndex++){const EMeshPass::Type PassType = (EMeshPass::Type)PassIndex;if ((FPassProcessorManager::GetPassFlags(ShadingPath, PassType) & EMeshPassFlags::MainView) != EMeshPassFlags::None){// Mobile: BasePass and MobileBasePassCSM lists need to be merged and sorted after shadow pass.if (ShadingPath == EShadingPath::Mobile && (PassType == EMeshPass::BasePass || PassType == EMeshPass::MobileBasePassCSM)){continue;}if (ViewFamily.UseDebugViewPS() && ShadingPath == EShadingPath::Deferred){switch (PassType){case EMeshPass::DepthPass:case EMeshPass::CustomDepth:case EMeshPass::DebugViewMode:
#if WITH_EDITORcase EMeshPass::HitProxy:case EMeshPass::HitProxyOpaqueOnly:case EMeshPass::EditorSelection:case EMeshPass::EditorLevelInstance:
#endifbreak;default:continue;}}FMeshPassProcessor* MeshPassProcessor = FPassProcessorManager::CreateMeshPassProcessor(ShadingPath, PassType, Scene->GetFeatureLevel(), Scene, &View, nullptr);FParallelMeshDrawCommandPass& Pass = View.ParallelMeshDrawCommandPasses[PassIndex];if (ShouldDumpMeshDrawCommandInstancingStats()){Pass.SetDumpInstancingStats(GetMeshPassName(PassType));}TArray<int32, TInlineAllocator<2> > ViewIds;ViewIds.Add(View.GPUSceneViewId);// Only apply instancing for ISR to main view passesconst bool bIsMainViewPass = PassType != EMeshPass::Num && (FPassProcessorManager::GetPassFlags(Scene->GetShadingPath(), PassType) & EMeshPassFlags::MainView) != EMeshPassFlags::None;EInstanceCullingMode InstanceCullingMode = bIsMainViewPass && View.IsInstancedStereoPass() ? EInstanceCullingMode::Stereo : EInstanceCullingMode::Normal;if (InstanceCullingMode == EInstanceCullingMode::Stereo){check(View.GetInstancedView() != nullptr);ViewIds.Add(View.GetInstancedView()->GPUSceneViewId);}EInstanceCullingFlags CullingFlags = EInstanceCullingFlags::None;if (ViewFamily.EngineShowFlags.DrawOnlyVSMInvalidatingGeo != 0){EnumAddFlags(CullingFlags, EInstanceCullingFlags::DrawOnlyVSMInvalidatingGeometry);}Pass.DispatchPassSetup(Scene,View,FInstanceCullingContext(FeatureLevel, &InstanceCullingManager, ViewIds, View.PrevViewInfo.HZB, InstanceCullingMode, CullingFlags),PassType,BasePassDepthStencilAccess,MeshPassProcessor,View.DynamicMeshElements,&View.DynamicMeshElementsPassRelevance,View.NumVisibleDynamicMeshElements[PassType],ViewCommands.DynamicMeshCommandBuildRequests[PassType],ViewCommands.NumDynamicMeshCommandBuildRequestElements[PassType],ViewCommands.MeshCommands[PassIndex]);}}
}
DispatchPassSetup函数参数准备流程(View. 和 ViewCommands.)
DispatchPassSetup函数实现流程
void FParallelMeshDrawCommandPass::DispatchPassSetup(FScene* Scene,const FViewInfo& View,FInstanceCullingContext&& InstanceCullingContext,EMeshPass::Type PassType,FExclusiveDepthStencil::Type BasePassDepthStencilAccess,FMeshPassProcessor* MeshPassProcessor,const TArray<FMeshBatchAndRelevance, SceneRenderingAllocator>& DynamicMeshElements,const TArray<FMeshPassMask, SceneRenderingAllocator>* DynamicMeshElementsPassRelevance,int32 NumDynamicMeshElements,TArray<const FStaticMeshBatch*, SceneRenderingAllocator>& InOutDynamicMeshCommandBuildRequests,int32 NumDynamicMeshCommandBuildRequestElements,FMeshCommandOneFrameArray& InOutMeshDrawCommands,FMeshPassProcessor* MobileBasePassCSMMeshPassProcessor,FMeshCommandOneFrameArray* InOutMobileBasePassCSMMeshDrawCommands
)
{TRACE_CPUPROFILER_EVENT_SCOPE(ParallelMdcDispatchPassSetup);check(!TaskEventRef.IsValid() && MeshPassProcessor != nullptr && TaskContext.PrimitiveIdBufferData == nullptr);check((PassType == EMeshPass::Num) == (DynamicMeshElementsPassRelevance == nullptr));MaxNumDraws = InOutMeshDrawCommands.Num() + NumDynamicMeshElements + NumDynamicMeshCommandBuildRequestElements;TaskContext.MeshPassProcessor = MeshPassProcessor;TaskContext.MobileBasePassCSMMeshPassProcessor = MobileBasePassCSMMeshPassProcessor;TaskContext.DynamicMeshElements = &DynamicMeshElements;TaskContext.DynamicMeshElementsPassRelevance = DynamicMeshElementsPassRelevance;TaskContext.View = &View;TaskContext.Scene = Scene;TaskContext.ShadingPath = Scene->GetShadingPath();TaskContext.ShaderPlatform = Scene->GetShaderPlatform();TaskContext.PassType = PassType;TaskContext.bUseGPUScene = UseGPUScene(GMaxRHIShaderPlatform, View.GetFeatureLevel());TaskContext.bDynamicInstancing = IsDynamicInstancingEnabled(View.GetFeatureLevel());TaskContext.bReverseCulling = View.bReverseCulling;TaskContext.bRenderSceneTwoSided = View.bRenderSceneTwoSided;TaskContext.BasePassDepthStencilAccess = BasePassDepthStencilAccess;TaskContext.DefaultBasePassDepthStencilAccess = Scene->DefaultBasePassDepthStencilAccess;TaskContext.NumDynamicMeshElements = NumDynamicMeshElements;TaskContext.NumDynamicMeshCommandBuildRequestElements = NumDynamicMeshCommandBuildRequestElements;// Only apply instancing for ISR to main view passesconst bool bIsMainViewPass = PassType != EMeshPass::Num && (FPassProcessorManager::GetPassFlags(TaskContext.ShadingPath, TaskContext.PassType) & EMeshPassFlags::MainView) != EMeshPassFlags::None;// GPUCULL_TODO: Note the InstanceFactor is ignored by the GPU-Scene supported instances, but is used for legacy primitives.TaskContext.InstanceFactor = (bIsMainViewPass && View.IsInstancedStereoPass()) ? 2 : 1;TaskContext.InstanceCullingContext = MoveTemp(InstanceCullingContext); // Setup translucency sort key update pass based on view.TaskContext.TranslucencyPass = ETranslucencyPass::TPT_MAX;TaskContext.TranslucentSortPolicy = View.TranslucentSortPolicy;TaskContext.TranslucentSortAxis = View.TranslucentSortAxis;TaskContext.ViewOrigin = View.ViewMatrices.GetViewOrigin();TaskContext.ViewMatrix = View.ViewMatrices.GetViewMatrix();TaskContext.PrimitiveBounds = &Scene->PrimitiveBounds;switch (PassType){case EMeshPass::TranslucencyStandard: TaskContext.TranslucencyPass = ETranslucencyPass::TPT_StandardTranslucency; break;case EMeshPass::TranslucencyAfterDOF: TaskContext.TranslucencyPass = ETranslucencyPass::TPT_TranslucencyAfterDOF; break;case EMeshPass::TranslucencyAfterDOFModulate: TaskContext.TranslucencyPass = ETranslucencyPass::TPT_TranslucencyAfterDOFModulate; break;case EMeshPass::TranslucencyAfterMotionBlur: TaskContext.TranslucencyPass = ETranslucencyPass::TPT_TranslucencyAfterMotionBlur; break;case EMeshPass::TranslucencyAll: TaskContext.TranslucencyPass = ETranslucencyPass::TPT_AllTranslucency; break;}FMemory::Memswap(&TaskContext.MeshDrawCommands, &InOutMeshDrawCommands, sizeof(InOutMeshDrawCommands));FMemory::Memswap(&TaskContext.DynamicMeshCommandBuildRequests, &InOutDynamicMeshCommandBuildRequests, sizeof(InOutDynamicMeshCommandBuildRequests));if (TaskContext.ShadingPath == EShadingPath::Mobile && TaskContext.PassType == EMeshPass::BasePass){FMemory::Memswap(&TaskContext.MobileBasePassCSMMeshDrawCommands, InOutMobileBasePassCSMMeshDrawCommands, sizeof(*InOutMobileBasePassCSMMeshDrawCommands));}else{check(MobileBasePassCSMMeshPassProcessor == nullptr && InOutMobileBasePassCSMMeshDrawCommands == nullptr);}if (MaxNumDraws > 0){// Preallocate resources on rendering thread based on MaxNumDraws.TaskContext.PrimitiveIdBufferDataSize = TaskContext.InstanceFactor * MaxNumDraws * sizeof(int32);TaskContext.PrimitiveIdBufferData = FMemory::Malloc(TaskContext.PrimitiveIdBufferDataSize);
#if DO_GUARD_SLOWFMemory::Memzero(TaskContext.PrimitiveIdBufferData, TaskContext.PrimitiveIdBufferDataSize);
#endif // DO_GUARD_SLOWTaskContext.MeshDrawCommands.Reserve(MaxNumDraws);TaskContext.TempVisibleMeshDrawCommands.Reserve(MaxNumDraws);const bool bExecuteInParallel = FApp::ShouldUseThreadingForPerformance()&& CVarMeshDrawCommandsParallelPassSetup.GetValueOnRenderThread() > 0&& GIsThreadedRendering; // Rendering thread is required to safely use rendering resources in parallel.if (bExecuteInParallel){if (IsOnDemandShaderCreationEnabled()){TaskEventRef = TGraphTask<FMeshDrawCommandPassSetupTask>::CreateTask(nullptr, ENamedThreads::GetRenderThread()).ConstructAndDispatchWhenReady(TaskContext);}else{FGraphEventArray DependentGraphEvents;DependentGraphEvents.Add(TGraphTask<FMeshDrawCommandPassSetupTask>::CreateTask(nullptr, ENamedThreads::GetRenderThread()).ConstructAndDispatchWhenReady(TaskContext));TaskEventRef = TGraphTask<FMeshDrawCommandInitResourcesTask>::CreateTask(&DependentGraphEvents, ENamedThreads::GetRenderThread()).ConstructAndDispatchWhenReady(TaskContext);}}else{QUICK_SCOPE_CYCLE_COUNTER(STAT_MeshPassSetupImmediate);FMeshDrawCommandPassSetupTask Task(TaskContext);Task.AnyThreadTask();if (!IsOnDemandShaderCreationEnabled()){FMeshDrawCommandInitResourcesTask DependentTask(TaskContext);DependentTask.AnyThreadTask();}}}
}
void AnyThreadTask(){FOptionalTaskTagScope Scope(ETaskTag::EParallelRenderingThread);SCOPED_NAMED_EVENT(MeshDrawCommandPassSetupTask, FColor::Magenta);// Mobile base pass is a special case, as final lists is created from two mesh passes based on CSM visibility.const bool bMobileShadingBasePass = Context.ShadingPath == EShadingPath::Mobile && Context.PassType == EMeshPass::BasePass;// On SM5 Mobile platform, still want the same sortingconst bool bMobileVulkanSM5BasePass = IsVulkanMobileSM5Platform(Context.ShaderPlatform) && Context.PassType == EMeshPass::BasePass;if (bMobileShadingBasePass){MergeMobileBasePassMeshDrawCommands(Context.View->MobileCSMVisibilityInfo,Context.PrimitiveBounds->Num(),Context.MeshDrawCommands,Context.MobileBasePassCSMMeshDrawCommands);GenerateMobileBasePassDynamicMeshDrawCommands(*Context.View,Context.ShadingPath,Context.PassType,Context.MeshPassProcessor,Context.MobileBasePassCSMMeshPassProcessor,*Context.DynamicMeshElements,Context.DynamicMeshElementsPassRelevance,Context.NumDynamicMeshElements,Context.DynamicMeshCommandBuildRequests,Context.NumDynamicMeshCommandBuildRequestElements,Context.MeshDrawCommands,Context.MeshDrawCommandStorage,Context.MinimalPipelineStatePassSet,Context.NeedsShaderInitialisation);}else{GenerateDynamicMeshDrawCommands(*Context.View,Context.ShadingPath,Context.PassType,Context.MeshPassProcessor,*Context.DynamicMeshElements,Context.DynamicMeshElementsPassRelevance,Context.NumDynamicMeshElements,Context.DynamicMeshCommandBuildRequests,Context.NumDynamicMeshCommandBuildRequestElements,Context.MeshDrawCommands,Context.MeshDrawCommandStorage,Context.MinimalPipelineStatePassSet,Context.NeedsShaderInitialisation);}if (Context.MeshDrawCommands.Num() > 0){if (Context.PassType != EMeshPass::Num){ApplyViewOverridesToMeshDrawCommands(Context.ShadingPath,Context.PassType,Context.bReverseCulling,Context.bRenderSceneTwoSided,Context.BasePassDepthStencilAccess,Context.DefaultBasePassDepthStencilAccess,Context.MeshDrawCommands,Context.MeshDrawCommandStorage,Context.MinimalPipelineStatePassSet,Context.NeedsShaderInitialisation,Context.TempVisibleMeshDrawCommands);}// Update sort keys.if (bMobileShadingBasePass || bMobileVulkanSM5BasePass){UpdateMobileBasePassMeshSortKeys(Context.ViewOrigin,*Context.PrimitiveBounds,Context.MeshDrawCommands);}else if (Context.TranslucencyPass != ETranslucencyPass::TPT_MAX){// When per-pixel OIT is enabled, sort primitive from front to back ensure avoid // constantly resorting front-to-back samples list.const bool bInverseSorting = OIT::IsEnabled(EOITSortingType::SortedPixels, Context.ShaderPlatform) && Context.View->AntiAliasingMethod != EAntiAliasingMethod::AAM_MSAA;UpdateTranslucentMeshSortKeys(Context.TranslucentSortPolicy,Context.TranslucentSortAxis,Context.ViewOrigin,Context.ViewMatrix,*Context.PrimitiveBounds,Context.TranslucencyPass,bInverseSorting,Context.MeshDrawCommands);}{QUICK_SCOPE_CYCLE_COUNTER(STAT_SortVisibleMeshDrawCommands);Context.MeshDrawCommands.Sort(FCompareFMeshDrawCommands());}if (Context.bUseGPUScene){TArrayView<const FStateBucketAuxData> StateBucketsAuxData;if (Context.PassType != EMeshPass::Num){StateBucketsAuxData = Context.Scene->CachedStateBucketsAuxData[Context.PassType];}Context.InstanceCullingContext.SetupDrawCommands(StateBucketsAuxData,Context.MeshDrawCommands, true, Context.MaxInstances, Context.VisibleMeshDrawCommandsNum, Context.NewPassVisibleMeshDrawCommandsNum);}}}
void GenerateDynamicMeshDrawCommands(const FViewInfo& View,EShadingPath ShadingPath,EMeshPass::Type PassType,FMeshPassProcessor* PassMeshProcessor,const TArray<FMeshBatchAndRelevance, SceneRenderingAllocator>& DynamicMeshElements,const TArray<FMeshPassMask, SceneRenderingAllocator>* DynamicMeshElementsPassRelevance,int32 MaxNumDynamicMeshElements,const TArray<const FStaticMeshBatch*, SceneRenderingAllocator>& DynamicMeshCommandBuildRequests,int32 MaxNumBuildRequestElements,FMeshCommandOneFrameArray& VisibleCommands,FDynamicMeshDrawCommandStorage& MeshDrawCommandStorage,FGraphicsMinimalPipelineStateSet& MinimalPipelineStatePassSet,bool& NeedsShaderInitialisation
)
{QUICK_SCOPE_CYCLE_COUNTER(STAT_GenerateDynamicMeshDrawCommands);check(PassMeshProcessor);check((PassType == EMeshPass::Num) == (DynamicMeshElementsPassRelevance == nullptr));FDynamicPassMeshDrawListContext DynamicPassMeshDrawListContext(MeshDrawCommandStorage,VisibleCommands,MinimalPipelineStatePassSet,NeedsShaderInitialisation);PassMeshProcessor->SetDrawListContext(&DynamicPassMeshDrawListContext);{const int32 NumCommandsBefore = VisibleCommands.Num();const int32 NumDynamicMeshBatches = DynamicMeshElements.Num();for (int32 MeshIndex = 0; MeshIndex < NumDynamicMeshBatches; MeshIndex++){if (!DynamicMeshElementsPassRelevance || (*DynamicMeshElementsPassRelevance)[MeshIndex].Get(PassType)){const FMeshBatchAndRelevance& MeshAndRelevance = DynamicMeshElements[MeshIndex];const uint64 BatchElementMask = ~0ull;PassMeshProcessor->AddMeshBatch(*MeshAndRelevance.Mesh, BatchElementMask, MeshAndRelevance.PrimitiveSceneProxy);}}const int32 NumCommandsGenerated = VisibleCommands.Num() - NumCommandsBefore;checkf(NumCommandsGenerated <= MaxNumDynamicMeshElements,TEXT("Generated %d mesh draw commands for DynamicMeshElements, while preallocating resources only for %d of them."), NumCommandsGenerated, MaxNumDynamicMeshElements);}{const int32 NumCommandsBefore = VisibleCommands.Num();const int32 NumStaticMeshBatches = DynamicMeshCommandBuildRequests.Num();for (int32 MeshIndex = 0; MeshIndex < NumStaticMeshBatches; MeshIndex++){const FStaticMeshBatch* StaticMeshBatch = DynamicMeshCommandBuildRequests[MeshIndex];const uint64 DefaultBatchElementMask = ~0ul;PassMeshProcessor->AddMeshBatch(*StaticMeshBatch, DefaultBatchElementMask, StaticMeshBatch->PrimitiveSceneInfo->Proxy, StaticMeshBatch->Id);}const int32 NumCommandsGenerated = VisibleCommands.Num() - NumCommandsBefore;checkf(NumCommandsGenerated <= MaxNumBuildRequestElements,TEXT("Generated %d mesh draw commands for DynamicMeshCommandBuildRequests, while preallocating resources only for %d of them."), NumCommandsGenerated, MaxNumBuildRequestElements);}
}
void FBasePassMeshProcessor::AddMeshBatch(const FMeshBatch& RESTRICT MeshBatch, uint64 BatchElementMask, const FPrimitiveSceneProxy* RESTRICT PrimitiveSceneProxy, int32 StaticMeshId)
{if (MeshBatch.bUseForMaterial){// Determine the mesh's material and blend mode.const FMaterialRenderProxy* MaterialRenderProxy = MeshBatch.MaterialRenderProxy;while (MaterialRenderProxy){const FMaterial* Material = MaterialRenderProxy->GetMaterialNoFallback(FeatureLevel);if (Material && Material->GetRenderingThreadShaderMap()){if (TryAddMeshBatch(MeshBatch, BatchElementMask, PrimitiveSceneProxy, StaticMeshId, *MaterialRenderProxy, *Material)){break;}}MaterialRenderProxy = MaterialRenderProxy->GetFallback(FeatureLevel);}}
}
bool FBasePassMeshProcessor::TryAddMeshBatch(const FMeshBatch& RESTRICT MeshBatch, uint64 BatchElementMask, const FPrimitiveSceneProxy* RESTRICT PrimitiveSceneProxy, int32 StaticMeshId, const FMaterialRenderProxy& MaterialRenderProxy, const FMaterial& Material)
{// Determine the mesh's material and blend mode.const EBlendMode BlendMode = Material.GetBlendMode();const FMaterialShadingModelField ShadingModels = Material.GetShadingModels();const bool bIsTranslucent = IsTranslucentBlendMode(BlendMode);const FMeshDrawingPolicyOverrideSettings OverrideSettings = ComputeMeshOverrideSettings(MeshBatch);const ERasterizerFillMode MeshFillMode = ComputeMeshFillMode(Material, OverrideSettings);const ERasterizerCullMode MeshCullMode = ComputeMeshCullMode(Material, OverrideSettings);bool bShouldDraw = ShouldDraw(Material);// Only draw opaque materials.bool bResult = true;if (bShouldDraw&& (!PrimitiveSceneProxy || PrimitiveSceneProxy->ShouldRenderInMainPass())&& ShouldIncludeDomainInMeshPass(Material.GetMaterialDomain())&& ShouldIncludeMaterialInDefaultOpaquePass(Material)){// Check for a cached light-map.const bool bIsLitMaterial = ShadingModels.IsLit();const bool bAllowStaticLighting = AllowStaticLighting();const FLightMapInteraction LightMapInteraction = (bAllowStaticLighting && MeshBatch.LCI && bIsLitMaterial)? MeshBatch.LCI->GetLightMapInteraction(FeatureLevel): FLightMapInteraction();const bool bAllowIndirectLightingCache = Scene && Scene->PrecomputedLightVolumes.Num() > 0;const bool bUseVolumetricLightmap = Scene && Scene->VolumetricLightmapSceneData.HasData();FMeshMaterialShaderElementData MeshMaterialShaderElementData;MeshMaterialShaderElementData.InitializeMeshMaterialData(ViewIfDynamicMeshCommand, PrimitiveSceneProxy, MeshBatch, StaticMeshId, true);// Render volumetric translucent self-shadowing only for >= SM4 and fallback to non-shadowed for lesser shader modelsif (bIsLitMaterial&& bIsTranslucent&& PrimitiveSceneProxy&& PrimitiveSceneProxy->CastsVolumetricTranslucentShadow()){checkSlow(ViewIfDynamicMeshCommand && ViewIfDynamicMeshCommand->bIsViewInfo);const FViewInfo* ViewInfo = (FViewInfo*)ViewIfDynamicMeshCommand;const int32 PrimitiveIndex = PrimitiveSceneProxy->GetPrimitiveSceneInfo()->GetIndex();const FUniformBufferRHIRef* UniformBufferPtr = ViewInfo->TranslucentSelfShadowUniformBufferMap.Find(PrimitiveIndex);FSelfShadowLightCacheElementData ElementData;ElementData.LCI = MeshBatch.LCI;ElementData.SelfShadowTranslucencyUniformBuffer = UniformBufferPtr ? (*UniformBufferPtr).GetReference() : GEmptyTranslucentSelfShadowUniformBuffer.GetUniformBufferRHI();if (bIsLitMaterial&& bAllowStaticLighting&& bUseVolumetricLightmap&& PrimitiveSceneProxy){bResult = Process< FSelfShadowedVolumetricLightmapPolicy >(MeshBatch,BatchElementMask,StaticMeshId,PrimitiveSceneProxy,MaterialRenderProxy,Material,BlendMode,ShadingModels,FSelfShadowedVolumetricLightmapPolicy(),ElementData,MeshFillMode,MeshCullMode);}else if (IsIndirectLightingCacheAllowed(FeatureLevel)&& bAllowIndirectLightingCache&& PrimitiveSceneProxy){// Apply cached point indirect lighting as well as self shadowing if neededbResult = Process< FSelfShadowedCachedPointIndirectLightingPolicy >(MeshBatch,BatchElementMask,StaticMeshId,PrimitiveSceneProxy,MaterialRenderProxy,Material,BlendMode,ShadingModels,FSelfShadowedCachedPointIndirectLightingPolicy(),ElementData,MeshFillMode,MeshCullMode);}else{bResult = Process< FSelfShadowedTranslucencyPolicy >(MeshBatch,BatchElementMask,StaticMeshId,PrimitiveSceneProxy,MaterialRenderProxy,Material,BlendMode,ShadingModels,FSelfShadowedTranslucencyPolicy(),ElementData.SelfShadowTranslucencyUniformBuffer,MeshFillMode,MeshCullMode);}}else{ELightMapPolicyType UniformLightMapPolicyType = GetUniformLightMapPolicyType(FeatureLevel, Scene, MeshBatch, PrimitiveSceneProxy, Material);bResult = Process< FUniformLightMapPolicy >(MeshBatch,BatchElementMask,StaticMeshId,PrimitiveSceneProxy,MaterialRenderProxy,Material,BlendMode,ShadingModels,FUniformLightMapPolicy(UniformLightMapPolicyType),MeshBatch.LCI,MeshFillMode,MeshCullMode);}}return bResult;
}
template<typename LightMapPolicyType>
bool FBasePassMeshProcessor::Process(const FMeshBatch& RESTRICT MeshBatch,uint64 BatchElementMask,int32 StaticMeshId,const FPrimitiveSceneProxy* RESTRICT PrimitiveSceneProxy,const FMaterialRenderProxy& RESTRICT MaterialRenderProxy,const FMaterial& RESTRICT MaterialResource,EBlendMode BlendMode,FMaterialShadingModelField ShadingModels,const LightMapPolicyType& RESTRICT LightMapPolicy,const typename LightMapPolicyType::ElementDataType& RESTRICT LightMapElementData,ERasterizerFillMode MeshFillMode,ERasterizerCullMode MeshCullMode)
{const FVertexFactory* VertexFactory = MeshBatch.VertexFactory;const bool bRenderSkylight = Scene && Scene->ShouldRenderSkylightInBasePass(BlendMode) && ShadingModels.IsLit();TMeshProcessorShaders<TBasePassVertexShaderPolicyParamType<LightMapPolicyType>,TBasePassPixelShaderPolicyParamType<LightMapPolicyType>> BasePassShaders;if (!GetBasePassShaders<LightMapPolicyType>(MaterialResource,VertexFactory->GetType(),LightMapPolicy,FeatureLevel,bRenderSkylight,Get128BitRequirement(),GBL_Default, // Currently only Nanite uses non-default layout&BasePassShaders.VertexShader,&BasePassShaders.PixelShader)){return false;}FMeshPassProcessorRenderState DrawRenderState(PassDrawRenderState);bool bForceEnableStencilDitherState = false;if (ViewIfDynamicMeshCommand && StaticMeshId >= 0 && MeshBatch.bDitheredLODTransition){checkSlow(ViewIfDynamicMeshCommand->bIsViewInfo);const FViewInfo* ViewInfo = static_cast<const FViewInfo*>(ViewIfDynamicMeshCommand);if (ViewInfo->bAllowStencilDither){if (ViewInfo->StaticMeshFadeOutDitheredLODMap[StaticMeshId] || ViewInfo->StaticMeshFadeInDitheredLODMap[StaticMeshId]){bForceEnableStencilDitherState = true;}}}SetDepthStencilStateForBasePass(DrawRenderState,FeatureLevel,MeshBatch.bDitheredLODTransition,MaterialResource,bEnableReceiveDecalOutput,bForceEnableStencilDitherState);if (bEnableReceiveDecalOutput){// Set stencil value for this draw call// This is effectively extending the GBuffer using the stencil bitsconst uint8 StencilValue = GET_STENCIL_BIT_MASK(RECEIVE_DECAL, PrimitiveSceneProxy ? !!PrimitiveSceneProxy->ReceivesDecals() : 0x00)| GET_STENCIL_BIT_MASK(DISTANCE_FIELD_REPRESENTATION, PrimitiveSceneProxy ? PrimitiveSceneProxy->HasDistanceFieldRepresentation() : 0x00)| STENCIL_LIGHTING_CHANNELS_MASK(PrimitiveSceneProxy ? PrimitiveSceneProxy->GetLightingChannelStencilValue() : 0x00);DrawRenderState.SetStencilRef(StencilValue);}if (bTranslucentBasePass){SetTranslucentRenderState(DrawRenderState, MaterialResource, GShaderPlatformForFeatureLevel[FeatureLevel], TranslucencyPassType);}TBasePassShaderElementData<LightMapPolicyType> ShaderElementData(LightMapElementData);ShaderElementData.InitializeMeshMaterialData(ViewIfDynamicMeshCommand, PrimitiveSceneProxy, MeshBatch, StaticMeshId, true);FMeshDrawCommandSortKey SortKey = FMeshDrawCommandSortKey::Default;if (bTranslucentBasePass){SortKey = CalculateTranslucentMeshStaticSortKey(PrimitiveSceneProxy, MeshBatch.MeshIdInPrimitive);}else{SortKey = CalculateBasePassMeshStaticSortKey(EarlyZPassMode, BlendMode, BasePassShaders.VertexShader.GetShader(), BasePassShaders.PixelShader.GetShader());}BuildMeshDrawCommands(MeshBatch,BatchElementMask,PrimitiveSceneProxy,MaterialRenderProxy,MaterialResource,DrawRenderState,BasePassShaders,MeshFillMode,MeshCullMode,SortKey,EMeshPassFeatures::Default,ShaderElementData);return true;
}
template<typename PassShadersType, typename ShaderElementDataType>
void FMeshPassProcessor::BuildMeshDrawCommands(const FMeshBatch& RESTRICT MeshBatch,uint64 BatchElementMask,const FPrimitiveSceneProxy* RESTRICT PrimitiveSceneProxy,const FMaterialRenderProxy& RESTRICT MaterialRenderProxy,const FMaterial& RESTRICT MaterialResource,const FMeshPassProcessorRenderState& RESTRICT DrawRenderState,PassShadersType PassShaders,ERasterizerFillMode MeshFillMode,ERasterizerCullMode MeshCullMode,FMeshDrawCommandSortKey SortKey,EMeshPassFeatures MeshPassFeatures,const ShaderElementDataType& ShaderElementData)
{const FVertexFactory* RESTRICT VertexFactory = MeshBatch.VertexFactory;const FPrimitiveSceneInfo* RESTRICT PrimitiveSceneInfo = PrimitiveSceneProxy ? PrimitiveSceneProxy->GetPrimitiveSceneInfo() : nullptr;FMeshDrawCommand SharedMeshDrawCommand;EFVisibleMeshDrawCommandFlags SharedFlags = EFVisibleMeshDrawCommandFlags::Default;if (MaterialResource.MaterialUsesWorldPositionOffset_RenderThread()){SharedFlags |= EFVisibleMeshDrawCommandFlags::MaterialUsesWorldPositionOffset;}SharedMeshDrawCommand.SetStencilRef(DrawRenderState.GetStencilRef());SharedMeshDrawCommand.PrimitiveType = (EPrimitiveType)MeshBatch.Type;FGraphicsMinimalPipelineStateInitializer PipelineState;PipelineState.PrimitiveType = (EPrimitiveType)MeshBatch.Type;PipelineState.ImmutableSamplerState = MaterialRenderProxy.ImmutableSamplerState;EVertexInputStreamType InputStreamType = EVertexInputStreamType::Default;if ((MeshPassFeatures & EMeshPassFeatures::PositionOnly) != EMeshPassFeatures::Default) InputStreamType = EVertexInputStreamType::PositionOnly;if ((MeshPassFeatures & EMeshPassFeatures::PositionAndNormalOnly) != EMeshPassFeatures::Default) InputStreamType = EVertexInputStreamType::PositionAndNormalOnly;check(VertexFactory && VertexFactory->IsInitialized());FRHIVertexDeclaration* VertexDeclaration = VertexFactory->GetDeclaration(InputStreamType);check(!VertexFactory->NeedsDeclaration() || VertexDeclaration);FMeshProcessorShaders MeshProcessorShaders = PassShaders.GetUntypedShaders();PipelineState.SetupBoundShaderState(VertexDeclaration, MeshProcessorShaders);SharedMeshDrawCommand.InitializeShaderBindings(MeshProcessorShaders);PipelineState.RasterizerState = GetStaticRasterizerState<true>(MeshFillMode, MeshCullMode);check(DrawRenderState.GetDepthStencilState());check(DrawRenderState.GetBlendState());PipelineState.BlendState = DrawRenderState.GetBlendState();PipelineState.DepthStencilState = DrawRenderState.GetDepthStencilState();PipelineState.DrawShadingRate = GetShadingRateFromMaterial(MaterialResource.GetShadingRate());// PSO Precache hash only needed when PSO precaching is enabledif (PipelineStateCache::IsPSOPrecachingEnabled()){PipelineState.ComputePrecachePSOHash();}check(VertexFactory && VertexFactory->IsInitialized());VertexFactory->GetStreams(FeatureLevel, InputStreamType, SharedMeshDrawCommand.VertexStreams);#if PSO_PRECACHING_VALIDATEPSOCollectorStats::CheckMinimalPipelineStateInCache(PipelineState, (uint32)MeshPassType, VertexFactory->GetType());
#endif // PSO_PRECACHING_VALIDATESharedMeshDrawCommand.PrimitiveIdStreamIndex = VertexFactory->GetPrimitiveIdStreamIndex(FeatureLevel, InputStreamType);if (SharedMeshDrawCommand.PrimitiveIdStreamIndex != INDEX_NONE){SharedFlags |= EFVisibleMeshDrawCommandFlags::HasPrimitiveIdStreamIndex;}int32 DataOffset = 0;if (PassShaders.VertexShader.IsValid()){FMeshDrawSingleShaderBindings ShaderBindings = SharedMeshDrawCommand.ShaderBindings.GetSingleShaderBindings(SF_Vertex, DataOffset);PassShaders.VertexShader->GetShaderBindings(Scene, FeatureLevel, PrimitiveSceneProxy, MaterialRenderProxy, MaterialResource, DrawRenderState, ShaderElementData, ShaderBindings);}if (PassShaders.PixelShader.IsValid()){FMeshDrawSingleShaderBindings ShaderBindings = SharedMeshDrawCommand.ShaderBindings.GetSingleShaderBindings(SF_Pixel, DataOffset);PassShaders.PixelShader->GetShaderBindings(Scene, FeatureLevel, PrimitiveSceneProxy, MaterialRenderProxy, MaterialResource, DrawRenderState, ShaderElementData, ShaderBindings);}if (PassShaders.GeometryShader.IsValid()){FMeshDrawSingleShaderBindings ShaderBindings = SharedMeshDrawCommand.ShaderBindings.GetSingleShaderBindings(SF_Geometry, DataOffset);PassShaders.GeometryShader->GetShaderBindings(Scene, FeatureLevel, PrimitiveSceneProxy, MaterialRenderProxy, MaterialResource, DrawRenderState, ShaderElementData, ShaderBindings);}SharedMeshDrawCommand.SetDebugData(PrimitiveSceneProxy, &MaterialResource, &MaterialRenderProxy, PassShaders.GetUntypedShaders(), VertexFactory, (uint32)MeshPassType);const int32 NumElements = ShouldSkipMeshDrawCommand(MeshBatch, PrimitiveSceneProxy) ? 0 : MeshBatch.Elements.Num();for (int32 BatchElementIndex = 0; BatchElementIndex < NumElements; BatchElementIndex++){if ((1ull << BatchElementIndex) & BatchElementMask){const FMeshBatchElement& BatchElement = MeshBatch.Elements[BatchElementIndex];FMeshDrawCommand& MeshDrawCommand = DrawListContext->AddCommand(SharedMeshDrawCommand, NumElements);EFVisibleMeshDrawCommandFlags Flags = SharedFlags;if (BatchElement.bForceInstanceCulling){Flags |= EFVisibleMeshDrawCommandFlags::ForceInstanceCulling;}if (BatchElement.bPreserveInstanceOrder){// TODO: add support for bPreserveInstanceOrder on mobileif (ensureMsgf(FeatureLevel > ERHIFeatureLevel::ES3_1, TEXT("FMeshBatchElement::bPreserveInstanceOrder is currently only supported on non-mobile platforms."))){ Flags |= EFVisibleMeshDrawCommandFlags::PreserveInstanceOrder;}}DataOffset = 0;if (PassShaders.VertexShader.IsValid()){FMeshDrawSingleShaderBindings VertexShaderBindings = MeshDrawCommand.ShaderBindings.GetSingleShaderBindings(SF_Vertex, DataOffset);FMeshMaterialShader::GetElementShaderBindings(PassShaders.VertexShader, Scene, ViewIfDynamicMeshCommand, VertexFactory, InputStreamType, FeatureLevel, PrimitiveSceneProxy, MeshBatch, BatchElement, ShaderElementData, VertexShaderBindings, MeshDrawCommand.VertexStreams);}if (PassShaders.PixelShader.IsValid()){FMeshDrawSingleShaderBindings PixelShaderBindings = MeshDrawCommand.ShaderBindings.GetSingleShaderBindings(SF_Pixel, DataOffset);FMeshMaterialShader::GetElementShaderBindings(PassShaders.PixelShader, Scene, ViewIfDynamicMeshCommand, VertexFactory, EVertexInputStreamType::Default, FeatureLevel, PrimitiveSceneProxy, MeshBatch, BatchElement, ShaderElementData, PixelShaderBindings, MeshDrawCommand.VertexStreams);}if (PassShaders.GeometryShader.IsValid()){FMeshDrawSingleShaderBindings GeometryShaderBindings = MeshDrawCommand.ShaderBindings.GetSingleShaderBindings(SF_Geometry, DataOffset);FMeshMaterialShader::GetElementShaderBindings(PassShaders.GeometryShader, Scene, ViewIfDynamicMeshCommand, VertexFactory, EVertexInputStreamType::Default, FeatureLevel, PrimitiveSceneProxy, MeshBatch, BatchElement, ShaderElementData, GeometryShaderBindings, MeshDrawCommand.VertexStreams);}FMeshDrawCommandPrimitiveIdInfo IdInfo = GetDrawCommandPrimitiveId(PrimitiveSceneInfo, BatchElement);FMeshProcessorShaders ShadersForDebugging = PassShaders.GetUntypedShaders();DrawListContext->FinalizeCommand(MeshBatch, BatchElementIndex, IdInfo, MeshFillMode, MeshCullMode, SortKey, Flags, PipelineState, &ShadersForDebugging, MeshDrawCommand);}}
}
void FCachedPassMeshDrawListContextImmediate::FinalizeCommand(const FMeshBatch& MeshBatch, int32 BatchElementIndex,const FMeshDrawCommandPrimitiveIdInfo& IdInfo,ERasterizerFillMode MeshFillMode,ERasterizerCullMode MeshCullMode,FMeshDrawCommandSortKey SortKey,EFVisibleMeshDrawCommandFlags Flags,const FGraphicsMinimalPipelineStateInitializer& PipelineState,const FMeshProcessorShaders* ShadersForDebugging,FMeshDrawCommand& MeshDrawCommand)
{// disabling this by default as it incurs a high cost in perf captures due to sheer volume. Recommendation is to re-enable locally if you need to profile this particular code.// QUICK_SCOPE_CYCLE_COUNTER(STAT_FinalizeCachedMeshDrawCommand);FinalizeCommandCommon(MeshBatch, BatchElementIndex,MeshFillMode,MeshCullMode,SortKey,Flags,PipelineState,ShadersForDebugging,MeshDrawCommand);if (bUseGPUScene){Experimental::FHashElementId SetId;FStateBucketMap& BucketMap = Scene.CachedMeshDrawCommandStateBuckets[CurrMeshPass];auto hash = BucketMap.ComputeHash(MeshDrawCommand);{SetId = BucketMap.FindOrAddIdByHash(hash, MeshDrawCommand, FMeshDrawCommandCount());FMeshDrawCommandCount& DrawCount = BucketMap.GetByElementId(SetId).Value;DrawCount.Num++;}CommandInfo.StateBucketId = SetId.GetIndex();if (bUseStateBucketsAuxData){// grow MDC AuxData array in sync with MDC StateBucketsScene.CachedStateBucketsAuxData[CurrMeshPass].SetNum(BucketMap.GetMaxIndex() + 1, false);Scene.CachedStateBucketsAuxData[CurrMeshPass][CommandInfo.StateBucketId] = FStateBucketAuxData(MeshBatch);}}else{// Only one FMeshDrawCommand supported per FStaticMesh in a pass// Allocate at lowest free index so that 'r.DoLazyStaticMeshUpdate' can shrink the TSparseArray more effectivelyFCachedPassMeshDrawList& CachedDrawLists = Scene.CachedDrawLists[CurrMeshPass];CommandInfo.CommandIndex = CachedDrawLists.MeshDrawCommands.EmplaceAtLowestFreeIndex(CachedDrawLists.LowestFreeIndexSearchStart, MeshDrawCommand);}
}
void FCachedPassMeshDrawListContext::FinalizeCommandCommon(const FMeshBatch& MeshBatch, int32 BatchElementIndex,ERasterizerFillMode MeshFillMode,ERasterizerCullMode MeshCullMode,FMeshDrawCommandSortKey SortKey,EFVisibleMeshDrawCommandFlags Flags,const FGraphicsMinimalPipelineStateInitializer& PipelineState,const FMeshProcessorShaders* ShadersForDebugging,FMeshDrawCommand& MeshDrawCommand)
{FGraphicsMinimalPipelineStateId PipelineId = FGraphicsMinimalPipelineStateId::GetPersistentId(PipelineState);MeshDrawCommand.SetDrawParametersAndFinalize(MeshBatch, BatchElementIndex, PipelineId, ShadersForDebugging);CommandInfo = FCachedMeshDrawCommandInfo(CurrMeshPass);CommandInfo.SortKey = SortKey;CommandInfo.MeshFillMode = MeshFillMode;CommandInfo.MeshCullMode = MeshCullMode;CommandInfo.Flags = Flags;#if MESH_DRAW_COMMAND_DEBUG_DATAif (bUseGPUScene){MeshDrawCommand.ClearDebugPrimitiveSceneProxy(); //When using State Buckets multiple PrimitiveSceneProxies use the same MeshDrawCommand, so The PrimitiveSceneProxy pointer can't be stored.}
#endif
#if DO_GUARD_SLOWif (bUseGPUScene){FMeshDrawCommand MeshDrawCommandDebug = FMeshDrawCommand(MeshDrawCommand);check(MeshDrawCommandDebug.ShaderBindings.GetDynamicInstancingHash() == MeshDrawCommand.ShaderBindings.GetDynamicInstancingHash());check(MeshDrawCommandDebug.GetDynamicInstancingHash() == MeshDrawCommand.GetDynamicInstancingHash());}if (Scene.GetShadingPath() == EShadingPath::Deferred){ensureMsgf(MeshDrawCommand.VertexStreams.GetAllocatedSize() == 0, TEXT("Cached Mesh Draw command overflows VertexStreams. VertexStream inline size should be tweaked."));if (CurrMeshPass == EMeshPass::BasePass || CurrMeshPass == EMeshPass::DepthPass || CurrMeshPass == EMeshPass::CSMShadowDepth || CurrMeshPass == EMeshPass::VSMShadowDepth){TArray<EShaderFrequency, TInlineAllocator<SF_NumFrequencies>> ShaderFrequencies;MeshDrawCommand.ShaderBindings.GetShaderFrequencies(ShaderFrequencies);int32 DataOffset = 0;for (int32 i = 0; i < ShaderFrequencies.Num(); i++){FMeshDrawSingleShaderBindings SingleShaderBindings = MeshDrawCommand.ShaderBindings.GetSingleShaderBindings(ShaderFrequencies[i], DataOffset);if (SingleShaderBindings.GetParameterMapInfo().LooseParameterBuffers.Num() != 0){bAnyLooseParameterBuffers = true;}ensureMsgf(SingleShaderBindings.GetParameterMapInfo().SRVs.Num() == 0, TEXT("Cached Mesh Draw command uses individual SRVs. This will break dynamic instancing in performance critical pass. Use Uniform Buffers instead."));ensureMsgf(SingleShaderBindings.GetParameterMapInfo().TextureSamplers.Num() == 0, TEXT("Cached Mesh Draw command uses individual Texture Samplers. This will break dynamic instancing in performance critical pass. Use Uniform Buffers instead."));}}}
#endif
}
CPP与usf
IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FSharedBasePassUniformParameters, "BasePass");
IMPLEMENT_STATIC_UNIFORM_BUFFER_STRUCT(FOpaqueBasePassUniformParameters, "OpaqueBasePass", SceneTextures);
IMPLEMENT_STATIC_UNIFORM_BUFFER_STRUCT(FTranslucentBasePassUniformParameters, "TranslucentBasePass", SceneTextures);// Typedef is necessary because the C preprocessor thinks the comma in the template parameter list is a comma in the macro parameter list.
#define IMPLEMENT_BASEPASS_VERTEXSHADER_TYPE(LightMapPolicyType,LightMapPolicyName) \typedef TBasePassVS< LightMapPolicyType > TBasePassVS##LightMapPolicyName ; \IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TBasePassVS##LightMapPolicyName,TEXT("/Engine/Private/BasePassVertexShader.usf"),TEXT("Main"),SF_Vertex);#define IMPLEMENT_BASEPASS_PIXELSHADER_TYPE(LightMapPolicyType,LightMapPolicyName,bEnableSkyLight,SkyLightName,GBufferLayout,LayoutName) \typedef TBasePassPS<LightMapPolicyType, bEnableSkyLight, GBufferLayout> TBasePassPS##LightMapPolicyName##SkyLightName##LayoutName; \IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TBasePassPS##LightMapPolicyName##SkyLightName##LayoutName,TEXT("/Engine/Private/BasePassPixelShader.usf"),TEXT("MainPS"),SF_Pixel);#define IMPLEMENT_BASEPASS_COMPUTESHADER_TYPE(LightMapPolicyType,LightMapPolicyName,bEnableSkyLight,SkyLightName,GBufferLayout,LayoutName) \typedef TBasePassCS<LightMapPolicyType, bEnableSkyLight, GBufferLayout> TBasePassCS##LightMapPolicyName##SkyLightName##LayoutName; \IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TBasePassCS##LightMapPolicyName##SkyLightName##LayoutName,TEXT("/Engine/Private/BasePassPixelShader.usf"),TEXT("MainCS"),SF_Compute);// Implement a pixel and compute shader type for skylights and one without, and one vertex shader that will be shared between them
#define IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE(LightMapPolicyType,LightMapPolicyName) \IMPLEMENT_BASEPASS_VERTEXSHADER_TYPE(LightMapPolicyType,LightMapPolicyName) \IMPLEMENT_BASEPASS_PIXELSHADER_TYPE(LightMapPolicyType,LightMapPolicyName,true,Skylight,GBL_Default,) \IMPLEMENT_BASEPASS_PIXELSHADER_TYPE(LightMapPolicyType,LightMapPolicyName,false,,GBL_Default,) \IMPLEMENT_BASEPASS_PIXELSHADER_TYPE(LightMapPolicyType,LightMapPolicyName,true,Skylight,GBL_ForceVelocity,ForceVelocity) \IMPLEMENT_BASEPASS_PIXELSHADER_TYPE(LightMapPolicyType,LightMapPolicyName,false,,GBL_ForceVelocity,ForceVelocity) \IMPLEMENT_BASEPASS_COMPUTESHADER_TYPE(LightMapPolicyType,LightMapPolicyName,true,Skylight,GBL_Default,) \IMPLEMENT_BASEPASS_COMPUTESHADER_TYPE(LightMapPolicyType,LightMapPolicyName,false,,GBL_Default,) \IMPLEMENT_BASEPASS_COMPUTESHADER_TYPE(LightMapPolicyType,LightMapPolicyName,true,Skylight,GBL_ForceVelocity,ForceVelocity) \IMPLEMENT_BASEPASS_COMPUTESHADER_TYPE(LightMapPolicyType,LightMapPolicyName,false,,GBL_ForceVelocity,ForceVelocity)// Implement shader types per lightmap policy
// If renaming or refactoring these, remember to update FMaterialResource::GetRepresentativeInstructionCounts and FPreviewMaterial::ShouldCache().
IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( FSelfShadowedTranslucencyPolicy, FSelfShadowedTranslucencyPolicy );
IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( FSelfShadowedCachedPointIndirectLightingPolicy, FSelfShadowedCachedPointIndirectLightingPolicy );
IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( FSelfShadowedVolumetricLightmapPolicy, FSelfShadowedVolumetricLightmapPolicy );IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( TUniformLightMapPolicy<LMP_NO_LIGHTMAP>, FNoLightMapPolicy );
IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( TUniformLightMapPolicy<LMP_PRECOMPUTED_IRRADIANCE_VOLUME_INDIRECT_LIGHTING>, FPrecomputedVolumetricLightmapLightingPolicy );
IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( TUniformLightMapPolicy<LMP_CACHED_VOLUME_INDIRECT_LIGHTING>, FCachedVolumeIndirectLightingPolicy );
IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( TUniformLightMapPolicy<LMP_CACHED_POINT_INDIRECT_LIGHTING>, FCachedPointIndirectLightingPolicy );
IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( TUniformLightMapPolicy<LMP_LQ_LIGHTMAP>, TLightMapPolicyLQ );
IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( TUniformLightMapPolicy<LMP_HQ_LIGHTMAP>, TLightMapPolicyHQ );
IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( TUniformLightMapPolicy<LMP_DISTANCE_FIELD_SHADOWS_AND_HQ_LIGHTMAP>, TDistanceFieldShadowsAndLightMapPolicyHQ );IMPLEMENT_MATERIAL_SHADER_TYPE(, F128BitRTBasePassPS, TEXT("/Engine/Private/BasePassPixelShader.usf"), TEXT("MainPS"), SF_Pixel);DEFINE_GPU_DRAWCALL_STAT(Basepass);