赞
踩
FSceneRenderer::InitDynamicShadows()
SetupInteractionShadows
- void FSceneRenderer::SetupInteractionShadows(
- FRHICommandListImmediate& RHICmdList,
- FLightPrimitiveInteraction* Interaction,
- FVisibleLightInfo& VisibleLightInfo,
- bool bStaticSceneOnly,
- const TArray<FProjectedShadowInfo*,SceneRenderingAllocator>& ViewDependentWholeSceneShadows,
- TArray<FProjectedShadowInfo*,SceneRenderingAllocator>& PreShadows)
- {
- // too high on hit count to leave on
- // SCOPE_CYCLE_COUNTER(STAT_SetupInteractionShadows);
-
- FPrimitiveSceneInfo* PrimitiveSceneInfo = Interaction->GetPrimitiveSceneInfo();
- FLightSceneProxy* LightProxy = Interaction->GetLight()->Proxy;
- extern bool GUseTranslucencyShadowDepths;
-
- bool bShadowHandledByParent = false;
-
- if (PrimitiveSceneInfo->LightingAttachmentRoot.IsValid())
- {
- FAttachmentGroupSceneInfo& AttachmentGroup = Scene->AttachmentGroups.FindChecked(PrimitiveSceneInfo->LightingAttachmentRoot);
- bShadowHandledByParent = AttachmentGroup.ParentSceneInfo && AttachmentGroup.ParentSceneInfo->Proxy->LightAttachmentsAsGroup();
- }
-
- // Shadowing for primitives with a shadow parent will be handled by that shadow parent
- if (!bShadowHandledByParent)
- {
- const bool bCreateTranslucentObjectShadow = GUseTranslucencyShadowDepths && Interaction->HasTranslucentObjectShadow();
- const bool bCreateInsetObjectShadow = Interaction->HasInsetObjectShadow();
- const bool bCreateObjectShadowForStationaryLight = ShouldCreateObjectShadowForStationaryLight(Interaction->GetLight(), PrimitiveSceneInfo->Proxy, Interaction->IsShadowMapped());
-
- if (Interaction->HasShadow()
- // TODO: Handle inset shadows, especially when an object is only casting a self-shadow.
- // Only render shadows from objects that use static lighting during a reflection capture, since the reflection capture doesn't update at runtime
- && (!bStaticSceneOnly || PrimitiveSceneInfo->Proxy->HasStaticLighting())
- && (bCreateTranslucentObjectShadow || bCreateInsetObjectShadow || bCreateObjectShadowForStationaryLight))
- {
- // Create projected shadow infos
- CreatePerObjectProjectedShadow(RHICmdList, Interaction, bCreateTranslucentObjectShadow, bCreateInsetObjectShadow || bCreateObjectShadowForStationaryLight, ViewDependentWholeSceneShadows, PreShadows);
- }
- }
- }
- void FSceneRenderer::CreatePerObjectProjectedShadow(
- FRHICommandListImmediate& RHICmdList,
- FLightPrimitiveInteraction* Interaction,
- bool bCreateTranslucentObjectShadow,
- bool bCreateOpaqueObjectShadow,
- const TArray<FProjectedShadowInfo*,SceneRenderingAllocator>& ViewDependentWholeSceneShadows,
- TArray<FProjectedShadowInfo*, SceneRenderingAllocator>& OutPreShadows)
- {
- check(bCreateOpaqueObjectShadow || bCreateTranslucentObjectShadow);
- FPrimitiveSceneInfo* PrimitiveSceneInfo = Interaction->GetPrimitiveSceneInfo();
- const int32 PrimitiveId = PrimitiveSceneInfo->GetIndex();
-
- FLightSceneInfo* LightSceneInfo = Interaction->GetLight();
- FVisibleLightInfo& VisibleLightInfo = VisibleLightInfos[LightSceneInfo->Id];
-
- // Check if the shadow is visible in any of the views.
- bool bShadowIsPotentiallyVisibleNextFrame = false;
- bool bOpaqueShadowIsVisibleThisFrame = false;
- bool bSubjectIsVisible = false;
- bool bOpaque = false;
- bool bTranslucentRelevance = false;
- bool bTranslucentShadowIsVisibleThisFrame = false;
- int32 NumBufferedFrames = FOcclusionQueryHelpers::GetNumBufferedFrames(FeatureLevel);
-
- for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
- {
- const FViewInfo& View = Views[ViewIndex];
-
- // Lookup the primitive's cached view relevance
- FPrimitiveViewRelevance ViewRelevance = View.PrimitiveViewRelevanceMap[PrimitiveId];
-
- if (!ViewRelevance.bInitializedThisFrame)
- {
- // Compute the subject primitive's view relevance since it wasn't cached
- ViewRelevance = PrimitiveSceneInfo->Proxy->GetViewRelevance(&View);
- }
-
- // Check if the subject primitive is shadow relevant.
- const bool bPrimitiveIsShadowRelevant = ViewRelevance.bShadowRelevance;
-
- const FSceneViewState::FProjectedShadowKey OpaqueKey(PrimitiveSceneInfo->PrimitiveComponentId, LightSceneInfo->Proxy->GetLightComponent(), INDEX_NONE, false);
-
- // Check if the shadow and preshadow are occluded.
- const bool bOpaqueShadowIsOccluded =
- !bCreateOpaqueObjectShadow ||
- (
- !View.bIgnoreExistingQueries && View.State &&
- ((FSceneViewState*)View.State)->IsShadowOccluded(RHICmdList, OpaqueKey, NumBufferedFrames)
- );
-
- const FSceneViewState::FProjectedShadowKey TranslucentKey(PrimitiveSceneInfo->PrimitiveComponentId, LightSceneInfo->Proxy->GetLightComponent(), INDEX_NONE, true);
-
- const bool bTranslucentShadowIsOccluded =
- !bCreateTranslucentObjectShadow ||
- (
- !View.bIgnoreExistingQueries && View.State &&
- ((FSceneViewState*)View.State)->IsShadowOccluded(RHICmdList, TranslucentKey, NumBufferedFrames)
- );
-
- // if subject doesn't render in the main pass, it's never considered visible
- // (in this case, there will be no need to generate any preshadows for the subject)
- if (PrimitiveSceneInfo->Proxy->ShouldRenderInMainPass())
- {
- const bool bSubjectIsVisibleInThisView = View.PrimitiveVisibilityMap[PrimitiveSceneInfo->GetIndex()];
- bSubjectIsVisible |= bSubjectIsVisibleInThisView;
- }
-
- // The shadow is visible if it is view relevant and unoccluded.
- bOpaqueShadowIsVisibleThisFrame |= (bPrimitiveIsShadowRelevant && !bOpaqueShadowIsOccluded);
- bTranslucentShadowIsVisibleThisFrame |= (bPrimitiveIsShadowRelevant && !bTranslucentShadowIsOccluded);
- bShadowIsPotentiallyVisibleNextFrame |= bPrimitiveIsShadowRelevant;
- bOpaque |= ViewRelevance.bOpaque;
- bTranslucentRelevance |= ViewRelevance.HasTranslucency();
- }
-
- if (!bOpaqueShadowIsVisibleThisFrame && !bTranslucentShadowIsVisibleThisFrame && !bShadowIsPotentiallyVisibleNextFrame)
- {
- // Don't setup the shadow info for shadows which don't need to be rendered or occlusion tested.
- return;
- }
-
- TArray<FPrimitiveSceneInfo*, SceneRenderingAllocator> ShadowGroupPrimitives;
- PrimitiveSceneInfo->GatherLightingAttachmentGroupPrimitives(ShadowGroupPrimitives);
-
- #if ENABLE_NAN_DIAGNOSTIC
- // allow for silent failure: only possible if NaN checking is enabled.
- if (ShadowGroupPrimitives.Num() == 0)
- {
- return;
- }
- #endif
-
- // Compute the composite bounds of this group of shadow primitives.
- FBoxSphereBounds OriginalBounds = ShadowGroupPrimitives[0]->Proxy->GetBounds();
-
- if (!ensureMsgf(OriginalBounds.ContainsNaN() == false, TEXT("OriginalBound contains NaN : %s"), *OriginalBounds.ToString()))
- {
- // fix up OriginalBounds. This is going to cause flickers
- OriginalBounds = FBoxSphereBounds(FVector::ZeroVector, FVector(1.f), 1.f);
- }
-
- for (int32 ChildIndex = 1; ChildIndex < ShadowGroupPrimitives.Num(); ChildIndex++)
- {
- const FPrimitiveSceneInfo* ShadowChild = ShadowGroupPrimitives[ChildIndex];
- if (ShadowChild->Proxy->CastsDynamicShadow())
- {
- FBoxSphereBounds ChildBound = ShadowChild->Proxy->GetBounds();
- OriginalBounds = OriginalBounds + ChildBound;
-
- if (!ensureMsgf(OriginalBounds.ContainsNaN() == false, TEXT("Child %s contains NaN : %s"), *ShadowChild->Proxy->GetOwnerName().ToString(), *ChildBound.ToString()))
- {
- // fix up OriginalBounds. This is going to cause flickers
- OriginalBounds = FBoxSphereBounds(FVector::ZeroVector, FVector(1.f), 1.f);
- }
- }
- }
-
- FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
-
- // Shadowing constants.
-
- const uint32 MaxShadowResolutionSetting = GetCachedScalabilityCVars().MaxShadowResolution;
- const FIntPoint ShadowBufferResolution = SceneContext.GetShadowDepthTextureResolution();
- const uint32 MaxShadowResolution = FMath::Min<int32>(MaxShadowResolutionSetting, ShadowBufferResolution.X) - SHADOW_BORDER * 2;
- const uint32 MaxShadowResolutionY = FMath::Min<int32>(MaxShadowResolutionSetting, ShadowBufferResolution.Y) - SHADOW_BORDER * 2;
- const uint32 MinShadowResolution = FMath::Max<int32>(0, CVarMinShadowResolution.GetValueOnRenderThread());
- const uint32 ShadowFadeResolution = FMath::Max<int32>(0, CVarShadowFadeResolution.GetValueOnRenderThread());
- const uint32 MinPreShadowResolution = FMath::Max<int32>(0, CVarMinPreShadowResolution.GetValueOnRenderThread());
- const uint32 PreShadowFadeResolution = FMath::Max<int32>(0, CVarPreShadowFadeResolution.GetValueOnRenderThread());
-
- // Compute the maximum resolution required for the shadow by any view. Also keep track of the unclamped resolution for fading.
- uint32 MaxDesiredResolution = 0;
- float MaxScreenPercent = 0;
- TArray<float, TInlineAllocator<2> > ResolutionFadeAlphas;
- TArray<float, TInlineAllocator<2> > ResolutionPreShadowFadeAlphas;
- float MaxResolutionFadeAlpha = 0;
- float MaxResolutionPreShadowFadeAlpha = 0;
-
- for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
- {
- const FViewInfo& View = Views[ViewIndex];
-
- // Determine the size of the subject's bounding sphere in this view.
- const FVector ShadowViewOrigin = View.ViewMatrices.GetViewOrigin();
- float ShadowViewDistFromBounds = (OriginalBounds.Origin - ShadowViewOrigin).Size();
- const float ScreenRadius = View.ShadowViewMatrices.GetScreenScale() *
- OriginalBounds.SphereRadius /
- FMath::Max(ShadowViewDistFromBounds, 1.0f);
- // Early catch for invalid CalculateShadowFadeAlpha()
- ensureMsgf(ScreenRadius >= 0.0f, TEXT("View.ShadowViewMatrices.ScreenScale %f, OriginalBounds.SphereRadius %f, ShadowViewDistFromBounds %f"), View.ShadowViewMatrices.GetScreenScale(), OriginalBounds.SphereRadius, ShadowViewDistFromBounds);
-
- const float ScreenPercent = FMath::Max(
- 1.0f / 2.0f * View.ShadowViewMatrices.GetProjectionScale().X,
- 1.0f / 2.0f * View.ShadowViewMatrices.GetProjectionScale().Y
- ) *
- OriginalBounds.SphereRadius /
- FMath::Max(ShadowViewDistFromBounds, 1.0f);
-
- MaxScreenPercent = FMath::Max(MaxScreenPercent, ScreenPercent);
-
- // Determine the amount of shadow buffer resolution needed for this view.
- const float UnclampedResolution = ScreenRadius * CVarShadowTexelsPerPixel.GetValueOnRenderThread();
-
- // Calculate fading based on resolution
- // Compute FadeAlpha before ShadowResolutionScale contribution (artists want to modify the softness of the shadow, not change the fade ranges)
- const float ViewSpecificAlpha = CalculateShadowFadeAlpha(UnclampedResolution, ShadowFadeResolution, MinShadowResolution) * LightSceneInfo->Proxy->GetShadowAmount();
- MaxResolutionFadeAlpha = FMath::Max(MaxResolutionFadeAlpha, ViewSpecificAlpha);
- ResolutionFadeAlphas.Add(ViewSpecificAlpha);
-
- const float ViewSpecificPreShadowAlpha = CalculateShadowFadeAlpha(UnclampedResolution * CVarPreShadowResolutionFactor.GetValueOnRenderThread(), PreShadowFadeResolution, MinPreShadowResolution) * LightSceneInfo->Proxy->GetShadowAmount();
- MaxResolutionPreShadowFadeAlpha = FMath::Max(MaxResolutionPreShadowFadeAlpha, ViewSpecificPreShadowAlpha);
- ResolutionPreShadowFadeAlphas.Add(ViewSpecificPreShadowAlpha);
-
- 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<uint32>(
- ClampedResolution,
- FMath::Min<int32>(MinShadowResolution, ShadowBufferResolution.X - SHADOW_BORDER * 2)
- )
- );
- }
-
- FBoxSphereBounds Bounds = OriginalBounds;
-
- const bool bRenderPreShadow =
- CVarAllowPreshadows.GetValueOnRenderThread()
- && LightSceneInfo->Proxy->HasStaticShadowing()
- // Preshadow only affects the subject's pixels
- && bSubjectIsVisible
- // Only objects with dynamic lighting should create a preshadow
- // Unless we're in the editor and need to preview an object without built lighting
- && (!PrimitiveSceneInfo->Proxy->HasStaticLighting() || !Interaction->IsShadowMapped())
- // Disable preshadows from directional lights for primitives that use single sample shadowing, the shadow factor will be written into the precomputed shadow mask in the GBuffer instead
- && !(PrimitiveSceneInfo->Proxy->UseSingleSampleShadowFromStationaryLights() && LightSceneInfo->Proxy->GetLightType() == LightType_Directional)
- && Scene->GetFeatureLevel() >= ERHIFeatureLevel::SM5;
-
- if (bRenderPreShadow && ShouldUseCachePreshadows())
- {
- float PreshadowExpandFraction = FMath::Max(CVarPreshadowExpandFraction.GetValueOnRenderThread(), 0.0f);
-
- // If we're creating a preshadow, expand the bounds somewhat so that the preshadow will be cached more often as the shadow caster moves around.
- //@todo - only expand the preshadow bounds for this, not the per object shadow.
- Bounds.SphereRadius += (Bounds.BoxExtent * PreshadowExpandFraction).Size();
- Bounds.BoxExtent *= PreshadowExpandFraction + 1.0f;
- }
-
- // Compute the projected shadow initializer for this primitive-light pair.
- FPerObjectProjectedShadowInitializer ShadowInitializer;
-
- if ((MaxResolutionFadeAlpha > 1.0f / 256.0f || (bRenderPreShadow && MaxResolutionPreShadowFadeAlpha > 1.0f / 256.0f))
- && LightSceneInfo->Proxy->GetPerObjectProjectedShadowInitializer(Bounds, ShadowInitializer))
- {
- const float MaxFadeAlpha = MaxResolutionFadeAlpha;
-
- // Only create a shadow from this object if it hasn't completely faded away
- if (CVarAllowPerObjectShadows.GetValueOnRenderThread() && MaxFadeAlpha > 1.0f / 256.0f)
- {
- // 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
- const int32 SizeX = MaxDesiredResolution >= MaxShadowResolution ? MaxShadowResolution : (1 << (FMath::CeilLogTwo(MaxDesiredResolution) - 1));
-
- if (bOpaque && bCreateOpaqueObjectShadow && (bOpaqueShadowIsVisibleThisFrame || bShadowIsPotentiallyVisibleNextFrame))
- {
- // Create a projected shadow for this interaction's shadow.
- FProjectedShadowInfo* ProjectedShadowInfo = new(FMemStack::Get(),1,16) FProjectedShadowInfo;
-
- if(ProjectedShadowInfo->SetupPerObjectProjection(
- LightSceneInfo,
- PrimitiveSceneInfo,
- ShadowInitializer,
- false, // no preshadow
- SizeX,
- MaxShadowResolutionY,
- SHADOW_BORDER,
- MaxScreenPercent,
- false)) // no translucent shadow
- {
- ProjectedShadowInfo->bPerObjectOpaqueShadow = true;
- ProjectedShadowInfo->FadeAlphas = ResolutionFadeAlphas;
- VisibleLightInfo.MemStackProjectedShadows.Add(ProjectedShadowInfo);
-
- if (bOpaqueShadowIsVisibleThisFrame)
- {
- VisibleLightInfo.AllProjectedShadows.Add(ProjectedShadowInfo);
-
- for (int32 ChildIndex = 0, ChildCount = ShadowGroupPrimitives.Num(); ChildIndex < ChildCount; ChildIndex++)
- {
- FPrimitiveSceneInfo* ShadowChild = ShadowGroupPrimitives[ChildIndex];
- ProjectedShadowInfo->AddSubjectPrimitive(ShadowChild, &Views, FeatureLevel, false);
- }
- }
- else if (bShadowIsPotentiallyVisibleNextFrame)
- {
- VisibleLightInfo.OccludedPerObjectShadows.Add(ProjectedShadowInfo);
- }
- }
- }
-
- if (bTranslucentRelevance
- && Scene->GetFeatureLevel() >= ERHIFeatureLevel::SM5
- && bCreateTranslucentObjectShadow
- && (bTranslucentShadowIsVisibleThisFrame || bShadowIsPotentiallyVisibleNextFrame))
- {
- // Create a projected shadow for this interaction's shadow.
- FProjectedShadowInfo* ProjectedShadowInfo = new(FMemStack::Get(),1,16) FProjectedShadowInfo;
-
- if(ProjectedShadowInfo->SetupPerObjectProjection(
- LightSceneInfo,
- PrimitiveSceneInfo,
- ShadowInitializer,
- false, // no preshadow
- // Size was computed for the full res opaque shadow, convert to downsampled translucent shadow size with proper clamping
- FMath::Clamp<int32>(SizeX / SceneContext.GetTranslucentShadowDownsampleFactor(), 1, SceneContext.GetTranslucentShadowDepthTextureResolution().X - SHADOW_BORDER * 2),
- FMath::Clamp<int32>(MaxShadowResolutionY / SceneContext.GetTranslucentShadowDownsampleFactor(), 1, SceneContext.GetTranslucentShadowDepthTextureResolution().Y - SHADOW_BORDER * 2),
- SHADOW_BORDER,
- MaxScreenPercent,
- true)) // translucent shadow
- {
- ProjectedShadowInfo->FadeAlphas = ResolutionFadeAlphas,
- VisibleLightInfo.MemStackProjectedShadows.Add(ProjectedShadowInfo);
-
- if (bTranslucentShadowIsVisibleThisFrame)
- {
- VisibleLightInfo.AllProjectedShadows.Add(ProjectedShadowInfo);
-
- for (int32 ChildIndex = 0, ChildCount = ShadowGroupPrimitives.Num(); ChildIndex < ChildCount; ChildIndex++)
- {
- FPrimitiveSceneInfo* ShadowChild = ShadowGroupPrimitives[ChildIndex];
- ProjectedShadowInfo->AddSubjectPrimitive(ShadowChild, &Views, FeatureLevel, false);
- }
- }
- else if (bShadowIsPotentiallyVisibleNextFrame)
- {
- VisibleLightInfo.OccludedPerObjectShadows.Add(ProjectedShadowInfo);
- }
- }
- }
- }
-
- const float MaxPreFadeAlpha = MaxResolutionPreShadowFadeAlpha;
-
- // If the subject is visible in at least one view, create a preshadow for static primitives shadowing the subject.
- if (MaxPreFadeAlpha > 1.0f / 256.0f
- && bRenderPreShadow
- && bOpaque)
- {
- // Round down to the nearest power of two so that resolution changes are always doubling or halving the resolution, which increases filtering stability.
- int32 PreshadowSizeX = 1 << (FMath::CeilLogTwo(FMath::TruncToInt(MaxDesiredResolution * CVarPreShadowResolutionFactor.GetValueOnRenderThread())) - 1);
-
- const FIntPoint PreshadowCacheResolution = SceneContext.GetPreShadowCacheTextureResolution();
- checkSlow(PreshadowSizeX <= PreshadowCacheResolution.X);
- bool bIsOutsideWholeSceneShadow = true;
-
- for (int32 i = 0; i < ViewDependentWholeSceneShadows.Num(); i++)
- {
- const FProjectedShadowInfo* WholeSceneShadow = ViewDependentWholeSceneShadows[i];
- const FVector2D DistanceFadeValues = WholeSceneShadow->GetLightSceneInfo().Proxy->GetDirectionalLightDistanceFadeParameters(Scene->GetFeatureLevel(), WholeSceneShadow->GetLightSceneInfo().IsPrecomputedLightingValid(), WholeSceneShadow->DependentView->MaxShadowCascades);
- const float DistanceFromShadowCenterSquared = (WholeSceneShadow->ShadowBounds.Center - Bounds.Origin).SizeSquared();
- //@todo - if view dependent whole scene shadows are ever supported in splitscreen,
- // We can only disable the preshadow at this point if it is inside a whole scene shadow for all views
- const float DistanceFromViewSquared = ((FVector)WholeSceneShadow->DependentView->ShadowViewMatrices.GetViewOrigin() - Bounds.Origin).SizeSquared();
- // Mark the preshadow as inside the whole scene shadow if its bounding sphere is inside the near fade distance
- if (DistanceFromShadowCenterSquared < FMath::Square(FMath::Max(WholeSceneShadow->ShadowBounds.W - Bounds.SphereRadius, 0.0f))
- //@todo - why is this extra threshold required?
- && DistanceFromViewSquared < FMath::Square(FMath::Max(DistanceFadeValues.X - 200.0f - Bounds.SphereRadius, 0.0f)))
- {
- bIsOutsideWholeSceneShadow = false;
- break;
- }
- }
-
- // Only create opaque preshadows when part of the caster is outside the whole scene shadow.
- if (bIsOutsideWholeSceneShadow)
- {
- // Try to reuse a preshadow from the cache
- TRefCountPtr<FProjectedShadowInfo> ProjectedPreShadowInfo = GetCachedPreshadow(Interaction, ShadowInitializer, OriginalBounds, PreshadowSizeX);
-
- bool bOk = true;
-
- if(!ProjectedPreShadowInfo)
- {
- // Create a new projected shadow for this interaction's preshadow
- // Not using the scene rendering mem stack because this shadow info may need to persist for multiple frames if it gets cached
- ProjectedPreShadowInfo = new FProjectedShadowInfo;
-
- bOk = ProjectedPreShadowInfo->SetupPerObjectProjection(
- LightSceneInfo,
- PrimitiveSceneInfo,
- ShadowInitializer,
- true, // preshadow
- PreshadowSizeX,
- FMath::TruncToInt(MaxShadowResolutionY * CVarPreShadowResolutionFactor.GetValueOnRenderThread()),
- SHADOW_BORDER,
- MaxScreenPercent,
- false // not translucent shadow
- );
- }
-
- if (bOk)
- {
-
- // Update fade alpha on the cached preshadow
- ProjectedPreShadowInfo->FadeAlphas = ResolutionPreShadowFadeAlphas;
-
- VisibleLightInfo.AllProjectedShadows.Add(ProjectedPreShadowInfo);
- VisibleLightInfo.ProjectedPreShadows.Add(ProjectedPreShadowInfo);
-
- // Only add to OutPreShadows if the preshadow doesn't already have depths cached,
- // Since OutPreShadows is used to generate information only used when rendering the shadow depths.
- if (!ProjectedPreShadowInfo->bDepthsCached && ProjectedPreShadowInfo->CasterFrustum.PermutedPlanes.Num())
- {
- OutPreShadows.Add(ProjectedPreShadowInfo);
- }
-
- for (int32 ChildIndex = 0; ChildIndex < ShadowGroupPrimitives.Num(); ChildIndex++)
- {
- FPrimitiveSceneInfo* ShadowChild = ShadowGroupPrimitives[ChildIndex];
- bool bChildIsVisibleInAnyView = false;
- for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
- {
- const FViewInfo& View = Views[ViewIndex];
- if (View.PrimitiveVisibilityMap[ShadowChild->GetIndex()])
- {
- bChildIsVisibleInAnyView = true;
- break;
- }
- }
- if (bChildIsVisibleInAnyView)
- {
- ProjectedPreShadowInfo->AddReceiverPrimitive(ShadowChild);
- }
- }
- }
- }
- }
- }
- }
- 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::SetupPerObjectProjection(
- FLightSceneInfo* InLightSceneInfo,
- const FPrimitiveSceneInfo* InParentSceneInfo,
- const FPerObjectProjectedShadowInitializer& Initializer,
- bool bInPreShadow,
- uint32 InResolutionX,
- uint32 MaxShadowResolutionY,
- uint32 InBorderSize,
- float InMaxScreenPercent,
- bool bInTranslucentShadow)
- {
- check(InParentSceneInfo);
-
- LightSceneInfo = InLightSceneInfo;
- LightSceneInfoCompact = InLightSceneInfo;
- ParentSceneInfo = InParentSceneInfo;
- PreShadowTranslation = Initializer.PreShadowTranslation;
- ShadowBounds = FSphere(Initializer.SubjectBounds.Origin - Initializer.PreShadowTranslation, Initializer.SubjectBounds.SphereRadius);
- ResolutionX = InResolutionX;
- BorderSize = InBorderSize;
- MaxScreenPercent = InMaxScreenPercent;
- bDirectionalLight = InLightSceneInfo->Proxy->GetLightType() == LightType_Directional;
- const ERHIFeatureLevel::Type FeatureLevel = LightSceneInfo->Scene->GetFeatureLevel();
- bCapsuleShadow = InParentSceneInfo->Proxy->CastsCapsuleDirectShadow() && !bInPreShadow && SupportsCapsuleDirectShadows(FeatureLevel, GShaderPlatformForFeatureLevel[FeatureLevel]);
- bTranslucentShadow = bInTranslucentShadow;
- bPreShadow = bInPreShadow;
- bSelfShadowOnly = InParentSceneInfo->Proxy->CastsSelfShadowOnly();
- bTransmission = InLightSceneInfo->Proxy->Transmission();
- bHairStrandsDeepShadow = InLightSceneInfo->Proxy->CastsHairStrandsDeepShadow();
-
- check(!bRayTracedDistanceField);
-
- const FMatrix WorldToLightScaled = Initializer.WorldToLight * FScaleMatrix(Initializer.Scales);
-
- // Create an array of the extreme vertices of the subject's bounds.
- FBoundingBoxVertexArray BoundsPoints;
- FBoundingBoxEdgeArray BoundsEdges;
- GetBoundingBoxVertices(Initializer.SubjectBounds.GetBox(),BoundsPoints,BoundsEdges);
-
- // Project the bounding box vertices.
- FBoundingBoxVertexArray ProjectedBoundsPoints;
- for (int32 PointIndex = 0; PointIndex < BoundsPoints.Num(); PointIndex++)
- {
- const FVector TransformedBoundsPoint = WorldToLightScaled.TransformPosition(BoundsPoints[PointIndex]);
- const float TransformedBoundsPointW = Dot4(FVector4(0, 0, TransformedBoundsPoint | Initializer.FaceDirection,1), Initializer.WAxis);
- if (TransformedBoundsPointW >= DELTA)
- {
- ProjectedBoundsPoints.Add(TransformedBoundsPoint / TransformedBoundsPointW);
- }
- else
- {
- //ProjectedBoundsPoints.Add(FVector(FLT_MAX, FLT_MAX, FLT_MAX));
- return false;
- }
- }
-
- // Compute the transform from light-space to shadow-space.
- FMatrix LightToShadow;
- float AspectRatio;
-
- // if this is a valid transform (can be false if the object is around the light)
- bool bRet = false;
-
- if (GetBestShadowTransform(Initializer.FaceDirection.GetSafeNormal(), ProjectedBoundsPoints, BoundsEdges, AspectRatio, LightToShadow))
- {
- bRet = true;
- const FMatrix WorldToShadow = WorldToLightScaled * LightToShadow;
-
- const FBox ShadowSubjectBounds = Initializer.SubjectBounds.GetBox().TransformBy(WorldToShadow);
-
- MinSubjectZ = FMath::Max(Initializer.MinLightW, ShadowSubjectBounds.Min.Z);
- float MaxReceiverZ = FMath::Min(MinSubjectZ + Initializer.MaxDistanceToCastInLightW, (float)HALF_WORLD_MAX);
- // Max can end up smaller than min due to the clamp to HALF_WORLD_MAX above
- MaxReceiverZ = FMath::Max(MaxReceiverZ, MinSubjectZ + 1);
- MaxSubjectZ = FMath::Max(ShadowSubjectBounds.Max.Z, MinSubjectZ + 1);
-
- const FMatrix SubjectMatrix = WorldToShadow * FShadowProjectionMatrix(MinSubjectZ, MaxSubjectZ, Initializer.WAxis);
- const float MaxSubjectAndReceiverDepth = Initializer.SubjectBounds.GetBox().TransformBy(SubjectMatrix).Max.Z;
-
- float MaxSubjectDepth;
-
- if (bPreShadow)
- {
- const FMatrix PreSubjectMatrix = WorldToShadow * FShadowProjectionMatrix(Initializer.MinLightW, MaxSubjectZ, Initializer.WAxis);
- // Preshadow frustum bounds go from the light to the furthest extent of the object in light space
- SubjectAndReceiverMatrix = PreSubjectMatrix;
- ReceiverMatrix = SubjectMatrix;
- MaxSubjectDepth = bDirectionalLight ? MaxSubjectAndReceiverDepth : Initializer.SubjectBounds.GetBox().TransformBy(PreSubjectMatrix).Max.Z;
- }
- else
- {
- const FMatrix PostSubjectMatrix = WorldToShadow * FShadowProjectionMatrix(MinSubjectZ, MaxReceiverZ, Initializer.WAxis);
- SubjectAndReceiverMatrix = SubjectMatrix;
- ReceiverMatrix = PostSubjectMatrix;
- MaxSubjectDepth = MaxSubjectAndReceiverDepth;
-
- if (bDirectionalLight)
- {
- // No room to fade out if the end of receiver range is inside the subject range, it will just clip.
- if (MaxSubjectZ < MaxReceiverZ)
- {
- float ShadowSubjectRange = MaxSubjectZ - MinSubjectZ;
- float FadeLength = FMath::Min(ShadowSubjectRange, MaxReceiverZ - MaxSubjectZ);
- //Initializer.MaxDistanceToCastInLightW / 16.0f;
- PerObjectShadowFadeStart = (MaxReceiverZ - MinSubjectZ - FadeLength) / ShadowSubjectRange;
- InvPerObjectShadowFadeLength = ShadowSubjectRange / FMath::Max(0.000001f, FadeLength);
- }
- }
- }
-
- InvMaxSubjectDepth = 1.0f / MaxSubjectDepth;
-
- MinPreSubjectZ = Initializer.MinLightW;
-
- ResolutionY = FMath::Clamp<uint32>(FMath::TruncToInt(InResolutionX / AspectRatio), 1, MaxShadowResolutionY);
-
- if (ResolutionX == 0 || ResolutionY == 0)
- {
- bRet = false;
- }
- else
- {
- // Store the view matrix
- // Reorder the vectors to match the main view, since ShadowViewMatrix will be used to override the main view's view matrix during shadow depth rendering
- ShadowViewMatrix = Initializer.WorldToLight *
- FMatrix(
- FPlane(0, 0, 1, 0),
- FPlane(1, 0, 0, 0),
- FPlane(0, 1, 0, 0),
- FPlane(0, 0, 0, 1));
-
- GetViewFrustumBounds(CasterFrustum, SubjectAndReceiverMatrix, true);
-
- InvReceiverMatrix = ReceiverMatrix.InverseFast();
- GetViewFrustumBounds(ReceiverFrustum, ReceiverMatrix, true);
- UpdateShaderDepthBias();
- }
- }
-
- return bRet;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。