void FIndirectLightingCache::UpdateBlock(FScene* Scene, FViewInfo* DebugDrawingView, FBlockUpdateInfo& BlockInfo) { const int32 NumSamplesPerBlock = BlockInfo.Block.TexelSize * BlockInfo.Block.TexelSize * BlockInfo.Block.TexelSize; FSHVectorRGB3 SingleSample; float DirectionalShadowing = 1; FVector SkyBentNormal(0, 0, 1); //always do point interpolation to get valid 3band single sample and directional data. InterpolatePoint(Scene, BlockInfo.Block, DirectionalShadowing, SingleSample, SkyBentNormal); if (CanIndirectLightingCacheUseVolumeTexture(GetFeatureLevel()) && !BlockInfo.Allocation->bPointSample) { static TArray<float> AccumulatedWeight; AccumulatedWeight.Reset(NumSamplesPerBlock); AccumulatedWeight.AddZeroed(NumSamplesPerBlock); //volume textures are encoded as two band, so no reason to waste perf interpolating 3 bands. static TArray<FSHVectorRGB2> AccumulatedIncidentRadiance; AccumulatedIncidentRadiance.Reset(NumSamplesPerBlock); AccumulatedIncidentRadiance.AddZeroed(NumSamplesPerBlock); // Interpolate SH samples from precomputed lighting samples and accumulate lighting data for an entire block InterpolateBlock(Scene, BlockInfo.Block, AccumulatedWeight, AccumulatedIncidentRadiance); static TArray<FFloat16Color> Texture0Data; static TArray<FFloat16Color> Texture1Data; static TArray<FFloat16Color> Texture2Data; Texture0Data.Reset(NumSamplesPerBlock); Texture1Data.Reset(NumSamplesPerBlock); Texture2Data.Reset(NumSamplesPerBlock); Texture0Data.AddUninitialized(NumSamplesPerBlock); Texture1Data.AddUninitialized(NumSamplesPerBlock); Texture2Data.AddUninitialized(NumSamplesPerBlock); const int32 FormatSize = GPixelFormats[PF_FloatRGBA].BlockBytes; check(FormatSize == sizeof(FFloat16Color)); // Encode the SH samples into a texture format // Note the single sample is updated even if this is a volume allocation, because translucent materials only use the single sample EncodeBlock(DebugDrawingView, BlockInfo.Block, AccumulatedWeight, AccumulatedIncidentRadiance, Texture0Data, Texture1Data, Texture2Data); // Setup an update region const FUpdateTextureRegion3D UpdateRegion( BlockInfo.Block.MinTexel.X, BlockInfo.Block.MinTexel.Y, BlockInfo.Block.MinTexel.Z, 0, 0, 0, BlockInfo.Block.TexelSize, BlockInfo.Block.TexelSize, BlockInfo.Block.TexelSize); // Update the volume texture atlas RHIUpdateTexture3D((const FTexture3DRHIRef&)GetTexture0().ShaderResourceTexture, 0, UpdateRegion, BlockInfo.Block.TexelSize * FormatSize, BlockInfo.Block.TexelSize * BlockInfo.Block.TexelSize * FormatSize, (const uint8*)Texture0Data.GetData()); RHIUpdateTexture3D((const FTexture3DRHIRef&)GetTexture1().ShaderResourceTexture, 0, UpdateRegion, BlockInfo.Block.TexelSize * FormatSize, BlockInfo.Block.TexelSize * BlockInfo.Block.TexelSize * FormatSize, (const uint8*)Texture1Data.GetData()); RHIUpdateTexture3D((const FTexture3DRHIRef&)GetTexture2().ShaderResourceTexture, 0, UpdateRegion, BlockInfo.Block.TexelSize * FormatSize, BlockInfo.Block.TexelSize * BlockInfo.Block.TexelSize * FormatSize, (const uint8*)Texture2Data.GetData()); } else { if (GCacheDrawInterpolationPoints != 0 && DebugDrawingView) { FViewElementPDI DebugPDI(DebugDrawingView, NULL); const FVector WorldPosition = BlockInfo.Block.Min; DebugPDI.DrawPoint(WorldPosition, FLinearColor(0, 0, 1), 10, SDPG_World); } } // Record the position that the sample was taken at BlockInfo.Allocation->TargetPosition = BlockInfo.Block.Min + BlockInfo.Block.Size / 2; BlockInfo.Allocation->TargetSamplePacked0[0] = FVector4(SingleSample.R.V[0], SingleSample.R.V[1], SingleSample.R.V[2], SingleSample.R.V[3]) / PI; BlockInfo.Allocation->TargetSamplePacked0[1] = FVector4(SingleSample.G.V[0], SingleSample.G.V[1], SingleSample.G.V[2], SingleSample.G.V[3]) / PI; BlockInfo.Allocation->TargetSamplePacked0[2] = FVector4(SingleSample.B.V[0], SingleSample.B.V[1], SingleSample.B.V[2], SingleSample.B.V[3]) / PI; BlockInfo.Allocation->TargetSamplePacked1[0] = FVector4(SingleSample.R.V[4], SingleSample.R.V[5], SingleSample.R.V[6], SingleSample.R.V[7]) / PI; BlockInfo.Allocation->TargetSamplePacked1[1] = FVector4(SingleSample.G.V[4], SingleSample.G.V[5], SingleSample.G.V[6], SingleSample.G.V[7]) / PI; BlockInfo.Allocation->TargetSamplePacked1[2] = FVector4(SingleSample.B.V[4], SingleSample.B.V[5], SingleSample.B.V[6], SingleSample.B.V[7]) / PI; BlockInfo.Allocation->TargetSamplePacked2 = FVector4(SingleSample.R.V[8], SingleSample.G.V[8], SingleSample.B.V[8], 0) / PI; BlockInfo.Allocation->TargetDirectionalShadowing = DirectionalShadowing; const float BentNormalLength = SkyBentNormal.Size(); BlockInfo.Allocation->TargetSkyBentNormal = FVector4(SkyBentNormal / FMath::Max(BentNormalLength, .0001f), BentNormalLength); if (!BlockInfo.Allocation->bHasEverUpdatedSingleSample) { // If this is the first update, also set the interpolated state to match the new target //@todo - detect and handle teleports in the same way BlockInfo.Allocation->SingleSamplePosition = BlockInfo.Allocation->TargetPosition; for (int32 VectorIndex = 0; VectorIndex < 3; VectorIndex++) // RGB { BlockInfo.Allocation->SingleSamplePacked0[VectorIndex] = BlockInfo.Allocation->TargetSamplePacked0[VectorIndex]; BlockInfo.Allocation->SingleSamplePacked1[VectorIndex] = BlockInfo.Allocation->TargetSamplePacked1[VectorIndex]; } BlockInfo.Allocation->SingleSamplePacked2 = BlockInfo.Allocation->TargetSamplePacked2; BlockInfo.Allocation->CurrentDirectionalShadowing = BlockInfo.Allocation->TargetDirectionalShadowing; BlockInfo.Allocation->CurrentSkyBentNormal = BlockInfo.Allocation->TargetSkyBentNormal; BlockInfo.Allocation->bHasEverUpdatedSingleSample = true; } BlockInfo.Block.bHasEverBeenUpdated = true; }
void FIndirectLightingCache::UpdateBlock(FScene* Scene, FViewInfo* DebugDrawingView, FBlockUpdateInfo& BlockInfo) { const int32 NumSamplesPerBlock = BlockInfo.Block.TexelSize * BlockInfo.Block.TexelSize * BlockInfo.Block.TexelSize; FSHVectorRGB2 SingleSample; float DirectionalShadowing = 1; if (CanIndirectLightingCacheUseVolumeTexture() && BlockInfo.Allocation->bOpaqueRelevance) { static TArray<float> AccumulatedWeight; AccumulatedWeight.Reset(NumSamplesPerBlock); AccumulatedWeight.AddZeroed(NumSamplesPerBlock); static TArray<FSHVectorRGB2> AccumulatedIncidentRadiance; AccumulatedIncidentRadiance.Reset(NumSamplesPerBlock); AccumulatedIncidentRadiance.AddZeroed(NumSamplesPerBlock); // Interpolate SH samples from precomputed lighting samples and accumulate lighting data for an entire block InterpolateBlock(Scene, BlockInfo.Block, AccumulatedWeight, AccumulatedIncidentRadiance); static TArray<FFloat16Color> Texture0Data; static TArray<FFloat16Color> Texture1Data; static TArray<FFloat16Color> Texture2Data; Texture0Data.Reset(NumSamplesPerBlock); Texture1Data.Reset(NumSamplesPerBlock); Texture2Data.Reset(NumSamplesPerBlock); Texture0Data.AddUninitialized(NumSamplesPerBlock); Texture1Data.AddUninitialized(NumSamplesPerBlock); Texture2Data.AddUninitialized(NumSamplesPerBlock); const int32 FormatSize = GPixelFormats[PF_FloatRGBA].BlockBytes; check(FormatSize == sizeof(FFloat16Color)); // Encode the SH samples into a texture format EncodeBlock(DebugDrawingView, BlockInfo.Block, AccumulatedWeight, AccumulatedIncidentRadiance, Texture0Data, Texture1Data, Texture2Data, SingleSample); // Setup an update region const FUpdateTextureRegion3D UpdateRegion( BlockInfo.Block.MinTexel.X, BlockInfo.Block.MinTexel.Y, BlockInfo.Block.MinTexel.Z, 0, 0, 0, BlockInfo.Block.TexelSize, BlockInfo.Block.TexelSize, BlockInfo.Block.TexelSize); // Update the volume texture atlas RHIUpdateTexture3D((const FTexture3DRHIRef&)GetTexture0().ShaderResourceTexture, 0, UpdateRegion, BlockInfo.Block.TexelSize * FormatSize, BlockInfo.Block.TexelSize * BlockInfo.Block.TexelSize * FormatSize, (const uint8*)Texture0Data.GetData()); RHIUpdateTexture3D((const FTexture3DRHIRef&)GetTexture1().ShaderResourceTexture, 0, UpdateRegion, BlockInfo.Block.TexelSize * FormatSize, BlockInfo.Block.TexelSize * BlockInfo.Block.TexelSize * FormatSize, (const uint8*)Texture1Data.GetData()); RHIUpdateTexture3D((const FTexture3DRHIRef&)GetTexture2().ShaderResourceTexture, 0, UpdateRegion, BlockInfo.Block.TexelSize * FormatSize, BlockInfo.Block.TexelSize * BlockInfo.Block.TexelSize * FormatSize, (const uint8*)Texture2Data.GetData()); } else { InterpolatePoint(Scene, BlockInfo.Block, DirectionalShadowing, SingleSample); } // Record the position that the sample was taken at BlockInfo.Allocation->TargetPosition = BlockInfo.Block.Min + BlockInfo.Block.Size / 2; BlockInfo.Allocation->TargetSamplePacked[0] = FVector4(SingleSample.R.V[0], SingleSample.R.V[1], SingleSample.R.V[2], SingleSample.R.V[3]) / PI; BlockInfo.Allocation->TargetSamplePacked[1] = FVector4(SingleSample.G.V[0], SingleSample.G.V[1], SingleSample.G.V[2], SingleSample.G.V[3]) / PI; BlockInfo.Allocation->TargetSamplePacked[2] = FVector4(SingleSample.B.V[0], SingleSample.B.V[1], SingleSample.B.V[2], SingleSample.B.V[3]) / PI; BlockInfo.Allocation->TargetDirectionalShadowing = DirectionalShadowing; if (!BlockInfo.Allocation->bHasEverUpdatedSingleSample) { // If this is the first update, also set the interpolated state to match the new target //@todo - detect and handle teleports in the same way BlockInfo.Allocation->SingleSamplePosition = BlockInfo.Allocation->TargetPosition; for (int32 VectorIndex = 0; VectorIndex < ARRAY_COUNT(BlockInfo.Allocation->SingleSamplePacked); VectorIndex++) { BlockInfo.Allocation->SingleSamplePacked[VectorIndex] = BlockInfo.Allocation->TargetSamplePacked[VectorIndex]; } BlockInfo.Allocation->CurrentDirectionalShadowing = BlockInfo.Allocation->TargetDirectionalShadowing; BlockInfo.Allocation->bHasEverUpdatedSingleSample = true; } BlockInfo.Block.bHasEverBeenUpdated = true; }