void FIndirectLightingCache::EncodeBlock(
	FViewInfo* DebugDrawingView,
	const FIndirectLightingCacheBlock& Block, 
	const TArray<float>& AccumulatedWeight, 
	const TArray<FSHVectorRGB2>& AccumulatedIncidentRadiance,
	const TArray<FVector>& AccumulatedSkyBentNormal,
	TArray<FFloat16Color>& Texture0Data,
	TArray<FFloat16Color>& Texture1Data,
	TArray<FFloat16Color>& Texture2Data,
	FSHVectorRGB2& SingleSample,
	FVector& SkyBentNormal)
{
	FViewElementPDI DebugPDI(DebugDrawingView, NULL);

	for (int32 Z = 0; Z < Block.TexelSize; Z++)
	{
		for (int32 Y = 0; Y < Block.TexelSize; Y++)
		{
			for (int32 X = 0; X < Block.TexelSize; X++)
			{
				const int32 LinearIndex = Z * Block.TexelSize * Block.TexelSize + Y * Block.TexelSize + X;

				FSHVectorRGB2 IncidentRadiance = AccumulatedIncidentRadiance[LinearIndex];
				float Weight = AccumulatedWeight[LinearIndex];

				if (Weight > 0)
				{
					IncidentRadiance = IncidentRadiance / Weight;

					if (GCacheReduceSHRinging != 0)
					{
						ReduceSHRinging(IncidentRadiance);
					}
				}

				// Populate single sample from center
				if (X == Block.TexelSize / 2 && Y == Block.TexelSize / 2 && Z == Block.TexelSize / 2)
				{
					SingleSample = IncidentRadiance;
					SkyBentNormal = AccumulatedSkyBentNormal[LinearIndex] / (Weight > 0 ? Weight : 1);
				}

				if (GCacheDrawInterpolationPoints != 0 && DebugDrawingView)
				{
					const FVector WorldPosition = Block.Min + (FVector(X, Y, Z) + .5f) / Block.TexelSize * Block.Size;
					DebugPDI.DrawPoint(WorldPosition, FLinearColor(0, 0, 1), 10, SDPG_World);
				}

				Texture0Data[LinearIndex] = FLinearColor(IncidentRadiance.R.V[0], IncidentRadiance.G.V[0], IncidentRadiance.B.V[0], IncidentRadiance.R.V[3]);
				Texture1Data[LinearIndex] = FLinearColor(IncidentRadiance.R.V[1], IncidentRadiance.G.V[1], IncidentRadiance.B.V[1], IncidentRadiance.G.V[3]);
				Texture2Data[LinearIndex] = FLinearColor(IncidentRadiance.R.V[2], IncidentRadiance.G.V[2], IncidentRadiance.B.V[2], IncidentRadiance.B.V[3]);
			}
		}
	}
}
void FIndirectLightingCache::InterpolatePoint(
	FScene* Scene, 
	const FIndirectLightingCacheBlock& Block,
	float& OutDirectionalShadowing, 
	FSHVectorRGB3& OutIncidentRadiance,
	FVector& OutSkyBentNormal)
{
	FSHVectorRGB3 AccumulatedIncidentRadiance;
	FVector AccumulatedSkyBentNormal(0, 0, 0);
	float AccumulatedDirectionalShadowing = 0;
	float AccumulatedWeight = 0;

	for (int32 VolumeIndex = 0; VolumeIndex < Scene->PrecomputedLightVolumes.Num(); VolumeIndex++)
	{
		const FPrecomputedLightVolume* PrecomputedLightVolume = Scene->PrecomputedLightVolumes[VolumeIndex];
		if (PrecomputedLightVolume)
		{
			PrecomputedLightVolume->InterpolateIncidentRadiancePoint(
				Block.Min + Block.Size / 2,
				AccumulatedWeight,
				AccumulatedDirectionalShadowing,
				AccumulatedIncidentRadiance,
				AccumulatedSkyBentNormal);
		}
	}

	if (AccumulatedWeight > 0)
	{
		OutDirectionalShadowing = AccumulatedDirectionalShadowing / AccumulatedWeight;
		OutIncidentRadiance = AccumulatedIncidentRadiance / AccumulatedWeight;
		OutSkyBentNormal = AccumulatedSkyBentNormal / AccumulatedWeight;

		if (GCacheReduceSHRinging != 0)
		{
			ReduceSHRinging(OutIncidentRadiance);
		}
	}
	else
	{
		OutIncidentRadiance = AccumulatedIncidentRadiance;
		OutDirectionalShadowing = 1;
		// Use an unoccluded vector if no valid samples were found for interpolation
		OutSkyBentNormal = FVector(0, 0, 1);
	}
}
void FIndirectLightingCache::InterpolatePoint(
	FScene* Scene, 
	const FIndirectLightingCacheBlock& Block,
	float& OutDirectionalShadowing, 
	FSHVectorRGB2& OutIncidentRadiance)
{
	FSHVectorRGB2 AccumulatedIncidentRadiance;
	float AccumulatedDirectionalShadowing = 0;
	float AccumulatedWeight = 0;

	for (int32 VolumeIndex = 0; VolumeIndex < Scene->PrecomputedLightVolumes.Num(); VolumeIndex++)
	{
		const FPrecomputedLightVolume* PrecomputedLightVolume = Scene->PrecomputedLightVolumes[VolumeIndex];
		PrecomputedLightVolume->InterpolateIncidentRadiancePoint(
			Block.Min + Block.Size / 2, 
			AccumulatedWeight, 
			AccumulatedDirectionalShadowing,
			AccumulatedIncidentRadiance);
	}

	if (AccumulatedWeight > 0)
	{
		OutDirectionalShadowing = AccumulatedDirectionalShadowing / AccumulatedWeight;
		OutIncidentRadiance = AccumulatedIncidentRadiance / AccumulatedWeight;

		if (GCacheReduceSHRinging != 0)
		{
			ReduceSHRinging(OutIncidentRadiance);
		}
	}
	else
	{
		OutIncidentRadiance = AccumulatedIncidentRadiance;
		OutDirectionalShadowing = AccumulatedDirectionalShadowing;
	}
}