void FSceneViewState::TrimHistoryRenderTargets(const FScene* Scene) { for (TMap<const ULightComponent*, TRefCountPtr<IPooledRenderTarget> >::TIterator It(LightShaftBloomHistoryRTs); It; ++It) { bool bLightIsUsed = false; for (TSparseArray<FLightSceneInfoCompact>::TConstIterator LightIt(Scene->Lights); LightIt; ++LightIt) { const FLightSceneInfo* const LightSceneInfo = LightIt->LightSceneInfo; if (LightSceneInfo->Proxy->GetLightComponent() == It.Key()) { bLightIsUsed = true; break; } } if (!bLightIsUsed) { // Remove references to render targets for lights that are no longer in the scene // This has to be done every frame instead of at light deregister time because the view states are not known by FScene It.RemoveCurrent(); } } }
void FDeferredShadingSceneRenderer::RenderLightShaftBloom(FRHICommandListImmediate& RHICmdList) { if (DoesViewFamilyAllowLightShafts(ViewFamily)) { TRefCountPtr<IPooledRenderTarget> LightShafts0; TRefCountPtr<IPooledRenderTarget> LightShafts1; for (TSparseArray<FLightSceneInfoCompact>::TConstIterator LightIt(Scene->Lights); LightIt; ++LightIt) { const FLightSceneInfo* const LightSceneInfo = LightIt->LightSceneInfo; if (LightSceneInfo->bEnableLightShaftBloom) { SCOPED_DRAW_EVENT(RHICmdList, RenderLightShaftBloom); // Allocate light shaft render targets on demand, using the pool AllocateOrReuseLightShaftRenderTarget(RHICmdList, LightShafts0, TEXT("LightShafts0")); AllocateOrReuseLightShaftRenderTarget(RHICmdList, LightShafts1, TEXT("LightShafts1")); for (int ViewIndex = 0;ViewIndex < Views.Num();ViewIndex++) { FViewInfo& View = Views[ViewIndex]; if (ShouldRenderLightShaftsForLight(View, LightSceneInfo)) { INC_DWORD_STAT(STAT_LightShaftsLights); // Generate the bloom source from scene color, masked by depth and downsampled DownsamplePass<false>(RHICmdList, View, LightSceneInfo, LightShafts0, LightShafts1); FSceneViewState* ViewState = (FSceneViewState*)View.State; TRefCountPtr<IPooledRenderTarget>* HistoryState = NULL; if (ViewState) { // Find the previous frame's bloom source for this light HistoryState = &ViewState->LightShaftBloomHistoryRTs.FindOrAdd(LightSceneInfo->Proxy->GetLightComponent()); } TRefCountPtr<IPooledRenderTarget> HistoryOutput; // Apply temporal AA to the occlusion mask // Result will be in HistoryOutput ApplyTemporalAA(RHICmdList, View, TEXT("LSBloomHistory"), HistoryState, LightShafts0, HistoryOutput); // Apply radial blur passes // Send HistoryOutput in as the first pass input only, so it will not be overwritten by any subsequent passes, since it is needed for next frame ApplyRadialBlurPasses(RHICmdList, View, LightSceneInfo, HistoryOutput, LightShafts0, LightShafts1); // Add light shaft bloom to scene color in full res ApplyLightShaftBloom(RHICmdList, View, LightSceneInfo, LightShafts0); } } } } } }
/** Renders light shafts. */ FLightShaftsOutput FDeferredShadingSceneRenderer::RenderLightShaftOcclusion(FRHICommandListImmediate& RHICmdList) { FLightShaftsOutput Output; if (DoesViewFamilyAllowLightShafts(ViewFamily)) { TRefCountPtr<IPooledRenderTarget> LightShafts0; TRefCountPtr<IPooledRenderTarget> LightShafts1; for (TSparseArray<FLightSceneInfoCompact>::TConstIterator LightIt(Scene->Lights); LightIt; ++LightIt) { const FLightSceneInfo* const LightSceneInfo = LightIt->LightSceneInfo; float OcclusionMaskDarkness; float OcclusionDepthRange; const bool bEnableOcclusion = LightSceneInfo->Proxy->GetLightShaftOcclusionParameters(OcclusionMaskDarkness, OcclusionDepthRange); if (bEnableOcclusion && LightSceneInfo->Proxy->GetLightType() == LightType_Directional) { SCOPED_DRAW_EVENT(RHICmdList, RenderLightShaftOcclusion); // Allocate light shaft render targets on demand, using the pool // Need two targets to ping pong between AllocateOrReuseLightShaftRenderTarget(RHICmdList, LightShafts0, TEXT("LightShafts0")); AllocateOrReuseLightShaftRenderTarget(RHICmdList, LightShafts1, TEXT("LightShafts1")); for (int ViewIndex = 0;ViewIndex < Views.Num();ViewIndex++) { FViewInfo& View = Views[ViewIndex]; if (ShouldRenderLightShaftsForLight(View, LightSceneInfo)) { INC_DWORD_STAT(STAT_LightShaftsLights); // Create a downsampled occlusion mask from scene depth, result will be in LightShafts0 DownsamplePass<true>(RHICmdList, View, LightSceneInfo, LightShafts0, LightShafts1); FSceneViewState* ViewState = (FSceneViewState*)View.State; // Find the previous frame's occlusion mask TRefCountPtr<IPooledRenderTarget>* HistoryState = ViewState ? &ViewState->LightShaftOcclusionHistoryRT : NULL; TRefCountPtr<IPooledRenderTarget> HistoryOutput; // Apply temporal AA to the occlusion mask // Result will be in HistoryOutput ApplyTemporalAA(RHICmdList, View, TEXT("LSOcclusionHistory"), HistoryState, LightShafts0, HistoryOutput); // Apply radial blur passes // Send HistoryOutput in as the first pass input only, so it will not be overwritten by any subsequent passes, since it is needed for next frame ApplyRadialBlurPasses(RHICmdList, View, LightSceneInfo, HistoryOutput, LightShafts0, LightShafts1); // Apply post-blur masking FinishOcclusionTerm(RHICmdList, View, LightSceneInfo, LightShafts0, LightShafts1); //@todo - different views could have different result render targets Output.LightShaftOcclusion = LightShafts1; Output.bRendered = true; } } } } } return Output; }
void FPrimitiveSceneInfo::AddToScene(bool bUpdateStaticDrawLists) { check(IsInRenderingThread()); // If we are attaching a primitive that should be statically lit but has unbuilt lighting, // Allocate space in the indirect lighting cache so that it can be used for previewing indirect lighting if (Proxy->HasStaticLighting() && Proxy->NeedsUnbuiltPreviewLighting() && IsIndirectLightingCacheAllowed()) { FIndirectLightingCacheAllocation* PrimitiveAllocation = Scene->IndirectLightingCache.FindPrimitiveAllocation(PrimitiveComponentId); if (PrimitiveAllocation) { IndirectLightingCacheAllocation = PrimitiveAllocation; PrimitiveAllocation->SetDirty(); } else { PrimitiveAllocation = Scene->IndirectLightingCache.AllocatePrimitive(this, true); PrimitiveAllocation->SetDirty(); IndirectLightingCacheAllocation = PrimitiveAllocation; } } if (bUpdateStaticDrawLists) { AddStaticMeshes(); } // create potential storage for our compact info FPrimitiveSceneInfoCompact LocalCompactPrimitiveSceneInfo; FPrimitiveSceneInfoCompact* CompactPrimitiveSceneInfo = &LocalCompactPrimitiveSceneInfo; // if we are being added directly to the Octree, initialize the temp compact scene info, // and let the Octree make a copy of it LocalCompactPrimitiveSceneInfo.Init(this); // Add the primitive to the octree. check(!OctreeId.IsValidId()); Scene->PrimitiveOctree.AddElement(LocalCompactPrimitiveSceneInfo); check(OctreeId.IsValidId()); // Set bounds. FPrimitiveBounds& PrimitiveBounds = Scene->PrimitiveBounds[PackedIndex]; FBoxSphereBounds BoxSphereBounds = Proxy->GetBounds(); PrimitiveBounds.Origin = BoxSphereBounds.Origin; PrimitiveBounds.SphereRadius = BoxSphereBounds.SphereRadius; PrimitiveBounds.BoxExtent = BoxSphereBounds.BoxExtent; PrimitiveBounds.MinDrawDistanceSq = FMath::Square(Proxy->GetMinDrawDistance()); PrimitiveBounds.MaxDrawDistance = Proxy->GetMaxDrawDistance(); // Store precomputed visibility ID. int32 VisibilityBitIndex = Proxy->GetVisibilityId(); FPrimitiveVisibilityId& VisibilityId = Scene->PrimitiveVisibilityIds[PackedIndex]; VisibilityId.ByteIndex = VisibilityBitIndex / 8; VisibilityId.BitMask = (1 << (VisibilityBitIndex & 0x7)); // Store occlusion flags. uint8 OcclusionFlags = EOcclusionFlags::None; if (Proxy->CanBeOccluded()) { OcclusionFlags |= EOcclusionFlags::CanBeOccluded; } if (Proxy->AllowApproximateOcclusion() // Allow approximate occlusion if attached, even if the parent does not have bLightAttachmentsAsGroup enabled || LightingAttachmentRoot.IsValid()) { OcclusionFlags |= EOcclusionFlags::AllowApproximateOcclusion; } if (VisibilityBitIndex >= 0) { OcclusionFlags |= EOcclusionFlags::HasPrecomputedVisibility; } Scene->PrimitiveOcclusionFlags[PackedIndex] = OcclusionFlags; // Store occlusion bounds. FBoxSphereBounds OcclusionBounds = BoxSphereBounds; if (Proxy->HasCustomOcclusionBounds()) { OcclusionBounds = Proxy->GetCustomOcclusionBounds(); } OcclusionBounds.BoxExtent.X = OcclusionBounds.BoxExtent.X + OCCLUSION_SLOP; OcclusionBounds.BoxExtent.Y = OcclusionBounds.BoxExtent.Y + OCCLUSION_SLOP; OcclusionBounds.BoxExtent.Z = OcclusionBounds.BoxExtent.Z + OCCLUSION_SLOP; OcclusionBounds.SphereRadius = OcclusionBounds.SphereRadius + OCCLUSION_SLOP; Scene->PrimitiveOcclusionBounds[PackedIndex] = OcclusionBounds; // Store the component. Scene->PrimitiveComponentIds[PackedIndex] = PrimitiveComponentId; bNeedsCachedReflectionCaptureUpdate = true; { FMemMark MemStackMark(FMemStack::Get()); // Find lights that affect the primitive in the light octree. for (FSceneLightOctree::TConstElementBoxIterator<SceneRenderingAllocator> LightIt(Scene->LightOctree, Proxy->GetBounds().GetBox()); LightIt.HasPendingElements(); LightIt.Advance()) { const FLightSceneInfoCompact& LightSceneInfoCompact = LightIt.GetCurrentElement(); if (LightSceneInfoCompact.AffectsPrimitive(*CompactPrimitiveSceneInfo)) { FLightPrimitiveInteraction::Create(LightSceneInfoCompact.LightSceneInfo,this); } } } INC_MEMORY_STAT_BY(STAT_PrimitiveInfoMemory, sizeof(*this) + StaticMeshes.GetAllocatedSize() + Proxy->GetMemoryFootprint()); }
void ULightComponent::ReassignStationaryLightChannels(UWorld* TargetWorld, bool bAssignForLightingBuild) { TMap<FLightAndChannel*, TArray<FLightAndChannel*> > LightToOverlapMap; // Build an array of all static shadowing lights that need to be assigned for(TObjectIterator<ULightComponent> LightIt(RF_ClassDefaultObject|RF_PendingKill); LightIt; ++LightIt) { ULightComponent* const LightComponent = *LightIt; const bool bLightIsInWorld = LightComponent->GetOwner() && TargetWorld->ContainsActor(LightComponent->GetOwner()) && !LightComponent->GetOwner()->IsPendingKill(); if (bLightIsInWorld // Only operate on stationary light components (static shadowing only) && LightComponent->HasStaticShadowing() && !LightComponent->HasStaticLighting()) { if (LightComponent->bAffectsWorld && LightComponent->CastShadows && LightComponent->CastStaticShadows) { LightToOverlapMap.Add(new FLightAndChannel(LightComponent), TArray<FLightAndChannel*>()); } else { // Reset the preview channel of stationary light components that shouldn't get a channel // This is necessary to handle a light being newly disabled LightComponent->PreviewShadowMapChannel = INDEX_NONE; #if WITH_EDITOR LightComponent->UpdateLightSpriteTexture(); #endif } } } // Build an array of overlapping lights for (TMap<FLightAndChannel*, TArray<FLightAndChannel*> >::TIterator It(LightToOverlapMap); It; ++It) { ULightComponent* CurrentLight = It.Key()->Light; TArray<FLightAndChannel*>& OverlappingLights = It.Value(); if (bAssignForLightingBuild) { // This should have happened during lighting invalidation at the beginning of the build anyway CurrentLight->ShadowMapChannel = INDEX_NONE; } for (TMap<FLightAndChannel*, TArray<FLightAndChannel*> >::TIterator OtherIt(LightToOverlapMap); OtherIt; ++OtherIt) { ULightComponent* OtherLight = OtherIt.Key()->Light; if (CurrentLight != OtherLight // Testing both directions because the spotlight <-> spotlight test is just cone vs bounding sphere //@todo - more accurate spotlight <-> spotlight intersection && CurrentLight->AffectsBounds(FBoxSphereBounds(OtherLight->GetBoundingSphere())) && OtherLight->AffectsBounds(FBoxSphereBounds(CurrentLight->GetBoundingSphere()))) { OverlappingLights.Add(OtherIt.Key()); } } } // Sort lights with the most overlapping lights first LightToOverlapMap.ValueSort(FCompareLightsByArrayCount()); TMap<FLightAndChannel*, TArray<FLightAndChannel*> > SortedLightToOverlapMap; // Add directional lights to the beginning so they always get channels for (TMap<FLightAndChannel*, TArray<FLightAndChannel*> >::TIterator It(LightToOverlapMap); It; ++It) { FLightAndChannel* CurrentLight = It.Key(); if (CurrentLight->Light->GetLightType() == LightType_Directional) { SortedLightToOverlapMap.Add(It.Key(), It.Value()); } } // Add everything else, which has been sorted by descending overlaps for (TMap<FLightAndChannel*, TArray<FLightAndChannel*> >::TIterator It(LightToOverlapMap); It; ++It) { FLightAndChannel* CurrentLight = It.Key(); if (CurrentLight->Light->GetLightType() != LightType_Directional) { SortedLightToOverlapMap.Add(It.Key(), It.Value()); } } // Go through lights and assign shadowmap channels //@todo - retry with different ordering heuristics when it fails for (TMap<FLightAndChannel*, TArray<FLightAndChannel*> >::TIterator It(SortedLightToOverlapMap); It; ++It) { bool bChannelUsed[4] = {0}; FLightAndChannel* CurrentLight = It.Key(); const TArray<FLightAndChannel*>& OverlappingLights = It.Value(); // Mark which channels have already been assigned to overlapping lights for (int32 OverlappingIndex = 0; OverlappingIndex < OverlappingLights.Num(); OverlappingIndex++) { FLightAndChannel* OverlappingLight = OverlappingLights[OverlappingIndex]; if (OverlappingLight->Channel != INDEX_NONE) { bChannelUsed[OverlappingLight->Channel] = true; } } // Use the lowest free channel for (int32 ChannelIndex = 0; ChannelIndex < ARRAY_COUNT(bChannelUsed); ChannelIndex++) { if (!bChannelUsed[ChannelIndex]) { CurrentLight->Channel = ChannelIndex; break; } } } // Go through the assigned lights and update their render state and icon for (TMap<FLightAndChannel*, TArray<FLightAndChannel*> >::TIterator It(SortedLightToOverlapMap); It; ++It) { FLightAndChannel* CurrentLight = It.Key(); if (CurrentLight->Light->PreviewShadowMapChannel != CurrentLight->Channel) { CurrentLight->Light->PreviewShadowMapChannel = CurrentLight->Channel; CurrentLight->Light->MarkRenderStateDirty(); } #if WITH_EDITOR CurrentLight->Light->UpdateLightSpriteTexture(); #endif if (bAssignForLightingBuild) { CurrentLight->Light->ShadowMapChannel = CurrentLight->Channel; if (CurrentLight->Light->ShadowMapChannel == INDEX_NONE) { FMessageLog("LightingResults").Error() ->AddToken(FUObjectToken::Create(CurrentLight->Light->GetOwner())) ->AddToken(FTextToken::Create( NSLOCTEXT("Lightmass", "LightmassError_FailedToAllocateShadowmapChannel", "Severe performance loss: Failed to allocate shadowmap channel for stationary light due to overlap - light will fall back to dynamic shadows!") ) ); } } delete CurrentLight; } }
void FDeferredShadingSceneRenderer::BeginOcclusionTests(FRHICommandListImmediate& RHICmdList, bool bRenderQueries) { SCOPE_CYCLE_COUNTER(STAT_BeginOcclusionTestsTime); int32 NumBufferedFrames = FOcclusionQueryHelpers::GetNumBufferedFrames(); FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); const bool bUseDownsampledDepth = SceneContext.UseDownsizedOcclusionQueries() && IsValidRef(SceneContext.SmallDepthZ) && IsValidRef(SceneContext.GetSmallDepthSurface()); if (bUseDownsampledDepth) { SetRenderTarget(RHICmdList, NULL, SceneContext.GetSmallDepthSurface(), ESimpleRenderTargetMode::EExistingColorAndDepth, FExclusiveDepthStencil::DepthRead_StencilWrite); } else { SetRenderTarget(RHICmdList, NULL, SceneContext.GetSceneDepthSurface(), ESimpleRenderTargetMode::EExistingColorAndDepth, FExclusiveDepthStencil::DepthRead_StencilWrite); } if (bRenderQueries) { RHICmdList.BeginOcclusionQueryBatch(); // Perform occlusion queries for each view for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) { SCOPED_DRAW_EVENT(RHICmdList, BeginOcclusionTests); FViewInfo& View = Views[ViewIndex]; if (bUseDownsampledDepth) { const uint32 DownsampledX = FMath::TruncToInt(View.ViewRect.Min.X / SceneContext.GetSmallColorDepthDownsampleFactor()); const uint32 DownsampledY = FMath::TruncToInt(View.ViewRect.Min.Y / SceneContext.GetSmallColorDepthDownsampleFactor()); const uint32 DownsampledSizeX = FMath::TruncToInt(View.ViewRect.Width() / SceneContext.GetSmallColorDepthDownsampleFactor()); const uint32 DownsampledSizeY = FMath::TruncToInt(View.ViewRect.Height() / SceneContext.GetSmallColorDepthDownsampleFactor()); // Setup the viewport for rendering to the downsampled depth buffer RHICmdList.SetViewport(DownsampledX, DownsampledY, 0.0f, DownsampledX + DownsampledSizeX, DownsampledY + DownsampledSizeY, 1.0f); } else { RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f); } FSceneViewState* ViewState = (FSceneViewState*)View.State; if (ViewState && !View.bDisableQuerySubmissions) { // Depth tests, no depth writes, no color writes, opaque, solid rasterization wo/ backface culling. RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_DepthNearOrEqual>::GetRHI()); // We only need to render the front-faces of the culling geometry (this halves the amount of pixels we touch) RHICmdList.SetRasterizerState(View.bReverseCulling ? TStaticRasterizerState<FM_Solid, CM_CCW>::GetRHI() : TStaticRasterizerState<FM_Solid, CM_CW>::GetRHI()); RHICmdList.SetBlendState(TStaticBlendState<CW_NONE>::GetRHI()); // Lookup the vertex shader. TShaderMapRef<FOcclusionQueryVS> VertexShader(View.ShaderMap); SetGlobalBoundShaderState(RHICmdList, View.GetFeatureLevel(), OcclusionTestBoundShaderState, GetVertexDeclarationFVector3(), *VertexShader, NULL); VertexShader->SetParameters(RHICmdList, View); // Issue this frame's occlusion queries (occlusion queries from last frame may still be in flight) const uint32 QueryIndex = FOcclusionQueryHelpers::GetQueryIssueIndex(ViewState->PendingPrevFrameNumber, NumBufferedFrames); FSceneViewState::ShadowKeyOcclusionQueryMap& ShadowOcclusionQueryMap = ViewState->ShadowOcclusionQueryMaps[QueryIndex]; // Clear primitives which haven't been visible recently out of the occlusion history, and reset old pending occlusion queries. ViewState->TrimOcclusionHistory(RHICmdList, ViewFamily.CurrentRealTime, ViewFamily.CurrentRealTime - GEngine->PrimitiveProbablyVisibleTime, ViewFamily.CurrentRealTime, ViewState->OcclusionFrameCounter); // Give back all these occlusion queries to the pool. for (TMap<FSceneViewState::FProjectedShadowKey, FRenderQueryRHIRef>::TIterator QueryIt(ShadowOcclusionQueryMap); QueryIt; ++QueryIt) { //FRenderQueryRHIParamRef Query = QueryIt.Value(); //check( Query.GetRefCount() == 1 ); ViewState->OcclusionQueryPool.ReleaseQuery(QueryIt.Value()); } ShadowOcclusionQueryMap.Reset(); { SCOPED_DRAW_EVENT(RHICmdList, ShadowFrustumQueries); for (TSparseArray<FLightSceneInfoCompact>::TConstIterator LightIt(Scene->Lights); LightIt; ++LightIt) { const FVisibleLightInfo& VisibleLightInfo = VisibleLightInfos[LightIt.GetIndex()]; for (int32 ShadowIndex = 0; ShadowIndex < VisibleLightInfo.AllProjectedShadows.Num(); ShadowIndex++) { const FProjectedShadowInfo& ProjectedShadowInfo = *VisibleLightInfo.AllProjectedShadows[ShadowIndex]; if (ProjectedShadowInfo.DependentView && ProjectedShadowInfo.DependentView != &View) { continue; } if (ProjectedShadowInfo.CascadeSettings.bOnePassPointLightShadow) { FLightSceneProxy& LightProxy = *(ProjectedShadowInfo.GetLightSceneInfo().Proxy); // Query one pass point light shadows separately because they don't have a shadow frustum, they have a bounding sphere instead. FSphere LightBounds = LightProxy.GetBoundingSphere(); const bool bCameraInsideLightGeometry = ((FVector)View.ViewMatrices.ViewOrigin - LightBounds.Center).SizeSquared() < FMath::Square(LightBounds.W * 1.05f + View.NearClippingDistance * 2.0f); if (!bCameraInsideLightGeometry) { const FRenderQueryRHIRef ShadowOcclusionQuery = ViewState->OcclusionQueryPool.AllocateQuery(); RHICmdList.BeginRenderQuery(ShadowOcclusionQuery); FSceneViewState::FProjectedShadowKey Key(ProjectedShadowInfo); checkSlow(ShadowOcclusionQueryMap.Find(Key) == NULL); ShadowOcclusionQueryMap.Add(Key, ShadowOcclusionQuery); // Draw bounding sphere VertexShader->SetParametersWithBoundingSphere(RHICmdList, View, LightBounds); StencilingGeometry::DrawVectorSphere(RHICmdList); RHICmdList.EndRenderQuery(ShadowOcclusionQuery); } } // Don't query preshadows, since they are culled if their subject is occluded. // Don't query if any subjects are visible because the shadow frustum will be definitely unoccluded else if (!ProjectedShadowInfo.IsWholeSceneDirectionalShadow() && !ProjectedShadowInfo.bPreShadow && !ProjectedShadowInfo.SubjectsVisible(View)) { IssueProjectedShadowOcclusionQuery(RHICmdList, View, ProjectedShadowInfo, *VertexShader, NumBufferedFrames); } } // Issue occlusion queries for all per-object projected shadows that we would have rendered but were occluded last frame. for (int32 ShadowIndex = 0; ShadowIndex < VisibleLightInfo.OccludedPerObjectShadows.Num(); ShadowIndex++) { const FProjectedShadowInfo& ProjectedShadowInfo = *VisibleLightInfo.OccludedPerObjectShadows[ShadowIndex]; IssueProjectedShadowOcclusionQuery(RHICmdList, View, ProjectedShadowInfo, *VertexShader, NumBufferedFrames); } } } // Don't do primitive occlusion if we have a view parent or are frozen. #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if (!ViewState->HasViewParent() && !ViewState->bIsFrozen) #endif { VertexShader->SetParameters(RHICmdList, View); { SCOPED_DRAW_EVENT(RHICmdList, IndividualQueries); View.IndividualOcclusionQueries.Flush(RHICmdList); } { SCOPED_DRAW_EVENT(RHICmdList, GroupedQueries); View.GroupedOcclusionQueries.Flush(RHICmdList); } } } } RHICmdList.EndOcclusionQueryBatch(); } if (bUseDownsampledDepth) { // Restore default render target SceneContext.BeginRenderingSceneColor(RHICmdList, ESimpleRenderTargetMode::EUninitializedColorExistingDepth, FExclusiveDepthStencil::DepthRead_StencilWrite); } }