/** * Executes all pending shadow-map encoding requests. * @param InWorld World in which the textures exist * @param bLightingSuccessful Whether the lighting build was successful or not. */ void FShadowMap2D::EncodeTextures(UWorld* InWorld , bool bLightingSuccessful ) { if ( bLightingSuccessful ) { GWarn->BeginSlowTask( NSLOCTEXT("ShadowMap2D", "BeginEncodingShadowMapsTask", "Encoding shadow-maps"), false ); const int32 PackedLightAndShadowMapTextureSize = InWorld->GetWorldSettings()->PackedLightAndShadowMapTextureSize; // Reset the pending shadow-map size. PendingShadowMapSize = 0; Sort(PendingShadowMaps.GetData(), PendingShadowMaps.Num(), FCompareShadowMaps()); // Allocate texture space for each light-map. TIndirectArray<FShadowMapPendingTexture> PendingTextures; for(int32 ShadowMapIndex = 0;ShadowMapIndex < PendingShadowMaps.Num();ShadowMapIndex++) { FShadowMapAllocation& Allocation = PendingShadowMaps[ShadowMapIndex]; // Find an existing texture which the light-map can be stored in. FShadowMapPendingTexture* Texture = NULL; for(int32 TextureIndex = 0;TextureIndex < PendingTextures.Num();TextureIndex++) { FShadowMapPendingTexture& ExistingTexture = PendingTextures[TextureIndex]; // See if the new one will fit in the existing texture if ( ExistingTexture.AddElement( Allocation ) ) { Texture = &ExistingTexture; break; } } // If there is no appropriate texture, create a new one. if(!Texture) { int32 NewTextureSizeX = PackedLightAndShadowMapTextureSize; int32 NewTextureSizeY = PackedLightAndShadowMapTextureSize; if(Allocation.MappedRect.Width() > NewTextureSizeX || Allocation.MappedRect.Height() > NewTextureSizeY) { NewTextureSizeX = FMath::RoundUpToPowerOfTwo(Allocation.MappedRect.Width()); NewTextureSizeY = FMath::RoundUpToPowerOfTwo(Allocation.MappedRect.Height()); } // If there is no existing appropriate texture, create a new one. Texture = ::new(PendingTextures) FShadowMapPendingTexture(NewTextureSizeX,NewTextureSizeY); Texture->Outer = Allocation.TextureOuter; Texture->Bounds = Allocation.Bounds; Texture->ShadowmapFlags = Allocation.ShadowmapFlags; verify( Texture->AddElement( Allocation, true ) ); } } for(int32 TextureIndex = 0;TextureIndex < PendingTextures.Num();TextureIndex++) { if (bUpdateStatus && (TextureIndex % 20) == 0) { GWarn->UpdateProgress(TextureIndex, PendingTextures.Num()); } FShadowMapPendingTexture& PendingTexture = PendingTextures[TextureIndex]; PendingTexture.StartEncoding(InWorld); } PendingTextures.Empty(); PendingShadowMaps.Empty(); GWarn->EndSlowTask(); } else { PendingShadowMaps.Empty(); } }
/** * Executes all pending shadow-map encoding requests. * @param InWorld World in which the textures exist * @param bLightingSuccessful Whether the lighting build was successful or not. */ void FShadowMap2D::EncodeTextures(UWorld* InWorld , bool bLightingSuccessful) { if ( bLightingSuccessful ) { GWarn->BeginSlowTask( NSLOCTEXT("ShadowMap2D", "BeginEncodingShadowMapsTask", "Encoding shadow-maps"), false ); const int32 PackedLightAndShadowMapTextureSize = InWorld->GetWorldSettings()->PackedLightAndShadowMapTextureSize; // Reset the pending shadow-map size. PendingShadowMapSize = 0; Sort(PendingShadowMaps.GetData(), PendingShadowMaps.Num(), FCompareShadowMaps()); // Allocate texture space for each shadow-map. TIndirectArray<FShadowMapPendingTexture> PendingTextures; for (FShadowMapAllocationGroup& PendingGroup : PendingShadowMaps) { if (!ensure(PendingGroup.Allocations.Num() >= 1)) { continue; } int32 MaxWidth = 0; int32 MaxHeight = 0; for (auto& Allocation : PendingGroup.Allocations) { MaxWidth = FMath::Max(MaxWidth, Allocation->MappedRect.Width()); MaxHeight = FMath::Max(MaxHeight, Allocation->MappedRect.Height()); } FShadowMapPendingTexture* Texture = nullptr; // Find an existing texture which the shadow-map can be stored in. // Shadowmaps will always be 4-pixel aligned... for (FShadowMapPendingTexture& ExistingTexture : PendingTextures) { if (ExistingTexture.AddElement(PendingGroup)) { Texture = &ExistingTexture; break; } } if (!Texture) { int32 NewTextureSizeX = PackedLightAndShadowMapTextureSize; int32 NewTextureSizeY = PackedLightAndShadowMapTextureSize; // Assumes identically-sized allocations, fit into the smallest square const int32 AllocationCountX = FMath::CeilToInt(FMath::Sqrt(FMath::DivideAndRoundUp(PendingGroup.Allocations.Num() * MaxHeight, MaxWidth))); const int32 AllocationCountY = FMath::DivideAndRoundUp(PendingGroup.Allocations.Num(), AllocationCountX); const int32 AllocationSizeX = AllocationCountX * MaxWidth; const int32 AllocationSizeY = AllocationCountY * MaxHeight; if (AllocationSizeX > NewTextureSizeX || AllocationSizeY > NewTextureSizeY) { NewTextureSizeX = FMath::RoundUpToPowerOfTwo(AllocationSizeX); NewTextureSizeY = FMath::RoundUpToPowerOfTwo(AllocationSizeY); } // If there is no existing appropriate texture, create a new one. Texture = new FShadowMapPendingTexture(NewTextureSizeX, NewTextureSizeY); PendingTextures.Add(Texture); Texture->Outer = PendingGroup.TextureOuter; Texture->Bounds = PendingGroup.Bounds; Texture->ShadowmapFlags = PendingGroup.ShadowmapFlags; verify(Texture->AddElement(PendingGroup)); } // Give the texture ownership of the allocations for (auto& Allocation : PendingGroup.Allocations) { Texture->Allocations.Add(Allocation.Release()); } } PendingShadowMaps.Empty(); // Encode all the pending textures. for (int32 TextureIndex = 0; TextureIndex < PendingTextures.Num(); TextureIndex++) { if (bUpdateStatus && (TextureIndex % 20) == 0) { GWarn->UpdateProgress(TextureIndex, PendingTextures.Num()); } FShadowMapPendingTexture& PendingTexture = PendingTextures[TextureIndex]; PendingTexture.StartEncoding(InWorld); } PendingTextures.Empty(); GWarn->EndSlowTask(); } else { PendingShadowMaps.Empty(); } }