当前位置:   article > 正文

阴影初始化【4】_round down to nearest power of two

round down to nearest power of two

FSceneRenderer::InitDynamicShadows()

SetupInteractionShadows

  1. void FSceneRenderer::SetupInteractionShadows(
  2. FRHICommandListImmediate& RHICmdList,
  3. FLightPrimitiveInteraction* Interaction,
  4. FVisibleLightInfo& VisibleLightInfo,
  5. bool bStaticSceneOnly,
  6. const TArray<FProjectedShadowInfo*,SceneRenderingAllocator>& ViewDependentWholeSceneShadows,
  7. TArray<FProjectedShadowInfo*,SceneRenderingAllocator>& PreShadows)
  8. {
  9. // too high on hit count to leave on
  10. // SCOPE_CYCLE_COUNTER(STAT_SetupInteractionShadows);
  11. FPrimitiveSceneInfo* PrimitiveSceneInfo = Interaction->GetPrimitiveSceneInfo();
  12. FLightSceneProxy* LightProxy = Interaction->GetLight()->Proxy;
  13. extern bool GUseTranslucencyShadowDepths;
  14. bool bShadowHandledByParent = false;
  15. if (PrimitiveSceneInfo->LightingAttachmentRoot.IsValid())
  16. {
  17. FAttachmentGroupSceneInfo& AttachmentGroup = Scene->AttachmentGroups.FindChecked(PrimitiveSceneInfo->LightingAttachmentRoot);
  18. bShadowHandledByParent = AttachmentGroup.ParentSceneInfo && AttachmentGroup.ParentSceneInfo->Proxy->LightAttachmentsAsGroup();
  19. }
  20. // Shadowing for primitives with a shadow parent will be handled by that shadow parent
  21. if (!bShadowHandledByParent)
  22. {
  23. const bool bCreateTranslucentObjectShadow = GUseTranslucencyShadowDepths && Interaction->HasTranslucentObjectShadow();
  24. const bool bCreateInsetObjectShadow = Interaction->HasInsetObjectShadow();
  25. const bool bCreateObjectShadowForStationaryLight = ShouldCreateObjectShadowForStationaryLight(Interaction->GetLight(), PrimitiveSceneInfo->Proxy, Interaction->IsShadowMapped());
  26. if (Interaction->HasShadow()
  27. // TODO: Handle inset shadows, especially when an object is only casting a self-shadow.
  28. // Only render shadows from objects that use static lighting during a reflection capture, since the reflection capture doesn't update at runtime
  29. && (!bStaticSceneOnly || PrimitiveSceneInfo->Proxy->HasStaticLighting())
  30. && (bCreateTranslucentObjectShadow || bCreateInsetObjectShadow || bCreateObjectShadowForStationaryLight))
  31. {
  32. // Create projected shadow infos
  33. CreatePerObjectProjectedShadow(RHICmdList, Interaction, bCreateTranslucentObjectShadow, bCreateInsetObjectShadow || bCreateObjectShadowForStationaryLight, ViewDependentWholeSceneShadows, PreShadows);
  34. }
  35. }
  36. }
  1. void FSceneRenderer::CreatePerObjectProjectedShadow(
  2. FRHICommandListImmediate& RHICmdList,
  3. FLightPrimitiveInteraction* Interaction,
  4. bool bCreateTranslucentObjectShadow,
  5. bool bCreateOpaqueObjectShadow,
  6. const TArray<FProjectedShadowInfo*,SceneRenderingAllocator>& ViewDependentWholeSceneShadows,
  7. TArray<FProjectedShadowInfo*, SceneRenderingAllocator>& OutPreShadows)
  8. {
  9. check(bCreateOpaqueObjectShadow || bCreateTranslucentObjectShadow);
  10. FPrimitiveSceneInfo* PrimitiveSceneInfo = Interaction->GetPrimitiveSceneInfo();
  11. const int32 PrimitiveId = PrimitiveSceneInfo->GetIndex();
  12. FLightSceneInfo* LightSceneInfo = Interaction->GetLight();
  13. FVisibleLightInfo& VisibleLightInfo = VisibleLightInfos[LightSceneInfo->Id];
  14. // Check if the shadow is visible in any of the views.
  15. bool bShadowIsPotentiallyVisibleNextFrame = false;
  16. bool bOpaqueShadowIsVisibleThisFrame = false;
  17. bool bSubjectIsVisible = false;
  18. bool bOpaque = false;
  19. bool bTranslucentRelevance = false;
  20. bool bTranslucentShadowIsVisibleThisFrame = false;
  21. int32 NumBufferedFrames = FOcclusionQueryHelpers::GetNumBufferedFrames(FeatureLevel);
  22. for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
  23. {
  24. const FViewInfo& View = Views[ViewIndex];
  25. // Lookup the primitive's cached view relevance
  26. FPrimitiveViewRelevance ViewRelevance = View.PrimitiveViewRelevanceMap[PrimitiveId];
  27. if (!ViewRelevance.bInitializedThisFrame)
  28. {
  29. // Compute the subject primitive's view relevance since it wasn't cached
  30. ViewRelevance = PrimitiveSceneInfo->Proxy->GetViewRelevance(&View);
  31. }
  32. // Check if the subject primitive is shadow relevant.
  33. const bool bPrimitiveIsShadowRelevant = ViewRelevance.bShadowRelevance;
  34. const FSceneViewState::FProjectedShadowKey OpaqueKey(PrimitiveSceneInfo->PrimitiveComponentId, LightSceneInfo->Proxy->GetLightComponent(), INDEX_NONE, false);
  35. // Check if the shadow and preshadow are occluded.
  36. const bool bOpaqueShadowIsOccluded =
  37. !bCreateOpaqueObjectShadow ||
  38. (
  39. !View.bIgnoreExistingQueries && View.State &&
  40. ((FSceneViewState*)View.State)->IsShadowOccluded(RHICmdList, OpaqueKey, NumBufferedFrames)
  41. );
  42. const FSceneViewState::FProjectedShadowKey TranslucentKey(PrimitiveSceneInfo->PrimitiveComponentId, LightSceneInfo->Proxy->GetLightComponent(), INDEX_NONE, true);
  43. const bool bTranslucentShadowIsOccluded =
  44. !bCreateTranslucentObjectShadow ||
  45. (
  46. !View.bIgnoreExistingQueries && View.State &&
  47. ((FSceneViewState*)View.State)->IsShadowOccluded(RHICmdList, TranslucentKey, NumBufferedFrames)
  48. );
  49. // if subject doesn't render in the main pass, it's never considered visible
  50. // (in this case, there will be no need to generate any preshadows for the subject)
  51. if (PrimitiveSceneInfo->Proxy->ShouldRenderInMainPass())
  52. {
  53. const bool bSubjectIsVisibleInThisView = View.PrimitiveVisibilityMap[PrimitiveSceneInfo->GetIndex()];
  54. bSubjectIsVisible |= bSubjectIsVisibleInThisView;
  55. }
  56. // The shadow is visible if it is view relevant and unoccluded.
  57. bOpaqueShadowIsVisibleThisFrame |= (bPrimitiveIsShadowRelevant && !bOpaqueShadowIsOccluded);
  58. bTranslucentShadowIsVisibleThisFrame |= (bPrimitiveIsShadowRelevant && !bTranslucentShadowIsOccluded);
  59. bShadowIsPotentiallyVisibleNextFrame |= bPrimitiveIsShadowRelevant;
  60. bOpaque |= ViewRelevance.bOpaque;
  61. bTranslucentRelevance |= ViewRelevance.HasTranslucency();
  62. }
  63. if (!bOpaqueShadowIsVisibleThisFrame && !bTranslucentShadowIsVisibleThisFrame && !bShadowIsPotentiallyVisibleNextFrame)
  64. {
  65. // Don't setup the shadow info for shadows which don't need to be rendered or occlusion tested.
  66. return;
  67. }
  68. TArray<FPrimitiveSceneInfo*, SceneRenderingAllocator> ShadowGroupPrimitives;
  69. PrimitiveSceneInfo->GatherLightingAttachmentGroupPrimitives(ShadowGroupPrimitives);
  70. #if ENABLE_NAN_DIAGNOSTIC
  71. // allow for silent failure: only possible if NaN checking is enabled.
  72. if (ShadowGroupPrimitives.Num() == 0)
  73. {
  74. return;
  75. }
  76. #endif
  77. // Compute the composite bounds of this group of shadow primitives.
  78. FBoxSphereBounds OriginalBounds = ShadowGroupPrimitives[0]->Proxy->GetBounds();
  79. if (!ensureMsgf(OriginalBounds.ContainsNaN() == false, TEXT("OriginalBound contains NaN : %s"), *OriginalBounds.ToString()))
  80. {
  81. // fix up OriginalBounds. This is going to cause flickers
  82. OriginalBounds = FBoxSphereBounds(FVector::ZeroVector, FVector(1.f), 1.f);
  83. }
  84. for (int32 ChildIndex = 1; ChildIndex < ShadowGroupPrimitives.Num(); ChildIndex++)
  85. {
  86. const FPrimitiveSceneInfo* ShadowChild = ShadowGroupPrimitives[ChildIndex];
  87. if (ShadowChild->Proxy->CastsDynamicShadow())
  88. {
  89. FBoxSphereBounds ChildBound = ShadowChild->Proxy->GetBounds();
  90. OriginalBounds = OriginalBounds + ChildBound;
  91. if (!ensureMsgf(OriginalBounds.ContainsNaN() == false, TEXT("Child %s contains NaN : %s"), *ShadowChild->Proxy->GetOwnerName().ToString(), *ChildBound.ToString()))
  92. {
  93. // fix up OriginalBounds. This is going to cause flickers
  94. OriginalBounds = FBoxSphereBounds(FVector::ZeroVector, FVector(1.f), 1.f);
  95. }
  96. }
  97. }
  98. FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
  99. // Shadowing constants.
  100. const uint32 MaxShadowResolutionSetting = GetCachedScalabilityCVars().MaxShadowResolution;
  101. const FIntPoint ShadowBufferResolution = SceneContext.GetShadowDepthTextureResolution();
  102. const uint32 MaxShadowResolution = FMath::Min<int32>(MaxShadowResolutionSetting, ShadowBufferResolution.X) - SHADOW_BORDER * 2;
  103. const uint32 MaxShadowResolutionY = FMath::Min<int32>(MaxShadowResolutionSetting, ShadowBufferResolution.Y) - SHADOW_BORDER * 2;
  104. const uint32 MinShadowResolution = FMath::Max<int32>(0, CVarMinShadowResolution.GetValueOnRenderThread());
  105. const uint32 ShadowFadeResolution = FMath::Max<int32>(0, CVarShadowFadeResolution.GetValueOnRenderThread());
  106. const uint32 MinPreShadowResolution = FMath::Max<int32>(0, CVarMinPreShadowResolution.GetValueOnRenderThread());
  107. const uint32 PreShadowFadeResolution = FMath::Max<int32>(0, CVarPreShadowFadeResolution.GetValueOnRenderThread());
  108. // Compute the maximum resolution required for the shadow by any view. Also keep track of the unclamped resolution for fading.
  109. uint32 MaxDesiredResolution = 0;
  110. float MaxScreenPercent = 0;
  111. TArray<float, TInlineAllocator<2> > ResolutionFadeAlphas;
  112. TArray<float, TInlineAllocator<2> > ResolutionPreShadowFadeAlphas;
  113. float MaxResolutionFadeAlpha = 0;
  114. float MaxResolutionPreShadowFadeAlpha = 0;
  115. for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
  116. {
  117. const FViewInfo& View = Views[ViewIndex];
  118. // Determine the size of the subject's bounding sphere in this view.
  119. const FVector ShadowViewOrigin = View.ViewMatrices.GetViewOrigin();
  120. float ShadowViewDistFromBounds = (OriginalBounds.Origin - ShadowViewOrigin).Size();
  121. const float ScreenRadius = View.ShadowViewMatrices.GetScreenScale() *
  122. OriginalBounds.SphereRadius /
  123. FMath::Max(ShadowViewDistFromBounds, 1.0f);
  124. // Early catch for invalid CalculateShadowFadeAlpha()
  125. ensureMsgf(ScreenRadius >= 0.0f, TEXT("View.ShadowViewMatrices.ScreenScale %f, OriginalBounds.SphereRadius %f, ShadowViewDistFromBounds %f"), View.ShadowViewMatrices.GetScreenScale(), OriginalBounds.SphereRadius, ShadowViewDistFromBounds);
  126. const float ScreenPercent = FMath::Max(
  127. 1.0f / 2.0f * View.ShadowViewMatrices.GetProjectionScale().X,
  128. 1.0f / 2.0f * View.ShadowViewMatrices.GetProjectionScale().Y
  129. ) *
  130. OriginalBounds.SphereRadius /
  131. FMath::Max(ShadowViewDistFromBounds, 1.0f);
  132. MaxScreenPercent = FMath::Max(MaxScreenPercent, ScreenPercent);
  133. // Determine the amount of shadow buffer resolution needed for this view.
  134. const float UnclampedResolution = ScreenRadius * CVarShadowTexelsPerPixel.GetValueOnRenderThread();
  135. // Calculate fading based on resolution
  136. // Compute FadeAlpha before ShadowResolutionScale contribution (artists want to modify the softness of the shadow, not change the fade ranges)
  137. const float ViewSpecificAlpha = CalculateShadowFadeAlpha(UnclampedResolution, ShadowFadeResolution, MinShadowResolution) * LightSceneInfo->Proxy->GetShadowAmount();
  138. MaxResolutionFadeAlpha = FMath::Max(MaxResolutionFadeAlpha, ViewSpecificAlpha);
  139. ResolutionFadeAlphas.Add(ViewSpecificAlpha);
  140. const float ViewSpecificPreShadowAlpha = CalculateShadowFadeAlpha(UnclampedResolution * CVarPreShadowResolutionFactor.GetValueOnRenderThread(), PreShadowFadeResolution, MinPreShadowResolution) * LightSceneInfo->Proxy->GetShadowAmount();
  141. MaxResolutionPreShadowFadeAlpha = FMath::Max(MaxResolutionPreShadowFadeAlpha, ViewSpecificPreShadowAlpha);
  142. ResolutionPreShadowFadeAlphas.Add(ViewSpecificPreShadowAlpha);
  143. const float ShadowResolutionScale = LightSceneInfo->Proxy->GetShadowResolutionScale();
  144. float ClampedResolution = UnclampedResolution;
  145. if (ShadowResolutionScale > 1.0f)
  146. {
  147. // Apply ShadowResolutionScale before the MaxShadowResolution clamp if raising the resolution
  148. ClampedResolution *= ShadowResolutionScale;
  149. }
  150. ClampedResolution = FMath::Min<float>(ClampedResolution, MaxShadowResolution);
  151. if (ShadowResolutionScale <= 1.0f)
  152. {
  153. // Apply ShadowResolutionScale after the MaxShadowResolution clamp if lowering the resolution
  154. // Artists want to modify the softness of the shadow with ShadowResolutionScale
  155. ClampedResolution *= ShadowResolutionScale;
  156. }
  157. MaxDesiredResolution = FMath::Max(
  158. MaxDesiredResolution,
  159. FMath::Max<uint32>(
  160. ClampedResolution,
  161. FMath::Min<int32>(MinShadowResolution, ShadowBufferResolution.X - SHADOW_BORDER * 2)
  162. )
  163. );
  164. }
  165. FBoxSphereBounds Bounds = OriginalBounds;
  166. const bool bRenderPreShadow =
  167. CVarAllowPreshadows.GetValueOnRenderThread()
  168. && LightSceneInfo->Proxy->HasStaticShadowing()
  169. // Preshadow only affects the subject's pixels
  170. && bSubjectIsVisible
  171. // Only objects with dynamic lighting should create a preshadow
  172. // Unless we're in the editor and need to preview an object without built lighting
  173. && (!PrimitiveSceneInfo->Proxy->HasStaticLighting() || !Interaction->IsShadowMapped())
  174. // 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
  175. && !(PrimitiveSceneInfo->Proxy->UseSingleSampleShadowFromStationaryLights() && LightSceneInfo->Proxy->GetLightType() == LightType_Directional)
  176. && Scene->GetFeatureLevel() >= ERHIFeatureLevel::SM5;
  177. if (bRenderPreShadow && ShouldUseCachePreshadows())
  178. {
  179. float PreshadowExpandFraction = FMath::Max(CVarPreshadowExpandFraction.GetValueOnRenderThread(), 0.0f);
  180. // 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.
  181. //@todo - only expand the preshadow bounds for this, not the per object shadow.
  182. Bounds.SphereRadius += (Bounds.BoxExtent * PreshadowExpandFraction).Size();
  183. Bounds.BoxExtent *= PreshadowExpandFraction + 1.0f;
  184. }
  185. // Compute the projected shadow initializer for this primitive-light pair.
  186. FPerObjectProjectedShadowInitializer ShadowInitializer;
  187. if ((MaxResolutionFadeAlpha > 1.0f / 256.0f || (bRenderPreShadow && MaxResolutionPreShadowFadeAlpha > 1.0f / 256.0f))
  188. && LightSceneInfo->Proxy->GetPerObjectProjectedShadowInitializer(Bounds, ShadowInitializer))
  189. {
  190. const float MaxFadeAlpha = MaxResolutionFadeAlpha;
  191. // Only create a shadow from this object if it hasn't completely faded away
  192. if (CVarAllowPerObjectShadows.GetValueOnRenderThread() && MaxFadeAlpha > 1.0f / 256.0f)
  193. {
  194. // Round down to the nearest power of two so that resolution changes are always doubling or halving the resolution, which increases filtering stability
  195. // Use the max resolution if the desired resolution is larger than that
  196. const int32 SizeX = MaxDesiredResolution >= MaxShadowResolution ? MaxShadowResolution : (1 << (FMath::CeilLogTwo(MaxDesiredResolution) - 1));
  197. if (bOpaque && bCreateOpaqueObjectShadow && (bOpaqueShadowIsVisibleThisFrame || bShadowIsPotentiallyVisibleNextFrame))
  198. {
  199. // Create a projected shadow for this interaction's shadow.
  200. FProjectedShadowInfo* ProjectedShadowInfo = new(FMemStack::Get(),1,16) FProjectedShadowInfo;
  201. if(ProjectedShadowInfo->SetupPerObjectProjection(
  202. LightSceneInfo,
  203. PrimitiveSceneInfo,
  204. ShadowInitializer,
  205. false, // no preshadow
  206. SizeX,
  207. MaxShadowResolutionY,
  208. SHADOW_BORDER,
  209. MaxScreenPercent,
  210. false)) // no translucent shadow
  211. {
  212. ProjectedShadowInfo->bPerObjectOpaqueShadow = true;
  213. ProjectedShadowInfo->FadeAlphas = ResolutionFadeAlphas;
  214. VisibleLightInfo.MemStackProjectedShadows.Add(ProjectedShadowInfo);
  215. if (bOpaqueShadowIsVisibleThisFrame)
  216. {
  217. VisibleLightInfo.AllProjectedShadows.Add(ProjectedShadowInfo);
  218. for (int32 ChildIndex = 0, ChildCount = ShadowGroupPrimitives.Num(); ChildIndex < ChildCount; ChildIndex++)
  219. {
  220. FPrimitiveSceneInfo* ShadowChild = ShadowGroupPrimitives[ChildIndex];
  221. ProjectedShadowInfo->AddSubjectPrimitive(ShadowChild, &Views, FeatureLevel, false);
  222. }
  223. }
  224. else if (bShadowIsPotentiallyVisibleNextFrame)
  225. {
  226. VisibleLightInfo.OccludedPerObjectShadows.Add(ProjectedShadowInfo);
  227. }
  228. }
  229. }
  230. if (bTranslucentRelevance
  231. && Scene->GetFeatureLevel() >= ERHIFeatureLevel::SM5
  232. && bCreateTranslucentObjectShadow
  233. && (bTranslucentShadowIsVisibleThisFrame || bShadowIsPotentiallyVisibleNextFrame))
  234. {
  235. // Create a projected shadow for this interaction's shadow.
  236. FProjectedShadowInfo* ProjectedShadowInfo = new(FMemStack::Get(),1,16) FProjectedShadowInfo;
  237. if(ProjectedShadowInfo->SetupPerObjectProjection(
  238. LightSceneInfo,
  239. PrimitiveSceneInfo,
  240. ShadowInitializer,
  241. false, // no preshadow
  242. // Size was computed for the full res opaque shadow, convert to downsampled translucent shadow size with proper clamping
  243. FMath::Clamp<int32>(SizeX / SceneContext.GetTranslucentShadowDownsampleFactor(), 1, SceneContext.GetTranslucentShadowDepthTextureResolution().X - SHADOW_BORDER * 2),
  244. FMath::Clamp<int32>(MaxShadowResolutionY / SceneContext.GetTranslucentShadowDownsampleFactor(), 1, SceneContext.GetTranslucentShadowDepthTextureResolution().Y - SHADOW_BORDER * 2),
  245. SHADOW_BORDER,
  246. MaxScreenPercent,
  247. true)) // translucent shadow
  248. {
  249. ProjectedShadowInfo->FadeAlphas = ResolutionFadeAlphas,
  250. VisibleLightInfo.MemStackProjectedShadows.Add(ProjectedShadowInfo);
  251. if (bTranslucentShadowIsVisibleThisFrame)
  252. {
  253. VisibleLightInfo.AllProjectedShadows.Add(ProjectedShadowInfo);
  254. for (int32 ChildIndex = 0, ChildCount = ShadowGroupPrimitives.Num(); ChildIndex < ChildCount; ChildIndex++)
  255. {
  256. FPrimitiveSceneInfo* ShadowChild = ShadowGroupPrimitives[ChildIndex];
  257. ProjectedShadowInfo->AddSubjectPrimitive(ShadowChild, &Views, FeatureLevel, false);
  258. }
  259. }
  260. else if (bShadowIsPotentiallyVisibleNextFrame)
  261. {
  262. VisibleLightInfo.OccludedPerObjectShadows.Add(ProjectedShadowInfo);
  263. }
  264. }
  265. }
  266. }
  267. const float MaxPreFadeAlpha = MaxResolutionPreShadowFadeAlpha;
  268. // If the subject is visible in at least one view, create a preshadow for static primitives shadowing the subject.
  269. if (MaxPreFadeAlpha > 1.0f / 256.0f
  270. && bRenderPreShadow
  271. && bOpaque)
  272. {
  273. // Round down to the nearest power of two so that resolution changes are always doubling or halving the resolution, which increases filtering stability.
  274. int32 PreshadowSizeX = 1 << (FMath::CeilLogTwo(FMath::TruncToInt(MaxDesiredResolution * CVarPreShadowResolutionFactor.GetValueOnRenderThread())) - 1);
  275. const FIntPoint PreshadowCacheResolution = SceneContext.GetPreShadowCacheTextureResolution();
  276. checkSlow(PreshadowSizeX <= PreshadowCacheResolution.X);
  277. bool bIsOutsideWholeSceneShadow = true;
  278. for (int32 i = 0; i < ViewDependentWholeSceneShadows.Num(); i++)
  279. {
  280. const FProjectedShadowInfo* WholeSceneShadow = ViewDependentWholeSceneShadows[i];
  281. const FVector2D DistanceFadeValues = WholeSceneShadow->GetLightSceneInfo().Proxy->GetDirectionalLightDistanceFadeParameters(Scene->GetFeatureLevel(), WholeSceneShadow->GetLightSceneInfo().IsPrecomputedLightingValid(), WholeSceneShadow->DependentView->MaxShadowCascades);
  282. const float DistanceFromShadowCenterSquared = (WholeSceneShadow->ShadowBounds.Center - Bounds.Origin).SizeSquared();
  283. //@todo - if view dependent whole scene shadows are ever supported in splitscreen,
  284. // We can only disable the preshadow at this point if it is inside a whole scene shadow for all views
  285. const float DistanceFromViewSquared = ((FVector)WholeSceneShadow->DependentView->ShadowViewMatrices.GetViewOrigin() - Bounds.Origin).SizeSquared();
  286. // Mark the preshadow as inside the whole scene shadow if its bounding sphere is inside the near fade distance
  287. if (DistanceFromShadowCenterSquared < FMath::Square(FMath::Max(WholeSceneShadow->ShadowBounds.W - Bounds.SphereRadius, 0.0f))
  288. //@todo - why is this extra threshold required?
  289. && DistanceFromViewSquared < FMath::Square(FMath::Max(DistanceFadeValues.X - 200.0f - Bounds.SphereRadius, 0.0f)))
  290. {
  291. bIsOutsideWholeSceneShadow = false;
  292. break;
  293. }
  294. }
  295. // Only create opaque preshadows when part of the caster is outside the whole scene shadow.
  296. if (bIsOutsideWholeSceneShadow)
  297. {
  298. // Try to reuse a preshadow from the cache
  299. TRefCountPtr<FProjectedShadowInfo> ProjectedPreShadowInfo = GetCachedPreshadow(Interaction, ShadowInitializer, OriginalBounds, PreshadowSizeX);
  300. bool bOk = true;
  301. if(!ProjectedPreShadowInfo)
  302. {
  303. // Create a new projected shadow for this interaction's preshadow
  304. // Not using the scene rendering mem stack because this shadow info may need to persist for multiple frames if it gets cached
  305. ProjectedPreShadowInfo = new FProjectedShadowInfo;
  306. bOk = ProjectedPreShadowInfo->SetupPerObjectProjection(
  307. LightSceneInfo,
  308. PrimitiveSceneInfo,
  309. ShadowInitializer,
  310. true, // preshadow
  311. PreshadowSizeX,
  312. FMath::TruncToInt(MaxShadowResolutionY * CVarPreShadowResolutionFactor.GetValueOnRenderThread()),
  313. SHADOW_BORDER,
  314. MaxScreenPercent,
  315. false // not translucent shadow
  316. );
  317. }
  318. if (bOk)
  319. {
  320. // Update fade alpha on the cached preshadow
  321. ProjectedPreShadowInfo->FadeAlphas = ResolutionPreShadowFadeAlphas;
  322. VisibleLightInfo.AllProjectedShadows.Add(ProjectedPreShadowInfo);
  323. VisibleLightInfo.ProjectedPreShadows.Add(ProjectedPreShadowInfo);
  324. // Only add to OutPreShadows if the preshadow doesn't already have depths cached,
  325. // Since OutPreShadows is used to generate information only used when rendering the shadow depths.
  326. if (!ProjectedPreShadowInfo->bDepthsCached && ProjectedPreShadowInfo->CasterFrustum.PermutedPlanes.Num())
  327. {
  328. OutPreShadows.Add(ProjectedPreShadowInfo);
  329. }
  330. for (int32 ChildIndex = 0; ChildIndex < ShadowGroupPrimitives.Num(); ChildIndex++)
  331. {
  332. FPrimitiveSceneInfo* ShadowChild = ShadowGroupPrimitives[ChildIndex];
  333. bool bChildIsVisibleInAnyView = false;
  334. for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
  335. {
  336. const FViewInfo& View = Views[ViewIndex];
  337. if (View.PrimitiveVisibilityMap[ShadowChild->GetIndex()])
  338. {
  339. bChildIsVisibleInAnyView = true;
  340. break;
  341. }
  342. }
  343. if (bChildIsVisibleInAnyView)
  344. {
  345. ProjectedPreShadowInfo->AddReceiverPrimitive(ShadowChild);
  346. }
  347. }
  348. }
  349. }
  350. }
  351. }
  352. }
  1. void FProjectedShadowInfo::AddSubjectPrimitive(FPrimitiveSceneInfo* PrimitiveSceneInfo, TArray<FViewInfo>* ViewArray, ERHIFeatureLevel::Type FeatureLevel, bool bRecordShadowSubjectsForMobileShading)
  2. {
  3. // Ray traced shadows use the GPU managed distance field object buffers, no CPU culling should be used
  4. check(!bRayTracedDistanceField);
  5. if (!ReceiverPrimitives.Contains(PrimitiveSceneInfo)
  6. // Far cascade only casts from primitives marked for it
  7. && (!CascadeSettings.bFarShadowCascade || PrimitiveSceneInfo->Proxy->CastsFarShadow()))
  8. {
  9. const FPrimitiveSceneProxy* Proxy = PrimitiveSceneInfo->Proxy;
  10. TArray<FViewInfo*, TInlineAllocator<1> > Views;
  11. const bool bWholeSceneDirectionalShadow = IsWholeSceneDirectionalShadow();
  12. if (bWholeSceneDirectionalShadow)
  13. {
  14. Views.Add(DependentView);
  15. }
  16. else
  17. {
  18. checkf(ViewArray,
  19. TEXT("bWholeSceneShadow=%d, CascadeSettings.ShadowSplitIndex=%d, bDirectionalLight=%s"),
  20. bWholeSceneShadow ? TEXT("true") : TEXT("false"),
  21. CascadeSettings.ShadowSplitIndex,
  22. bDirectionalLight ? TEXT("true") : TEXT("false"));
  23. for (int32 ViewIndex = 0; ViewIndex < ViewArray->Num(); ViewIndex++)
  24. {
  25. Views.Add(&(*ViewArray)[ViewIndex]);
  26. }
  27. }
  28. bool bOpaque = false;
  29. bool bTranslucentRelevance = false;
  30. bool bShadowRelevance = false;
  31. uint32 ViewMask = 0;
  32. int32 PrimitiveId = PrimitiveSceneInfo->GetIndex();
  33. for (int32 ViewIndex = 0, Num = Views.Num(); ViewIndex < Num; ViewIndex++)
  34. {
  35. FViewInfo& CurrentView = *Views[ViewIndex];
  36. FPrimitiveViewRelevance& ViewRelevance = CurrentView.PrimitiveViewRelevanceMap[PrimitiveId];
  37. if (!ViewRelevance.bInitializedThisFrame)
  38. {
  39. if( CurrentView.IsPerspectiveProjection() )
  40. {
  41. // Compute the distance between the view and the primitive.
  42. float DistanceSquared = (Proxy->GetBounds().Origin - CurrentView.ShadowViewMatrices.GetViewOrigin()).SizeSquared();
  43. bool bIsDistanceCulled = CurrentView.IsDistanceCulled(
  44. DistanceSquared,
  45. Proxy->GetMinDrawDistance(),
  46. Proxy->GetMaxDrawDistance(),
  47. PrimitiveSceneInfo
  48. );
  49. if( bIsDistanceCulled )
  50. {
  51. continue;
  52. }
  53. }
  54. // Respect HLOD visibility which can hide child LOD primitives
  55. if (CurrentView.ViewState &&
  56. CurrentView.ViewState->HLODVisibilityState.IsValidPrimitiveIndex(PrimitiveId) &&
  57. CurrentView.ViewState->HLODVisibilityState.IsNodeForcedHidden(PrimitiveId))
  58. {
  59. continue;
  60. }
  61. if ((CurrentView.ShowOnlyPrimitives.IsSet() &&
  62. !CurrentView.ShowOnlyPrimitives->Contains(PrimitiveSceneInfo->Proxy->GetPrimitiveComponentId())) ||
  63. CurrentView.HiddenPrimitives.Contains(PrimitiveSceneInfo->Proxy->GetPrimitiveComponentId()))
  64. {
  65. continue;
  66. }
  67. // Compute the subject primitive's view relevance since it wasn't cached
  68. // Update the main view's PrimitiveViewRelevanceMap
  69. ViewRelevance = PrimitiveSceneInfo->Proxy->GetViewRelevance(&CurrentView);
  70. ViewMask |= (1 << ViewIndex);
  71. }
  72. bOpaque |= ViewRelevance.bOpaque || ViewRelevance.bMasked;
  73. bTranslucentRelevance |= ViewRelevance.HasTranslucency() && !ViewRelevance.bMasked;
  74. bShadowRelevance |= ViewRelevance.bShadowRelevance;
  75. }
  76. if (bShadowRelevance)
  77. {
  78. // Update the primitive component's last render time. Allows the component to update when using bCastWhenHidden.
  79. const float CurrentWorldTime = Views[0]->Family->CurrentWorldTime;
  80. PrimitiveSceneInfo->UpdateComponentLastRenderTime(CurrentWorldTime, /*bUpdateLastRenderTimeOnScreen=*/false);
  81. if (PrimitiveSceneInfo->NeedsUniformBufferUpdate())
  82. {
  83. for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
  84. {
  85. // Main view visible primitives are processed on parallel tasks, updating uniform buffer them here will cause a race condition.
  86. check(!Views[ViewIndex]->PrimitiveVisibilityMap[PrimitiveSceneInfo->GetIndex()]);
  87. }
  88. PrimitiveSceneInfo->ConditionalUpdateUniformBuffer(FRHICommandListExecutor::GetImmediateCommandList());
  89. }
  90. if (PrimitiveSceneInfo->NeedsUpdateStaticMeshes())
  91. {
  92. // Need to defer to next InitViews, as main view visible primitives are processed on parallel tasks and calling
  93. // CacheMeshDrawCommands may resize CachedDrawLists/CachedMeshDrawCommandStateBuckets causing a crash.
  94. PrimitiveSceneInfo->BeginDeferredUpdateStaticMeshesWithoutVisibilityCheck();
  95. }
  96. }
  97. if (bOpaque && bShadowRelevance)
  98. {
  99. const FBoxSphereBounds& Bounds = Proxy->GetBounds();
  100. bool bDrawingStaticMeshes = false;
  101. if (PrimitiveSceneInfo->StaticMeshes.Num() > 0)
  102. {
  103. for (int32 ViewIndex = 0, ViewCount = Views.Num(); ViewIndex < ViewCount; ViewIndex++)
  104. {
  105. FViewInfo& CurrentView = *Views[ViewIndex];
  106. const float DistanceSquared = ( Bounds.Origin - CurrentView.ShadowViewMatrices.GetViewOrigin() ).SizeSquared();
  107. if (bWholeSceneShadow)
  108. {
  109. const float LODScaleSquared = FMath::Square(CurrentView.LODDistanceFactor);
  110. const bool bDrawShadowDepth = FMath::Square(Bounds.SphereRadius) > FMath::Square(GMinScreenRadiusForShadowCaster) * DistanceSquared * LODScaleSquared;
  111. if( !bDrawShadowDepth )
  112. {
  113. // cull object if it's too small to be considered as shadow caster
  114. continue;
  115. }
  116. }
  117. // Update visibility for meshes which weren't visible in the main views or were visible with static relevance
  118. if (!CurrentView.PrimitiveVisibilityMap[PrimitiveId] || CurrentView.PrimitiveViewRelevanceMap[PrimitiveId].bStaticRelevance)
  119. {
  120. bDrawingStaticMeshes |= ShouldDrawStaticMeshes(CurrentView, PrimitiveSceneInfo);
  121. }
  122. }
  123. }
  124. if (bDrawingStaticMeshes)
  125. {
  126. if (bRecordShadowSubjectsForMobileShading)
  127. {
  128. DependentView->VisibleLightInfos[GetLightSceneInfo().Id].MobileCSMSubjectPrimitives.AddSubjectPrimitive(PrimitiveSceneInfo, PrimitiveId);
  129. }
  130. }
  131. else
  132. {
  133. // Add the primitive to the subject primitive list.
  134. DynamicSubjectPrimitives.Add(PrimitiveSceneInfo);
  135. if (bRecordShadowSubjectsForMobileShading)
  136. {
  137. DependentView->VisibleLightInfos[GetLightSceneInfo().Id].MobileCSMSubjectPrimitives.AddSubjectPrimitive(PrimitiveSceneInfo, PrimitiveId);
  138. }
  139. }
  140. }
  141. // Add translucent shadow casting primitives to SubjectTranslucentPrimitives
  142. if (bTranslucentRelevance && bShadowRelevance)
  143. {
  144. SubjectTranslucentPrimitives.Add(PrimitiveSceneInfo);
  145. }
  146. }
  147. }
  1. bool FProjectedShadowInfo::SetupPerObjectProjection(
  2. FLightSceneInfo* InLightSceneInfo,
  3. const FPrimitiveSceneInfo* InParentSceneInfo,
  4. const FPerObjectProjectedShadowInitializer& Initializer,
  5. bool bInPreShadow,
  6. uint32 InResolutionX,
  7. uint32 MaxShadowResolutionY,
  8. uint32 InBorderSize,
  9. float InMaxScreenPercent,
  10. bool bInTranslucentShadow)
  11. {
  12. check(InParentSceneInfo);
  13. LightSceneInfo = InLightSceneInfo;
  14. LightSceneInfoCompact = InLightSceneInfo;
  15. ParentSceneInfo = InParentSceneInfo;
  16. PreShadowTranslation = Initializer.PreShadowTranslation;
  17. ShadowBounds = FSphere(Initializer.SubjectBounds.Origin - Initializer.PreShadowTranslation, Initializer.SubjectBounds.SphereRadius);
  18. ResolutionX = InResolutionX;
  19. BorderSize = InBorderSize;
  20. MaxScreenPercent = InMaxScreenPercent;
  21. bDirectionalLight = InLightSceneInfo->Proxy->GetLightType() == LightType_Directional;
  22. const ERHIFeatureLevel::Type FeatureLevel = LightSceneInfo->Scene->GetFeatureLevel();
  23. bCapsuleShadow = InParentSceneInfo->Proxy->CastsCapsuleDirectShadow() && !bInPreShadow && SupportsCapsuleDirectShadows(FeatureLevel, GShaderPlatformForFeatureLevel[FeatureLevel]);
  24. bTranslucentShadow = bInTranslucentShadow;
  25. bPreShadow = bInPreShadow;
  26. bSelfShadowOnly = InParentSceneInfo->Proxy->CastsSelfShadowOnly();
  27. bTransmission = InLightSceneInfo->Proxy->Transmission();
  28. bHairStrandsDeepShadow = InLightSceneInfo->Proxy->CastsHairStrandsDeepShadow();
  29. check(!bRayTracedDistanceField);
  30. const FMatrix WorldToLightScaled = Initializer.WorldToLight * FScaleMatrix(Initializer.Scales);
  31. // Create an array of the extreme vertices of the subject's bounds.
  32. FBoundingBoxVertexArray BoundsPoints;
  33. FBoundingBoxEdgeArray BoundsEdges;
  34. GetBoundingBoxVertices(Initializer.SubjectBounds.GetBox(),BoundsPoints,BoundsEdges);
  35. // Project the bounding box vertices.
  36. FBoundingBoxVertexArray ProjectedBoundsPoints;
  37. for (int32 PointIndex = 0; PointIndex < BoundsPoints.Num(); PointIndex++)
  38. {
  39. const FVector TransformedBoundsPoint = WorldToLightScaled.TransformPosition(BoundsPoints[PointIndex]);
  40. const float TransformedBoundsPointW = Dot4(FVector4(0, 0, TransformedBoundsPoint | Initializer.FaceDirection,1), Initializer.WAxis);
  41. if (TransformedBoundsPointW >= DELTA)
  42. {
  43. ProjectedBoundsPoints.Add(TransformedBoundsPoint / TransformedBoundsPointW);
  44. }
  45. else
  46. {
  47. //ProjectedBoundsPoints.Add(FVector(FLT_MAX, FLT_MAX, FLT_MAX));
  48. return false;
  49. }
  50. }
  51. // Compute the transform from light-space to shadow-space.
  52. FMatrix LightToShadow;
  53. float AspectRatio;
  54. // if this is a valid transform (can be false if the object is around the light)
  55. bool bRet = false;
  56. if (GetBestShadowTransform(Initializer.FaceDirection.GetSafeNormal(), ProjectedBoundsPoints, BoundsEdges, AspectRatio, LightToShadow))
  57. {
  58. bRet = true;
  59. const FMatrix WorldToShadow = WorldToLightScaled * LightToShadow;
  60. const FBox ShadowSubjectBounds = Initializer.SubjectBounds.GetBox().TransformBy(WorldToShadow);
  61. MinSubjectZ = FMath::Max(Initializer.MinLightW, ShadowSubjectBounds.Min.Z);
  62. float MaxReceiverZ = FMath::Min(MinSubjectZ + Initializer.MaxDistanceToCastInLightW, (float)HALF_WORLD_MAX);
  63. // Max can end up smaller than min due to the clamp to HALF_WORLD_MAX above
  64. MaxReceiverZ = FMath::Max(MaxReceiverZ, MinSubjectZ + 1);
  65. MaxSubjectZ = FMath::Max(ShadowSubjectBounds.Max.Z, MinSubjectZ + 1);
  66. const FMatrix SubjectMatrix = WorldToShadow * FShadowProjectionMatrix(MinSubjectZ, MaxSubjectZ, Initializer.WAxis);
  67. const float MaxSubjectAndReceiverDepth = Initializer.SubjectBounds.GetBox().TransformBy(SubjectMatrix).Max.Z;
  68. float MaxSubjectDepth;
  69. if (bPreShadow)
  70. {
  71. const FMatrix PreSubjectMatrix = WorldToShadow * FShadowProjectionMatrix(Initializer.MinLightW, MaxSubjectZ, Initializer.WAxis);
  72. // Preshadow frustum bounds go from the light to the furthest extent of the object in light space
  73. SubjectAndReceiverMatrix = PreSubjectMatrix;
  74. ReceiverMatrix = SubjectMatrix;
  75. MaxSubjectDepth = bDirectionalLight ? MaxSubjectAndReceiverDepth : Initializer.SubjectBounds.GetBox().TransformBy(PreSubjectMatrix).Max.Z;
  76. }
  77. else
  78. {
  79. const FMatrix PostSubjectMatrix = WorldToShadow * FShadowProjectionMatrix(MinSubjectZ, MaxReceiverZ, Initializer.WAxis);
  80. SubjectAndReceiverMatrix = SubjectMatrix;
  81. ReceiverMatrix = PostSubjectMatrix;
  82. MaxSubjectDepth = MaxSubjectAndReceiverDepth;
  83. if (bDirectionalLight)
  84. {
  85. // No room to fade out if the end of receiver range is inside the subject range, it will just clip.
  86. if (MaxSubjectZ < MaxReceiverZ)
  87. {
  88. float ShadowSubjectRange = MaxSubjectZ - MinSubjectZ;
  89. float FadeLength = FMath::Min(ShadowSubjectRange, MaxReceiverZ - MaxSubjectZ);
  90. //Initializer.MaxDistanceToCastInLightW / 16.0f;
  91. PerObjectShadowFadeStart = (MaxReceiverZ - MinSubjectZ - FadeLength) / ShadowSubjectRange;
  92. InvPerObjectShadowFadeLength = ShadowSubjectRange / FMath::Max(0.000001f, FadeLength);
  93. }
  94. }
  95. }
  96. InvMaxSubjectDepth = 1.0f / MaxSubjectDepth;
  97. MinPreSubjectZ = Initializer.MinLightW;
  98. ResolutionY = FMath::Clamp<uint32>(FMath::TruncToInt(InResolutionX / AspectRatio), 1, MaxShadowResolutionY);
  99. if (ResolutionX == 0 || ResolutionY == 0)
  100. {
  101. bRet = false;
  102. }
  103. else
  104. {
  105. // Store the view matrix
  106. // 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
  107. ShadowViewMatrix = Initializer.WorldToLight *
  108. FMatrix(
  109. FPlane(0, 0, 1, 0),
  110. FPlane(1, 0, 0, 0),
  111. FPlane(0, 1, 0, 0),
  112. FPlane(0, 0, 0, 1));
  113. GetViewFrustumBounds(CasterFrustum, SubjectAndReceiverMatrix, true);
  114. InvReceiverMatrix = ReceiverMatrix.InverseFast();
  115. GetViewFrustumBounds(ReceiverFrustum, ReceiverMatrix, true);
  116. UpdateShaderDepthBias();
  117. }
  118. }
  119. return bRet;
  120. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/91460
推荐阅读
相关标签
  

闽ICP备14008679号