FShadowMap2D* FShadowMap2D::AllocateInstancedShadowMap(UInstancedStaticMeshComponent* Component, TArray<TMap<ULightComponent*, TUniquePtr<FShadowMapData2D>>> InstancedShadowMapData, const FBoxSphereBounds& Bounds, ELightMapPaddingType InPaddingType, EShadowMapFlags InShadowmapFlags) { #if WITH_EDITOR check(InstancedShadowMapData.Num() > 0); // Verify all instance shadowmaps are the same size, and build complete list of shadow lights int32 SizeX = -1; int32 SizeY = -1; TSet<ULightComponent*> AllLights; for (auto& ShadowMapData : InstancedShadowMapData) { for (const auto& ShadowDataPair : ShadowMapData) { if (SizeX == -1) { SizeX = ShadowDataPair.Value->GetSizeX(); SizeY = ShadowDataPair.Value->GetSizeY(); } else { check(ShadowDataPair.Value->GetSizeX() == SizeX); check(ShadowDataPair.Value->GetSizeY() == SizeY); } AllLights.Add(ShadowDataPair.Key); } } check(SizeX != -1 && SizeY != -1); // No valid shadowmaps TArray<FGuid> LightGuids; LightGuids.Reserve(AllLights.Num()); for (ULightComponent* Light : AllLights) { LightGuids.Add(Light->LightGuid); } // Unify all the shadow map data to contain the same lights in the same order for (auto& ShadowMapData : InstancedShadowMapData) { for (ULightComponent* Light : AllLights) { if (!ShadowMapData.Contains(Light)) { ShadowMapData.Add(Light, MakeUnique<FQuantizedShadowSignedDistanceFieldData2D>(SizeX, SizeY)); } } } FShadowMapAllocationGroup AllocationGroup; AllocationGroup.TextureOuter = Component->GetOutermost(); AllocationGroup.ShadowmapFlags = InShadowmapFlags; AllocationGroup.Bounds = Bounds; if (!GAllowStreamingLightmaps) { AllocationGroup.ShadowmapFlags = EShadowMapFlags(AllocationGroup.ShadowmapFlags & ~SMF_Streamed); } FShadowMap2D* BaseShadowmap = nullptr; for (int32 InstanceIndex = 0; InstanceIndex < InstancedShadowMapData.Num(); ++InstanceIndex) { auto& ShadowMapData = InstancedShadowMapData[InstanceIndex]; check(ShadowMapData.Num() > 0); // Create a new shadow-map. FShadowMap2D* ShadowMap = new FShadowMap2D(LightGuids); if (InstanceIndex == 0) { BaseShadowmap = ShadowMap; } // Add a pending allocation for this shadow-map. TUniquePtr<FShadowMapAllocation> Allocation = MakeUnique<FShadowMapAllocation>(); Allocation->PaddingType = InPaddingType; Allocation->ShadowMap = ShadowMap; Allocation->TotalSizeX = SizeX; Allocation->TotalSizeY = SizeY; Allocation->MappedRect = FIntRect(0, 0, SizeX, SizeY); Allocation->Primitive = Component; Allocation->InstanceIndex = InstanceIndex; for (auto& ShadowDataPair : ShadowMapData) { auto& RawData = ShadowDataPair.Value; auto& DistanceFieldShadowData = Allocation->ShadowMapData.Add(ShadowDataPair.Key, TArray<FQuantizedSignedDistanceFieldShadowSample>()); switch (RawData->GetType()) { case FShadowMapData2D::SHADOW_SIGNED_DISTANCE_FIELD_DATA: case FShadowMapData2D::SHADOW_SIGNED_DISTANCE_FIELD_DATA_QUANTIZED: // If the data is already quantized, this will just copy the data RawData->Quantize(DistanceFieldShadowData); break; default: check(0); } RawData.Reset(); // Track the size of pending light-maps. PendingShadowMapSize += Allocation->TotalSizeX * Allocation->TotalSizeY; } // Assumes bAlignByFour AllocationGroup.TotalTexels += ((Allocation->MappedRect.Width() + 3) & ~3) * ((Allocation->MappedRect.Height() + 3) & ~3); AllocationGroup.Allocations.Add(MoveTemp(Allocation)); } PendingShadowMaps.Add(MoveTemp(AllocationGroup)); return BaseShadowmap; #else return nullptr; #endif }
FShadowMap2D* FShadowMap2D::AllocateShadowMap( UObject* Outer, const TMap<ULightComponent*,FShadowMapData2D*>& ShadowMapData, const FBoxSphereBounds& Bounds, ELightMapPaddingType InPaddingType, EShadowMapFlags InShadowmapFlags) { #if WITH_EDITOR check(ShadowMapData.Num() > 0); // Create a new shadow-map. FShadowMap2D* ShadowMap = new FShadowMap2D(ShadowMapData); int32 SizeX = -1; int32 SizeY = -1; int32 LightIndex = 0; for (TMap<ULightComponent*, FShadowMapData2D*>::TConstIterator It(ShadowMapData); It; ++It) { if (LightIndex == 0) { SizeX = It.Value()->GetSizeX(); SizeY = It.Value()->GetSizeY(); } else { check(SizeX == It.Value()->GetSizeX() && SizeY == It.Value()->GetSizeY()); } LightIndex++; } check(SizeX != -1 && SizeY != -1); // Add a pending allocation for this shadow-map. FShadowMapAllocation* Allocation = new(PendingShadowMaps) FShadowMapAllocation; Allocation->ShadowMap = ShadowMap; Allocation->TextureOuter = Outer->GetOutermost(); Allocation->TotalSizeX = SizeX; Allocation->TotalSizeY = SizeY; Allocation->MappedRect = FIntRect( 0, 0, SizeX, SizeY ); Allocation->PaddingType = InPaddingType; Allocation->Bounds = Bounds; Allocation->ShadowmapFlags = InShadowmapFlags; if ( !GAllowStreamingLightmaps ) { Allocation->ShadowmapFlags = EShadowMapFlags( Allocation->ShadowmapFlags & ~SMF_Streamed ); } for (TMap<ULightComponent*, FShadowMapData2D*>::TConstIterator It(ShadowMapData); It; ++It) { const FShadowMapData2D* RawData = It.Value(); TArray<FQuantizedSignedDistanceFieldShadowSample>& DistanceFieldShadowData = Allocation->ShadowMapData.Add(It.Key(), TArray<FQuantizedSignedDistanceFieldShadowSample>()); switch (RawData->GetType()) { case FShadowMapData2D::SHADOW_SIGNED_DISTANCE_FIELD_DATA: case FShadowMapData2D::SHADOW_SIGNED_DISTANCE_FIELD_DATA_QUANTIZED: // If the data is already quantized, this will just copy the data RawData->Quantize(DistanceFieldShadowData); break; default: check(0); } delete RawData; // Track the size of pending light-maps. PendingShadowMapSize += Allocation->TotalSizeX * Allocation->TotalSizeY; } return ShadowMap; #else return NULL; #endif }
FShadowMap2D* FShadowMap2D::AllocateShadowMap( UObject* Outer, const TMap<ULightComponent*,FShadowMapData2D*>& ShadowMapData, const FBoxSphereBounds& Bounds, ELightMapPaddingType InPaddingType, EShadowMapFlags InShadowmapFlags) { #if WITH_EDITOR check(ShadowMapData.Num() > 0); FShadowMapAllocationGroup AllocationGroup; AllocationGroup.TextureOuter = Outer->GetOutermost(); AllocationGroup.ShadowmapFlags = InShadowmapFlags; AllocationGroup.Bounds = Bounds; if (!GAllowStreamingLightmaps) { AllocationGroup.ShadowmapFlags = EShadowMapFlags(AllocationGroup.ShadowmapFlags & ~SMF_Streamed); } // Create a new shadow-map. FShadowMap2D* ShadowMap = new FShadowMap2D(ShadowMapData); // Calculate Shadowmap size int32 SizeX = -1; int32 SizeY = -1; int32 LightIndex = 0; for (const auto& ShadowDataPair : ShadowMapData) { if (LightIndex == 0) { SizeX = ShadowDataPair.Value->GetSizeX(); SizeY = ShadowDataPair.Value->GetSizeY(); } else { check(SizeX == ShadowDataPair.Value->GetSizeX() && SizeY == ShadowDataPair.Value->GetSizeY()); } LightIndex++; } check(SizeX != -1 && SizeY != -1); // Add a pending allocation for this shadow-map. TUniquePtr<FShadowMapAllocation> Allocation = MakeUnique<FShadowMapAllocation>(); Allocation->PaddingType = InPaddingType; Allocation->ShadowMap = ShadowMap; Allocation->TotalSizeX = SizeX; Allocation->TotalSizeY = SizeY; Allocation->MappedRect = FIntRect(0, 0, SizeX, SizeY); Allocation->PaddingType = InPaddingType; for (const auto& ShadowDataPair : ShadowMapData) { const FShadowMapData2D* RawData = ShadowDataPair.Value; TArray<FQuantizedSignedDistanceFieldShadowSample>& DistanceFieldShadowData = Allocation->ShadowMapData.Add(ShadowDataPair.Key, TArray<FQuantizedSignedDistanceFieldShadowSample>()); switch (RawData->GetType()) { case FShadowMapData2D::SHADOW_SIGNED_DISTANCE_FIELD_DATA: case FShadowMapData2D::SHADOW_SIGNED_DISTANCE_FIELD_DATA_QUANTIZED: // If the data is already quantized, this will just copy the data RawData->Quantize(DistanceFieldShadowData); break; default: check(0); } delete RawData; // Track the size of pending light-maps. PendingShadowMapSize += Allocation->TotalSizeX * Allocation->TotalSizeY; } // Assumes bAlignByFour AllocationGroup.TotalTexels += ((Allocation->MappedRect.Width() + 3) & ~3) * ((Allocation->MappedRect.Height() + 3) & ~3); AllocationGroup.Allocations.Add(MoveTemp(Allocation)); PendingShadowMaps.Add(MoveTemp(AllocationGroup)); return ShadowMap; #else return nullptr; #endif }