赞
踩
FSceneRenderer::InitDynamicShadows()
CreateWholeSceneProjectedShadow()
- void FSceneRenderer::CreateWholeSceneProjectedShadow(
- FLightSceneInfo* LightSceneInfo,
- uint32& InOutNumPointShadowCachesUpdatedThisFrame,
- uint32& InOutNumSpotShadowCachesUpdatedThisFrame)
- {
- SCOPE_CYCLE_COUNTER(STAT_CreateWholeSceneProjectedShadow);
- FVisibleLightInfo& VisibleLightInfo = VisibleLightInfos[LightSceneInfo->Id];
-
- // early out if shadow resoluion scale is zero
- if (CVarResolutionScaleZeroDisablesSm.GetValueOnRenderThread() != 0 && LightSceneInfo->Proxy->GetShadowResolutionScale() <= 0.0f)
- {
- return;
- }
-
- // Try to create a whole-scene projected shadow initializer for the light.
- TArray<FWholeSceneProjectedShadowInitializer, TInlineAllocator<6> > ProjectedShadowInitializers;
- if (LightSceneInfo->Proxy->GetWholeSceneProjectedShadowInitializer(ViewFamily, ProjectedShadowInitializers))
- {
- FSceneRenderTargets& SceneContext_ConstantsOnly = FSceneRenderTargets::Get_FrameConstantsOnly();
-
- checkSlow(ProjectedShadowInitializers.Num() > 0);
-
- // Shadow resolution constants.
- const uint32 ShadowBorder = ProjectedShadowInitializers[0].bOnePassPointLightShadow ? 0 : SHADOW_BORDER;
- const uint32 EffectiveDoubleShadowBorder = ShadowBorder * 2;
- const uint32 MinShadowResolution = FMath::Max<int32>(0, CVarMinShadowResolution.GetValueOnRenderThread());
- const int32 MaxShadowResolutionSetting = GetCachedScalabilityCVars().MaxShadowResolution;
- const FIntPoint ShadowBufferResolution = SceneContext_ConstantsOnly.GetShadowDepthTextureResolution();
- const uint32 MaxShadowResolution = FMath::Min(MaxShadowResolutionSetting, ShadowBufferResolution.X) - EffectiveDoubleShadowBorder;
- const uint32 MaxShadowResolutionY = FMath::Min(MaxShadowResolutionSetting, ShadowBufferResolution.Y) - EffectiveDoubleShadowBorder;
- const uint32 ShadowFadeResolution = FMath::Max<int32>(0, CVarShadowFadeResolution.GetValueOnRenderThread());
-
- // Compute the maximum resolution required for the shadow by any view. Also keep track of the unclamped resolution for fading.
- float MaxDesiredResolution = 0;
- TArray<float, TInlineAllocator<2> > FadeAlphas;
- float MaxFadeAlpha = 0;
- bool bStaticSceneOnly = false;
- bool bAnyViewIsSceneCapture = false;
-
- for(int32 ViewIndex = 0, ViewCount = Views.Num(); ViewIndex < ViewCount; ++ViewIndex)
- {
- const FViewInfo& View = Views[ViewIndex];
-
- const float ScreenRadius = LightSceneInfo->Proxy->GetEffectiveScreenRadius(View.ShadowViewMatrices);
-
- // Determine the amount of shadow buffer resolution needed for this view.
- float UnclampedResolution = 1.0f;
-
- switch (LightSceneInfo->Proxy->GetLightType())
- {
- case LightType_Point:
- UnclampedResolution = ScreenRadius * CVarShadowTexelsPerPixelPointlight.GetValueOnRenderThread();
- break;
- case LightType_Spot:
- UnclampedResolution = ScreenRadius * CVarShadowTexelsPerPixelSpotlight.GetValueOnRenderThread();
- break;
- case LightType_Rect:
- UnclampedResolution = ScreenRadius * CVarShadowTexelsPerPixelRectlight.GetValueOnRenderThread();
- break;
- default:
- // directional lights are not handled here
- checkf(false, TEXT("Unexpected LightType %d appears in CreateWholeSceneProjectedShadow %s"),
- (int32)LightSceneInfo->Proxy->GetLightType(),
- *LightSceneInfo->Proxy->GetComponentName().ToString());
- }
-
- // Compute FadeAlpha before ShadowResolutionScale contribution (artists want to modify the softness of the shadow, not change the fade ranges)
- const float FadeAlpha = CalculateShadowFadeAlpha( UnclampedResolution, ShadowFadeResolution, MinShadowResolution ) * LightSceneInfo->Proxy->GetShadowAmount();
- MaxFadeAlpha = FMath::Max(MaxFadeAlpha, FadeAlpha);
- FadeAlphas.Add(FadeAlpha);
-
- const float ShadowResolutionScale = LightSceneInfo->Proxy->GetShadowResolutionScale();
-
- float ClampedResolution = UnclampedResolution;
-
- if (ShadowResolutionScale > 1.0f)
- {
- // Apply ShadowResolutionScale before the MaxShadowResolution clamp if raising the resolution
- ClampedResolution *= ShadowResolutionScale;
- }
-
- ClampedResolution = FMath::Min<float>(ClampedResolution, MaxShadowResolution);
-
- if (ShadowResolutionScale <= 1.0f)
- {
- // Apply ShadowResolutionScale after the MaxShadowResolution clamp if lowering the resolution
- // Artists want to modify the softness of the shadow with ShadowResolutionScale
- ClampedResolution *= ShadowResolutionScale;
- }
-
- MaxDesiredResolution = FMath::Max(
- MaxDesiredResolution,
- FMath::Max<float>(
- ClampedResolution,
- FMath::Min<float>(MinShadowResolution, ShadowBufferResolution.X - EffectiveDoubleShadowBorder)
- )
- );
-
- bStaticSceneOnly = bStaticSceneOnly || View.bStaticSceneOnly;
- bAnyViewIsSceneCapture = bAnyViewIsSceneCapture || View.bIsSceneCapture;
- }
-
- if (MaxFadeAlpha > 1.0f / 256.0f)
- {
- Scene->FlushAsyncLightPrimitiveInteractionCreation();
-
- for (int32 ShadowIndex = 0, ShadowCount = ProjectedShadowInitializers.Num(); ShadowIndex < ShadowCount; ShadowIndex++)
- {
- FWholeSceneProjectedShadowInitializer& ProjectedShadowInitializer = ProjectedShadowInitializers[ShadowIndex];
-
- // Round down to the nearest power of two so that resolution changes are always doubling or halving the resolution, which increases filtering stability
- // Use the max resolution if the desired resolution is larger than that
- // FMath::CeilLogTwo(MaxDesiredResolution + 1.0f) instead of FMath::CeilLogTwo(MaxDesiredResolution) because FMath::CeilLogTwo takes
- // an uint32 as argument and this causes MaxDesiredResolution get truncated. For example, if MaxDesiredResolution is 256.1f,
- // FMath::CeilLogTwo returns 8 but the next line of code expects a 9 to work correctly
- int32 RoundedDesiredResolution = FMath::Max<int32>((1 << (FMath::CeilLogTwo(MaxDesiredResolution + 1.0f) - 1)) - ShadowBorder * 2, 1);
- int32 SizeX = MaxDesiredResolution >= MaxShadowResolution ? MaxShadowResolution : RoundedDesiredResolution;
- int32 SizeY = MaxDesiredResolution >= MaxShadowResolutionY ? MaxShadowResolutionY : RoundedDesiredResolution;
-
- if (ProjectedShadowInitializer.bOnePassPointLightShadow)
- {
- // Round to a resolution that is supported for one pass point light shadows
- SizeX = SizeY = SceneContext_ConstantsOnly.GetCubeShadowDepthZResolution(SceneContext_ConstantsOnly.GetCubeShadowDepthZIndex(MaxDesiredResolution));
- }
-
- int32 NumShadowMaps = 1;
- EShadowDepthCacheMode CacheMode[2] = { SDCM_Uncached, SDCM_Uncached };
-
- if (!bAnyViewIsSceneCapture && !ProjectedShadowInitializer.bRayTracedDistanceField)
- {
- FIntPoint ShadowMapSize(SizeX + ShadowBorder * 2, SizeY + ShadowBorder * 2);
-
- ComputeWholeSceneShadowCacheModes(
- LightSceneInfo,
- ProjectedShadowInitializer.bOnePassPointLightShadow,
- ViewFamily.CurrentRealTime,
- MaxDesiredResolution,
- FIntPoint(MaxShadowResolution, MaxShadowResolutionY),
- Scene,
- // Below are in-out or out parameters. They can change
- ProjectedShadowInitializer,
- ShadowMapSize,
- InOutNumPointShadowCachesUpdatedThisFrame,
- InOutNumSpotShadowCachesUpdatedThisFrame,
- NumShadowMaps,
- CacheMode);
-
- SizeX = ShadowMapSize.X - ShadowBorder * 2;
- SizeY = ShadowMapSize.Y - ShadowBorder * 2;
- }
-
- for (int32 CacheModeIndex = 0; CacheModeIndex < NumShadowMaps; CacheModeIndex++)
- {
- // Create the projected shadow info.
- FProjectedShadowInfo* ProjectedShadowInfo = new(FMemStack::Get(), 1, 16) FProjectedShadowInfo;
-
- ProjectedShadowInfo->SetupWholeSceneProjection(
- LightSceneInfo,
- NULL,
- ProjectedShadowInitializer,
- SizeX,
- SizeY,
- ShadowBorder,
- false // no RSM
- );
-
- ProjectedShadowInfo->CacheMode = CacheMode[CacheModeIndex];
- ProjectedShadowInfo->FadeAlphas = FadeAlphas;
-
- VisibleLightInfo.MemStackProjectedShadows.Add(ProjectedShadowInfo);
-
- if (ProjectedShadowInitializer.bOnePassPointLightShadow)
- {
- const static FVector CubeDirections[6] =
- {
- FVector(-1, 0, 0),
- FVector(1, 0, 0),
- FVector(0, -1, 0),
- FVector(0, 1, 0),
- FVector(0, 0, -1),
- FVector(0, 0, 1)
- };
-
- const static FVector UpVectors[6] =
- {
- FVector(0, 1, 0),
- FVector(0, 1, 0),
- FVector(0, 0, -1),
- FVector(0, 0, 1),
- FVector(0, 1, 0),
- FVector(0, 1, 0)
- };
-
- const FLightSceneProxy& LightProxy = *(ProjectedShadowInfo->GetLightSceneInfo().Proxy);
-
- const FMatrix FaceProjection = FPerspectiveMatrix(PI / 4.0f, 1, 1, 1, LightProxy.GetRadius());
-
- // Light projection and bounding volume is set up relative to the light position
- // the view pre-translation (relative to light) is added later, when rendering & sampling.
- const FVector LightPosition = ProjectedShadowInitializer.WorldToLight.GetOrigin();
-
- ProjectedShadowInfo->OnePassShadowViewMatrices.Empty(6);
- ProjectedShadowInfo->OnePassShadowViewProjectionMatrices.Empty(6);
- const FMatrix ScaleMatrix = FScaleMatrix(FVector(1, -1, 1));
-
- // fill in the caster frustum with the far plane from every face
- ProjectedShadowInfo->CasterFrustum.Planes.Empty();
- for (int32 FaceIndex = 0; FaceIndex < 6; FaceIndex++)
- {
- // Create a view projection matrix for each cube face
- const FMatrix WorldToLightMatrix = FLookFromMatrix(LightPosition, CubeDirections[FaceIndex], UpVectors[FaceIndex]) * ScaleMatrix;
- ProjectedShadowInfo->OnePassShadowViewMatrices.Add(WorldToLightMatrix);
- const FMatrix ShadowViewProjectionMatrix = WorldToLightMatrix * FaceProjection;
- ProjectedShadowInfo->OnePassShadowViewProjectionMatrices.Add(ShadowViewProjectionMatrix);
- // Add plane representing cube face to bounding volume
- ProjectedShadowInfo->CasterFrustum.Planes.Add(FPlane(CubeDirections[FaceIndex], LightProxy.GetRadius()));
- }
- ProjectedShadowInfo->CasterFrustum.Init();
- }
-
- // Ray traced shadows use the GPU managed distance field object buffers, no CPU culling should be used
- if (!ProjectedShadowInfo->bRayTracedDistanceField)
- {
- // Build light-view convex hulls for shadow caster culling
- FLightViewFrustumConvexHulls LightViewFrustumConvexHulls;
- if (CacheMode[CacheModeIndex] != SDCM_StaticPrimitivesOnly)
- {
- FVector const& LightOrigin = LightSceneInfo->Proxy->GetOrigin();
- BuildLightViewFrustumConvexHulls(LightOrigin, Views, LightViewFrustumConvexHulls);
- }
-
- bool bCastCachedShadowFromMovablePrimitives = GCachedShadowsCastFromMovablePrimitives || LightSceneInfo->Proxy->GetForceCachedShadowsForMovablePrimitives();
- if (CacheMode[CacheModeIndex] != SDCM_StaticPrimitivesOnly
- && (CacheMode[CacheModeIndex] != SDCM_MovablePrimitivesOnly || bCastCachedShadowFromMovablePrimitives))
- {
- // Add all the shadow casting primitives affected by the light to the shadow's subject primitive list.
- for (FLightPrimitiveInteraction* Interaction = LightSceneInfo->GetDynamicInteractionOftenMovingPrimitiveList(false);
- Interaction;
- Interaction = Interaction->GetNextPrimitive())
- {
- if (Interaction->HasShadow()
- // If the primitive only wants to cast a self shadow don't include it in whole scene shadows.
- && !Interaction->CastsSelfShadowOnly()
- && (!bStaticSceneOnly || Interaction->GetPrimitiveSceneInfo()->Proxy->HasStaticLighting()))
- {
- FBoxSphereBounds const& Bounds = Interaction->GetPrimitiveSceneInfo()->Proxy->GetBounds();
- if (IntersectsConvexHulls(LightViewFrustumConvexHulls, Bounds))
- {
- ProjectedShadowInfo->AddSubjectPrimitive(Interaction->GetPrimitiveSceneInfo(), &Views, FeatureLevel, false);
- }
- }
- }
- }
-
- if (CacheMode[CacheModeIndex] != SDCM_MovablePrimitivesOnly)
- {
- // Add all the shadow casting primitives affected by the light to the shadow's subject primitive list.
- for (FLightPrimitiveInteraction* Interaction = LightSceneInfo->GetDynamicInteractionStaticPrimitiveList(false);
- Interaction;
- Interaction = Interaction->GetNextPrimitive())
- {
- if (Interaction->HasShadow()
- // If the primitive only wants to cast a self shadow don't include it in whole scene shadows.
- && !Interaction->CastsSelfShadowOnly()
- && (!bStaticSceneOnly || Interaction->GetPrimitiveSceneInfo()->Proxy->HasStaticLighting()))
- {
- FBoxSphereBounds const& Bounds = Interaction->GetPrimitiveSceneInfo()->Proxy->GetBounds();
- if (IntersectsConvexHulls(LightViewFrustumConvexHulls, Bounds))
- {
- ProjectedShadowInfo->AddSubjectPrimitive(Interaction->GetPrimitiveSceneInfo(), &Views, FeatureLevel, false);
- }
- }
- }
- }
- }
-
- bool bRenderShadow = true;
-
- if (CacheMode[CacheModeIndex] == SDCM_StaticPrimitivesOnly)
- {
- const bool bHasStaticPrimitives = ProjectedShadowInfo->HasSubjectPrims();
- bRenderShadow = bHasStaticPrimitives;
- FCachedShadowMapData& CachedShadowMapData = Scene->CachedShadowMaps.FindChecked(ProjectedShadowInfo->GetLightSceneInfo().Id);
- CachedShadowMapData.bCachedShadowMapHasPrimitives = bHasStaticPrimitives;
- }
-
- if (bRenderShadow)
- {
- VisibleLightInfo.AllProjectedShadows.Add(ProjectedShadowInfo);
- }
- }
- }
- }
- }
- }
- void FProjectedShadowInfo::AddSubjectPrimitive(FPrimitiveSceneInfo* PrimitiveSceneInfo, TArray<FViewInfo>* ViewArray, ERHIFeatureLevel::Type FeatureLevel, bool bRecordShadowSubjectsForMobileShading)
- {
- // Ray traced shadows use the GPU managed distance field object buffers, no CPU culling should be used
- check(!bRayTracedDistanceField);
-
- if (!ReceiverPrimitives.Contains(PrimitiveSceneInfo)
- // Far cascade only casts from primitives marked for it
- && (!CascadeSettings.bFarShadowCascade || PrimitiveSceneInfo->Proxy->CastsFarShadow()))
- {
- const FPrimitiveSceneProxy* Proxy = PrimitiveSceneInfo->Proxy;
-
- TArray<FViewInfo*, TInlineAllocator<1> > Views;
- const bool bWholeSceneDirectionalShadow = IsWholeSceneDirectionalShadow();
-
- if (bWholeSceneDirectionalShadow)
- {
- Views.Add(DependentView);
- }
- else
- {
- checkf(ViewArray,
- TEXT("bWholeSceneShadow=%d, CascadeSettings.ShadowSplitIndex=%d, bDirectionalLight=%s"),
- bWholeSceneShadow ? TEXT("true") : TEXT("false"),
- CascadeSettings.ShadowSplitIndex,
- bDirectionalLight ? TEXT("true") : TEXT("false"));
-
- for (int32 ViewIndex = 0; ViewIndex < ViewArray->Num(); ViewIndex++)
- {
- Views.Add(&(*ViewArray)[ViewIndex]);
- }
- }
-
- bool bOpaque = false;
- bool bTranslucentRelevance = false;
- bool bShadowRelevance = false;
-
- uint32 ViewMask = 0;
- int32 PrimitiveId = PrimitiveSceneInfo->GetIndex();
-
- for (int32 ViewIndex = 0, Num = Views.Num(); ViewIndex < Num; ViewIndex++)
- {
- FViewInfo& CurrentView = *Views[ViewIndex];
- FPrimitiveViewRelevance& ViewRelevance = CurrentView.PrimitiveViewRelevanceMap[PrimitiveId];
-
- if (!ViewRelevance.bInitializedThisFrame)
- {
- if( CurrentView.IsPerspectiveProjection() )
- {
- // Compute the distance between the view and the primitive.
- float DistanceSquared = (Proxy->GetBounds().Origin - CurrentView.ShadowViewMatrices.GetViewOrigin()).SizeSquared();
-
- bool bIsDistanceCulled = CurrentView.IsDistanceCulled(
- DistanceSquared,
- Proxy->GetMinDrawDistance(),
- Proxy->GetMaxDrawDistance(),
- PrimitiveSceneInfo
- );
- if( bIsDistanceCulled )
- {
- continue;
- }
- }
-
- // Respect HLOD visibility which can hide child LOD primitives
- if (CurrentView.ViewState &&
- CurrentView.ViewState->HLODVisibilityState.IsValidPrimitiveIndex(PrimitiveId) &&
- CurrentView.ViewState->HLODVisibilityState.IsNodeForcedHidden(PrimitiveId))
- {
- continue;
- }
-
- if ((CurrentView.ShowOnlyPrimitives.IsSet() &&
- !CurrentView.ShowOnlyPrimitives->Contains(PrimitiveSceneInfo->Proxy->GetPrimitiveComponentId())) ||
- CurrentView.HiddenPrimitives.Contains(PrimitiveSceneInfo->Proxy->GetPrimitiveComponentId()))
- {
- continue;
- }
-
- // Compute the subject primitive's view relevance since it wasn't cached
- // Update the main view's PrimitiveViewRelevanceMap
- ViewRelevance = PrimitiveSceneInfo->Proxy->GetViewRelevance(&CurrentView);
-
- ViewMask |= (1 << ViewIndex);
- }
-
- bOpaque |= ViewRelevance.bOpaque || ViewRelevance.bMasked;
- bTranslucentRelevance |= ViewRelevance.HasTranslucency() && !ViewRelevance.bMasked;
- bShadowRelevance |= ViewRelevance.bShadowRelevance;
- }
-
- if (bShadowRelevance)
- {
- // Update the primitive component's last render time. Allows the component to update when using bCastWhenHidden.
- const float CurrentWorldTime = Views[0]->Family->CurrentWorldTime;
- PrimitiveSceneInfo->UpdateComponentLastRenderTime(CurrentWorldTime, /*bUpdateLastRenderTimeOnScreen=*/false);
-
- if (PrimitiveSceneInfo->NeedsUniformBufferUpdate())
- {
- for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
- {
- // Main view visible primitives are processed on parallel tasks, updating uniform buffer them here will cause a race condition.
- check(!Views[ViewIndex]->PrimitiveVisibilityMap[PrimitiveSceneInfo->GetIndex()]);
- }
-
- PrimitiveSceneInfo->ConditionalUpdateUniformBuffer(FRHICommandListExecutor::GetImmediateCommandList());
- }
-
- if (PrimitiveSceneInfo->NeedsUpdateStaticMeshes())
- {
- // Need to defer to next InitViews, as main view visible primitives are processed on parallel tasks and calling
- // CacheMeshDrawCommands may resize CachedDrawLists/CachedMeshDrawCommandStateBuckets causing a crash.
- PrimitiveSceneInfo->BeginDeferredUpdateStaticMeshesWithoutVisibilityCheck();
- }
- }
-
- if (bOpaque && bShadowRelevance)
- {
- const FBoxSphereBounds& Bounds = Proxy->GetBounds();
- bool bDrawingStaticMeshes = false;
-
- if (PrimitiveSceneInfo->StaticMeshes.Num() > 0)
- {
- for (int32 ViewIndex = 0, ViewCount = Views.Num(); ViewIndex < ViewCount; ViewIndex++)
- {
- FViewInfo& CurrentView = *Views[ViewIndex];
-
- const float DistanceSquared = ( Bounds.Origin - CurrentView.ShadowViewMatrices.GetViewOrigin() ).SizeSquared();
-
- if (bWholeSceneShadow)
- {
- const float LODScaleSquared = FMath::Square(CurrentView.LODDistanceFactor);
- const bool bDrawShadowDepth = FMath::Square(Bounds.SphereRadius) > FMath::Square(GMinScreenRadiusForShadowCaster) * DistanceSquared * LODScaleSquared;
- if( !bDrawShadowDepth )
- {
- // cull object if it's too small to be considered as shadow caster
- continue;
- }
- }
-
- // Update visibility for meshes which weren't visible in the main views or were visible with static relevance
- if (!CurrentView.PrimitiveVisibilityMap[PrimitiveId] || CurrentView.PrimitiveViewRelevanceMap[PrimitiveId].bStaticRelevance)
- {
- bDrawingStaticMeshes |= ShouldDrawStaticMeshes(CurrentView, PrimitiveSceneInfo);
- }
- }
- }
-
- if (bDrawingStaticMeshes)
- {
- if (bRecordShadowSubjectsForMobileShading)
- {
- DependentView->VisibleLightInfos[GetLightSceneInfo().Id].MobileCSMSubjectPrimitives.AddSubjectPrimitive(PrimitiveSceneInfo, PrimitiveId);
- }
- }
- else
- {
- // Add the primitive to the subject primitive list.
- DynamicSubjectPrimitives.Add(PrimitiveSceneInfo);
-
- if (bRecordShadowSubjectsForMobileShading)
- {
- DependentView->VisibleLightInfos[GetLightSceneInfo().Id].MobileCSMSubjectPrimitives.AddSubjectPrimitive(PrimitiveSceneInfo, PrimitiveId);
- }
- }
- }
-
- // Add translucent shadow casting primitives to SubjectTranslucentPrimitives
- if (bTranslucentRelevance && bShadowRelevance)
- {
- SubjectTranslucentPrimitives.Add(PrimitiveSceneInfo);
- }
- }
- }
- bool FProjectedShadowInfo::ShouldDrawStaticMeshes(FViewInfo& InCurrentView, FPrimitiveSceneInfo* InPrimitiveSceneInfo)
- {
- bool WholeSceneDirectionalShadow = IsWholeSceneDirectionalShadow();
- bool bDrawingStaticMeshes = false;
- int32 PrimitiveId = InPrimitiveSceneInfo->GetIndex();
-
- {
- const int32 ForcedLOD = (InCurrentView.Family->EngineShowFlags.LOD) ? (GetCVarForceLODShadow() != -1 ? GetCVarForceLODShadow() : GetCVarForceLOD()) : -1;
- const FLODMask* VisibilePrimitiveLODMask = nullptr;
-
- if (InCurrentView.PrimitivesLODMask[PrimitiveId].ContainsLOD(MAX_int8)) // only calculate it if it's not set
- {
- FLODMask ViewLODToRender;
- float MeshScreenSizeSquared = 0;
- const int8 CurFirstLODIdx = InPrimitiveSceneInfo->Proxy->GetCurrentFirstLODIdx_RenderThread();
-
- const FBoxSphereBounds& Bounds = InPrimitiveSceneInfo->Proxy->GetBounds();
- const float LODScale = InCurrentView.LODDistanceFactor * GetCachedScalabilityCVars().StaticMeshLODDistanceScale;
- ViewLODToRender = ComputeLODForMeshes(InPrimitiveSceneInfo->StaticMeshRelevances, InCurrentView, Bounds.Origin, Bounds.SphereRadius, ForcedLOD, MeshScreenSizeSquared, CurFirstLODIdx, LODScale);
-
- InCurrentView.PrimitivesLODMask[PrimitiveId] = ViewLODToRender;
- }
-
- VisibilePrimitiveLODMask = &InCurrentView.PrimitivesLODMask[PrimitiveId];
- check(VisibilePrimitiveLODMask != nullptr);
-
- FLODMask ShadowLODToRender = *VisibilePrimitiveLODMask;
-
- // Use lowest LOD for PreShadow
- if (bReflectiveShadowmap || (bPreShadow && GPreshadowsForceLowestLOD))
- {
- int8 LODToRenderScan = -MAX_int8;
- FLODMask LODToRender;
-
- for (int32 Index = 0; Index < InPrimitiveSceneInfo->StaticMeshRelevances.Num(); Index++)
- {
- LODToRenderScan = FMath::Max<int8>(InPrimitiveSceneInfo->StaticMeshRelevances[Index].LODIndex, LODToRenderScan);
- }
- if (LODToRenderScan != -MAX_int8)
- {
- ShadowLODToRender.SetLOD(LODToRenderScan);
- }
- }
-
- if (CascadeSettings.bFarShadowCascade)
- {
- extern ENGINE_API int32 GFarShadowStaticMeshLODBias;
- int8 LODToRenderScan = ShadowLODToRender.DitheredLODIndices[0] + GFarShadowStaticMeshLODBias;
-
- for (int32 Index = InPrimitiveSceneInfo->StaticMeshRelevances.Num() - 1; Index >= 0; Index--)
- {
- if (LODToRenderScan == InPrimitiveSceneInfo->StaticMeshRelevances[Index].LODIndex)
- {
- ShadowLODToRender.SetLOD(LODToRenderScan);
- break;
- }
- }
- }
-
- if (WholeSceneDirectionalShadow)
- {
- // Don't cache if it requires per view per mesh state for distance cull fade.
- const bool bIsPrimitiveDistanceCullFading = InCurrentView.PotentiallyFadingPrimitiveMap[InPrimitiveSceneInfo->GetIndex()];
- const bool bCanCache = !bIsPrimitiveDistanceCullFading && !InPrimitiveSceneInfo->NeedsUpdateStaticMeshes();
-
- for (int32 MeshIndex = 0; MeshIndex < InPrimitiveSceneInfo->StaticMeshRelevances.Num(); MeshIndex++)
- {
- const FStaticMeshBatchRelevance& StaticMeshRelevance = InPrimitiveSceneInfo->StaticMeshRelevances[MeshIndex];
- const FStaticMeshBatch& StaticMesh = InPrimitiveSceneInfo->StaticMeshes[MeshIndex];
-
- if ((StaticMeshRelevance.CastShadow || (bSelfShadowOnly && StaticMeshRelevance.bUseForDepthPass)) && ShadowLODToRender.ContainsLOD(StaticMeshRelevance.LODIndex))
- {
- if (GetShadowDepthType() == CSMShadowDepthType && bCanCache)
- {
- AddCachedMeshDrawCommandsForPass(
- PrimitiveId,
- InPrimitiveSceneInfo,
- StaticMeshRelevance,
- StaticMesh,
- InPrimitiveSceneInfo->Scene,
- EMeshPass::CSMShadowDepth,
- ShadowDepthPassVisibleCommands,
- SubjectMeshCommandBuildRequests,
- NumSubjectMeshCommandBuildRequestElements);
- }
- else
- {
- NumSubjectMeshCommandBuildRequestElements += StaticMeshRelevance.NumElements;
- SubjectMeshCommandBuildRequests.Add(&StaticMesh);
- }
-
- bDrawingStaticMeshes = true;
- }
- }
- }
- else
- {
- for (int32 MeshIndex = 0; MeshIndex < InPrimitiveSceneInfo->StaticMeshRelevances.Num(); MeshIndex++)
- {
- const FStaticMeshBatchRelevance& StaticMeshRelevance = InPrimitiveSceneInfo->StaticMeshRelevances[MeshIndex];
- const FStaticMeshBatch& StaticMesh = InPrimitiveSceneInfo->StaticMeshes[MeshIndex];
-
- if ((StaticMeshRelevance.CastShadow || (bSelfShadowOnly && StaticMeshRelevance.bUseForDepthPass)) && ShadowLODToRender.ContainsLOD(StaticMeshRelevance.LODIndex))
- {
- NumSubjectMeshCommandBuildRequestElements += StaticMeshRelevance.NumElements;
- SubjectMeshCommandBuildRequests.Add(&StaticMesh);
-
- bDrawingStaticMeshes = true;
- }
- }
- }
- }
-
- return bDrawingStaticMeshes;
- }
- void FProjectedShadowInfo::AddCachedMeshDrawCommandsForPass(
- int32 PrimitiveIndex,
- const FPrimitiveSceneInfo* InPrimitiveSceneInfo,
- const FStaticMeshBatchRelevance& RESTRICT StaticMeshRelevance,
- const FStaticMeshBatch& StaticMesh,
- const FScene* Scene,
- EMeshPass::Type PassType,
- FMeshCommandOneFrameArray& VisibleMeshCommands,
- TArray<const FStaticMeshBatch*, SceneRenderingAllocator>& MeshCommandBuildRequests,
- int32& NumMeshCommandBuildRequestElements)
- {
- const EShadingPath ShadingPath = Scene->GetShadingPath();
- const bool bUseCachedMeshCommand = UseCachedMeshDrawCommands()
- && !!(FPassProcessorManager::GetPassFlags(ShadingPath, PassType) & EMeshPassFlags::CachedMeshCommands)
- && StaticMeshRelevance.bSupportsCachingMeshDrawCommands;
-
- if (bUseCachedMeshCommand)
- {
- const int32 StaticMeshCommandInfoIndex = StaticMeshRelevance.GetStaticMeshCommandInfoIndex(PassType);
- if (StaticMeshCommandInfoIndex >= 0)
- {
- const FCachedMeshDrawCommandInfo& CachedMeshDrawCommand = InPrimitiveSceneInfo->StaticMeshCommandInfos[StaticMeshCommandInfoIndex];
- const FCachedPassMeshDrawList& SceneDrawList = Scene->CachedDrawLists[PassType];
- const FMeshDrawCommand* MeshDrawCommand = CachedMeshDrawCommand.StateBucketId >= 0
- ? &Scene->CachedMeshDrawCommandStateBuckets[PassType].GetByElementId(CachedMeshDrawCommand.StateBucketId).Key
- : &SceneDrawList.MeshDrawCommands[CachedMeshDrawCommand.CommandIndex];
-
- FVisibleMeshDrawCommand NewVisibleMeshDrawCommand;
-
- NewVisibleMeshDrawCommand.Setup(
- MeshDrawCommand,
- PrimitiveIndex,
- PrimitiveIndex,
- CachedMeshDrawCommand.StateBucketId,
- CachedMeshDrawCommand.MeshFillMode,
- CachedMeshDrawCommand.MeshCullMode,
- CachedMeshDrawCommand.SortKey);
-
- VisibleMeshCommands.Add(NewVisibleMeshDrawCommand);
- }
- }
- else
- {
- NumMeshCommandBuildRequestElements += StaticMeshRelevance.NumElements;
- MeshCommandBuildRequests.Add(&StaticMesh);
- }
- }
- FORCEINLINE_DEBUGGABLE void Setup(
- const FMeshDrawCommand* InMeshDrawCommand,
- int32 InDrawPrimitiveId,
- int32 InScenePrimitiveId,
- int32 InStateBucketId,
- ERasterizerFillMode InMeshFillMode,
- ERasterizerCullMode InMeshCullMode,
- FMeshDrawCommandSortKey InSortKey)
- {
- MeshDrawCommand = InMeshDrawCommand;
- DrawPrimitiveId = InDrawPrimitiveId;
- ScenePrimitiveId = InScenePrimitiveId;
- PrimitiveIdBufferOffset = -1;
- StateBucketId = InStateBucketId;
- MeshFillMode = InMeshFillMode;
- MeshCullMode = InMeshCullMode;
- SortKey = InSortKey;
- }
- class FMeshDrawCommand
- {
- public:
-
- /**
- * Resource bindings
- */
- FMeshDrawShaderBindings ShaderBindings;
- FVertexInputStreamArray VertexStreams;
- FRHIIndexBuffer* IndexBuffer;
-
- /**
- * PSO
- */
- FGraphicsMinimalPipelineStateId CachedPipelineId;
-
- /**
- * Draw command parameters
- */
- uint32 FirstIndex;
- uint32 NumPrimitives;
- uint32 NumInstances;
-
- union
- {
- struct
- {
- uint32 BaseVertexIndex;
- uint32 NumVertices;
- } VertexParams;
-
- struct
- {
- FRHIVertexBuffer* Buffer;
- uint32 Offset;
- } IndirectArgs;
- };
-
- int8 PrimitiveIdStreamIndex;
-
- /** Non-pipeline state */
- uint8 StencilRef;
-
- FMeshDrawCommand() {};
- FMeshDrawCommand(FMeshDrawCommand&& Other) = default;
- FMeshDrawCommand(const FMeshDrawCommand& Other) = default;
- FMeshDrawCommand& operator=(const FMeshDrawCommand& Other) = default;
- FMeshDrawCommand& operator=(FMeshDrawCommand&& Other) = default;
-
- bool MatchesForDynamicInstancing(const FMeshDrawCommand& Rhs) const
- {
- return CachedPipelineId == Rhs.CachedPipelineId
- && StencilRef == Rhs.StencilRef
- && ShaderBindings.MatchesForDynamicInstancing(Rhs.ShaderBindings)
- && VertexStreams == Rhs.VertexStreams
- && PrimitiveIdStreamIndex == Rhs.PrimitiveIdStreamIndex
- && IndexBuffer == Rhs.IndexBuffer
- && FirstIndex == Rhs.FirstIndex
- && NumPrimitives == Rhs.NumPrimitives
- && NumInstances == Rhs.NumInstances
- && ((NumPrimitives > 0 && VertexParams.BaseVertexIndex == Rhs.VertexParams.BaseVertexIndex && VertexParams.NumVertices == Rhs.VertexParams.NumVertices)
- || (NumPrimitives == 0 && IndirectArgs.Buffer == Rhs.IndirectArgs.Buffer && IndirectArgs.Offset == Rhs.IndirectArgs.Offset));
- }
-
- uint32 GetDynamicInstancingHash() const
- {
- //add and initialize any leftover padding within the struct to avoid unstable keys
- struct FHashKey
- {
- uint32 IndexBuffer;
- uint32 VertexBuffers = 0;
- uint32 VertexStreams = 0;
- uint32 PipelineId;
- uint32 DynamicInstancingHash;
- uint32 FirstIndex;
- uint32 NumPrimitives;
- uint32 NumInstances;
- uint32 IndirectArgsBufferOrBaseVertexIndex;
- uint32 NumVertices;
- uint32 StencilRefAndPrimitiveIdStreamIndex;
-
- static inline uint32 PointerHash(const void* Key)
- {
- #if PLATFORM_64BITS
- // Ignoring the lower 4 bits since they are likely zero anyway.
- // Higher bits are more significant in 64 bit builds.
- return reinterpret_cast<UPTRINT>(Key) >> 4;
- #else
- return reinterpret_cast<UPTRINT>(Key);
- #endif
- };
-
- static inline uint32 HashCombine(uint32 A, uint32 B)
- {
- return A ^ (B + 0x9e3779b9 + (A << 6) + (A >> 2));
- }
- } HashKey;
-
- HashKey.PipelineId = CachedPipelineId.GetId();
- HashKey.StencilRefAndPrimitiveIdStreamIndex = StencilRef | (PrimitiveIdStreamIndex << 8);
- HashKey.DynamicInstancingHash = ShaderBindings.GetDynamicInstancingHash();
-
- for (int index = 0; index < VertexStreams.Num(); index++)
- {
- const FVertexInputStream& VertexInputStream = VertexStreams[index];
- const uint32 StreamIndex = VertexInputStream.StreamIndex;
- const uint32 Offset = VertexInputStream.Offset;
-
- uint32 Packed = (StreamIndex << 28) | Offset;
- HashKey.VertexStreams = FHashKey::HashCombine(HashKey.VertexStreams, Packed);
- HashKey.VertexBuffers = FHashKey::HashCombine(HashKey.VertexBuffers, FHashKey::PointerHash(VertexInputStream.VertexBuffer));
- }
-
- HashKey.IndexBuffer = FHashKey::PointerHash(IndexBuffer);
- HashKey.FirstIndex = FirstIndex;
- HashKey.NumPrimitives = NumPrimitives;
- HashKey.NumInstances = NumInstances;
-
- if (NumPrimitives > 0)
- {
- HashKey.IndirectArgsBufferOrBaseVertexIndex = VertexParams.BaseVertexIndex;
- HashKey.NumVertices = VertexParams.NumVertices;
- }
- else
- {
- HashKey.IndirectArgsBufferOrBaseVertexIndex = FHashKey::PointerHash(IndirectArgs.Buffer);
- HashKey.NumVertices = IndirectArgs.Offset;
- }
-
- return uint32(CityHash64((char*)&HashKey, sizeof(FHashKey)));
- }
-
- /** Sets shaders on the mesh draw command and allocates room for the shader bindings. */
- RENDERER_API void SetShaders(FRHIVertexDeclaration* VertexDeclaration, const FMeshProcessorShaders& Shaders, FGraphicsMinimalPipelineStateInitializer& PipelineState);
-
- inline void SetStencilRef(uint32 InStencilRef)
- {
- StencilRef = InStencilRef;
- // Verify no overflow
- checkSlow((uint32)StencilRef == InStencilRef);
- }
-
- /** Called when the mesh draw command is complete. */
- RENDERER_API void SetDrawParametersAndFinalize(
- const FMeshBatch& MeshBatch,
- int32 BatchElementIndex,
- FGraphicsMinimalPipelineStateId PipelineId,
- const FMeshProcessorShaders* ShadersForDebugging);
-
- void Finalize(FGraphicsMinimalPipelineStateId PipelineId, const FMeshProcessorShaders* ShadersForDebugging)
- {
- CachedPipelineId = PipelineId;
- ShaderBindings.Finalize(ShadersForDebugging);
- }
-
- /** Submits commands to the RHI Commandlist to draw the MeshDrawCommand. */
- static void SubmitDraw(
- const FMeshDrawCommand& RESTRICT MeshDrawCommand,
- const FGraphicsMinimalPipelineStateSet& GraphicsMinimalPipelineStateSet,
- FRHIVertexBuffer* ScenePrimitiveIdsBuffer,
- int32 PrimitiveIdOffset,
- uint32 InstanceFactor,
- FRHICommandList& CommandList,
- class FMeshDrawCommandStateCache& RESTRICT StateCache);
-
- FORCENOINLINE friend uint32 GetTypeHash( const FMeshDrawCommand& Other )
- {
- return Other.CachedPipelineId.GetId();
- }
- #if MESH_DRAW_COMMAND_DEBUG_DATA
- RENDERER_API void SetDebugData(const FPrimitiveSceneProxy* PrimitiveSceneProxy, const FMaterial* Material, const FMaterialRenderProxy* MaterialRenderProxy, const FMeshProcessorShaders& UntypedShaders, const FVertexFactory* VertexFactory);
- #else
- void SetDebugData(const FPrimitiveSceneProxy* PrimitiveSceneProxy, const FMaterial* Material, const FMaterialRenderProxy* MaterialRenderProxy, const FMeshProcessorShaders& UntypedShaders, const FVertexFactory* VertexFactory){}
- #endif
-
- SIZE_T GetAllocatedSize() const
- {
- return ShaderBindings.GetAllocatedSize() + VertexStreams.GetAllocatedSize();
- }
-
- SIZE_T GetDebugDataSize() const
- {
- #if MESH_DRAW_COMMAND_DEBUG_DATA
- return sizeof(DebugData);
- #endif
- return 0;
- }
-
- #if MESH_DRAW_COMMAND_DEBUG_DATA
- void ClearDebugPrimitiveSceneProxy() const
- {
- DebugData.PrimitiveSceneProxyIfNotUsingStateBuckets = nullptr;
- }
- private:
- mutable FMeshDrawCommandDebugData DebugData;
- #endif
- };
MeshPassProcessor.cpp
- void FCachedPassMeshDrawListContext::FinalizeCommand(
- const FMeshBatch& MeshBatch,
- int32 BatchElementIndex,
- int32 DrawPrimitiveId,
- int32 ScenePrimitiveId,
- ERasterizerFillMode MeshFillMode,
- ERasterizerCullMode MeshCullMode,
- FMeshDrawCommandSortKey SortKey,
- 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);
-
- FGraphicsMinimalPipelineStateId PipelineId = FGraphicsMinimalPipelineStateId::GetPersistentId(PipelineState);
-
- MeshDrawCommand.SetDrawParametersAndFinalize(MeshBatch, BatchElementIndex, PipelineId, ShadersForDebugging);
-
- if (UseGPUScene(GMaxRHIShaderPlatform, GMaxRHIFeatureLevel))
- {
- Experimental::FHashElementId SetId;
- auto hash = CachedMeshDrawCommandStateBuckets.ComputeHash(MeshDrawCommand);
- {
- FScopeLock Lock(&CachedMeshDrawCommandLock);
-
- #if UE_BUILD_DEBUG
- FMeshDrawCommand MeshDrawCommandDebug = FMeshDrawCommand(MeshDrawCommand);
- check(MeshDrawCommandDebug.ShaderBindings.GetDynamicInstancingHash() == MeshDrawCommand.ShaderBindings.GetDynamicInstancingHash());
- check(MeshDrawCommandDebug.GetDynamicInstancingHash() == MeshDrawCommand.GetDynamicInstancingHash());
- #endif
- SetId = CachedMeshDrawCommandStateBuckets.FindOrAddIdByHash(hash, MeshDrawCommand, FMeshDrawCommandCount());
- CachedMeshDrawCommandStateBuckets.GetByElementId(SetId).Value.Num++;
-
- #if MESH_DRAW_COMMAND_DEBUG_DATA
- if (CachedMeshDrawCommandStateBuckets.GetByElementId(SetId).Value.Num == 1)
- {
- MeshDrawCommand.ClearDebugPrimitiveSceneProxy(); //When using State Buckets multiple PrimitiveSceneProxies use the same MeshDrawCommand, so The PrimitiveSceneProxy pointer can't be stored.
- }
- #endif
- }
-
- check(CommandInfo.StateBucketId == -1);
- CommandInfo.StateBucketId = SetId.GetIndex();
- check(CommandInfo.CommandIndex == -1);
- }
- else
- {
- check(CommandInfo.CommandIndex == -1);
- FScopeLock Lock(&CachedMeshDrawCommandLock);
- // Only one FMeshDrawCommand supported per FStaticMesh in a pass
- // Allocate at lowest free index so that 'r.DoLazyStaticMeshUpdate' can shrink the TSparseArray more effectively
- CommandInfo.CommandIndex = CachedDrawLists.MeshDrawCommands.EmplaceAtLowestFreeIndex(CachedDrawLists.LowestFreeIndexSearchStart, MeshDrawCommand);
- }
-
- CommandInfo.SortKey = SortKey;
- CommandInfo.MeshFillMode = MeshFillMode;
- CommandInfo.MeshCullMode = MeshCullMode;
- }
- void FMeshDrawCommand::SetDrawParametersAndFinalize(
- const FMeshBatch& MeshBatch,
- int32 BatchElementIndex,
- FGraphicsMinimalPipelineStateId PipelineId,
- const FMeshProcessorShaders* ShadersForDebugging)
- {
- const FMeshBatchElement& BatchElement = MeshBatch.Elements[BatchElementIndex];
-
- check(!BatchElement.IndexBuffer || (BatchElement.IndexBuffer && BatchElement.IndexBuffer->IsInitialized() && BatchElement.IndexBuffer->IndexBufferRHI));
- checkSlow(!BatchElement.bIsInstanceRuns);
- IndexBuffer = BatchElement.IndexBuffer ? BatchElement.IndexBuffer->IndexBufferRHI.GetReference() : nullptr;
- FirstIndex = BatchElement.FirstIndex;
- NumPrimitives = BatchElement.NumPrimitives;
- NumInstances = BatchElement.NumInstances;
-
- if (NumPrimitives > 0)
- {
- VertexParams.BaseVertexIndex = BatchElement.BaseVertexIndex;
- VertexParams.NumVertices = BatchElement.MaxVertexIndex - BatchElement.MinVertexIndex + 1;
- checkf(!BatchElement.IndirectArgsBuffer, TEXT("FMeshBatchElement::NumPrimitives must be set to 0 when a IndirectArgsBuffer is used"));
- }
- else
- {
- checkf(BatchElement.IndirectArgsBuffer, TEXT("It is only valid to set BatchElement.NumPrimitives == 0 when a IndirectArgsBuffer is used"));
- IndirectArgs.Buffer = BatchElement.IndirectArgsBuffer;
- IndirectArgs.Offset = BatchElement.IndirectArgsOffset;
- }
-
- Finalize(PipelineId, ShadersForDebugging);
- }
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。