Lumen DirectLighting:CullTiles

 SpliceCardPagesInotTiles:

LumenSceneDirectLightingCulling.usf

StructuredBuffer CardPageIndexAllocator;
StructuredBuffer CardPageIndexData;
RWStructuredBuffer RWCardTileAllocator;
RWStructuredBuffer RWCardTiles;

groupshared uint SharedTileAllocator;
groupshared uint SharedTiles[ 8  *  8 ];
groupshared uint SharedGlobalTileOffset;




[numthreads( 8 ,  8 , 1)]
void SpliceCardPagesIntoTilesCS(
	uint3 GroupId : SV_GroupID,
	uint3 DispatchThreadId : SV_DispatchThreadID,
	uint3 GroupThreadId : SV_GroupThreadID)
{
	uint LinearThreadIndex = GroupThreadId.x + GroupThreadId.y *  8 ;
	if (all(GroupThreadId == 0))
	{
		SharedTileAllocator = 0;
		SharedGlobalTileOffset = 0;
		SharedTiles[0] = 0;
	}

	GroupMemoryBarrierWithGroupSync();


	uint LinearLightTileOffset = (GroupId.x % 4);
	uint IndexInIndexBuffer = GroupId.x / 4;


	uint2 TileOffset = ZOrder2D(LinearThreadIndex, log2(8));

	uint2 TileCoord;
	TileCoord.x = (LinearLightTileOffset % 2) * 8 + TileOffset.x;
	TileCoord.y = (LinearLightTileOffset / 2) * 8 + TileOffset.y;

	if (IndexInIndexBuffer < CardPageIndexAllocator[0])
	{
		uint CardPageIndex = CardPageIndexData[IndexInIndexBuffer];
		FLumenCardPageData CardPage = GetLumenCardPageData(CardPageIndex);
		if (CardPage.CardIndex >= 0)
		{
			FLumenCardData Card = GetLumenCardData(CardPage.CardIndex);

			const uint2 SizeInTiles = CardPage.SizeInTexels /  8 ;

			if (all(TileCoord < SizeInTiles))
			{
				FCardTileData CardTile;
				CardTile.CardPageIndex = CardPageIndex;
				CardTile.TileCoord = TileCoord;

				uint CardTileIndex = 0;
				InterlockedAdd(SharedTileAllocator, 1, CardTileIndex);
				SharedTiles[CardTileIndex] = PackCardTileData(CardTile);
			}
		}
	}

	GroupMemoryBarrierWithGroupSync();

	if (all(GroupThreadId == 0) && SharedTileAllocator > 0)
	{
		InterlockedAdd(RWCardTileAllocator[0], SharedTileAllocator, SharedGlobalTileOffset);
	}

	GroupMemoryBarrierWithGroupSync();

	if (LinearThreadIndex < SharedTileAllocator)
	{
		RWCardTiles[SharedGlobalTileOffset + LinearThreadIndex] = SharedTiles[LinearThreadIndex];
	}
}

InitializeCardTileIndirectArgs

StructuredBuffer CardTileAllocator;
StructuredBuffer CardTiles;
RWBuffer RWDispatchCardTilesIndirectArgs;

[numthreads( 64 , 1, 1)]
void InitializeCardTileIndirectArgsCS(uint3 DispatchThreadId : SV_DispatchThreadID)
{
	if (DispatchThreadId.x == 0)
	{
		uint NumCardTiles = CardTileAllocator[0];


		RWDispatchCardTilesIndirectArgs[0] = (NumCardTiles + 63) / 64;
		RWDispatchCardTilesIndirectArgs[1] = 1;
		RWDispatchCardTilesIndirectArgs[2] = 1;


		RWDispatchCardTilesIndirectArgs[3] = NumCardTiles;
		RWDispatchCardTilesIndirectArgs[4] = 1;
		RWDispatchCardTilesIndirectArgs[5] = 1;
	}
}

BuildLightTiles:

[numthreads( 64 , 1, 1)]
void BuildLightTilesCS(
	uint3 GroupId : SV_GroupID,
	uint3 DispatchThreadId : SV_DispatchThreadID,
	uint3 GroupThreadId : SV_GroupThreadID)
{

	uint CardTileIndex = DispatchThreadId.x;

	FLightSampleAccumulator LightSampleAccumulator = InitLightSampleAccumulator();

	if (CardTileIndex < CardTileAllocator[0])
	{
		FCardTileData CardTile = UnpackCardTileData(CardTiles[CardTileIndex]);
		FLumenCardPageData CardPage = GetLumenCardPageData(CardTile.CardPageIndex);
		uint PackedOffsetNum = 0;

		if (CardPage.CardIndex >= 0)
		{
			FLumenCardData Card = GetLumenCardData(CardPage.CardIndex);

			const uint2 SizeInTiles = CardPage.SizeInTexels /  8 ;
			float2 UVMin = float2(CardTile.TileCoord) / SizeInTiles;
			float2 UVMax = float2(CardTile.TileCoord + 1) / SizeInTiles;

			float SwapY = UVMin.y;
			UVMin.y = 1.0f - UVMax.y;
			UVMax.y = 1.0f - SwapY;

			uint ViewIndex = GetCardViewIndex(CardPage, Card, UVMin, UVMax, NumViews, true);


			for (uint LightIndex = 0; LightIndex < NumLights; ++LightIndex)
			{
				FLumenLight LumenLight = LoadLumenLight(LightIndex, PreViewTranslation[ViewIndex].xyz);

				float3 CardPageWorldCenter = 0.0f;
				bool bLightAffectsCard = DoesLightAffectCardPageUVRange(LumenLight, CardPage, Card, UVMin, UVMax, CardPageWorldCenter);
				if (bLightAffectsCard)
				{

					float3 TranslatedWorldPosition = CardPageWorldCenter +  LWCToFloat( GetPrimaryView() .PreViewTranslation) ;

					FLightSample LightSample;
					LightSample.Weight = GetLightWeight(LumenLight, TranslatedWorldPosition);
					LightSample.LightIndex = LightIndex;
					LightSample.bHasShadowMask = LumenLight.bHasShadowMask;
					AddLightSample(LightSampleAccumulator, LightSample);
				}
			}

			uint NumPackedLightSamples = 0;
			for (uint PackedSampleIndex = 0; PackedSampleIndex <  8 ; ++PackedSampleIndex)
			{
				if (LightSampleAccumulator.PackedSamples[PackedSampleIndex] > 0)
				{
					++NumPackedLightSamples;
				}
			}

			uint LightTileOffset = 0;
			if (NumPackedLightSamples > 0)
			{
				InterlockedAdd(RWLightTileAllocator[0], NumPackedLightSamples, LightTileOffset);
			}

			for (uint LightSampleIndex = 0; LightSampleIndex < NumPackedLightSamples; ++LightSampleIndex)
			{
				FLightSample LightSample = UnpackLightSample(LightSampleAccumulator.PackedSamples[LightSampleIndex]);


				FLightTileForCompactionPass LightTile;
				LightTile.LightIndex = LightSample.LightIndex;
				LightTile.ViewIndex = ViewIndex;
				LightTile.bHasShadowMask = LightSample.bHasShadowMask;
				LightTile.CardTileIndex = CardTileIndex;
				LightTile.CulledLightIndex = LightSampleIndex;
				RWLightTiles[LightTileOffset + LightSampleIndex] = PackLightTileForCompactionPass(LightTile);

				InterlockedAdd(RWLightTileAllocatorPerLight[LightSample.LightIndex * NumViews + ViewIndex], 1);
			}

			if (NumPackedLightSamples > 0)
			{
				uint CardLightTilesOffset;
				InterlockedAdd(RWLightTileAllocatorForPerCardTileDispatch[0], NumPackedLightSamples, CardLightTilesOffset);
				PackedOffsetNum = (NumPackedLightSamples << 24) | CardLightTilesOffset;
			}
		}

		RWLightTileOffsetNumPerCardTile[CardTileIndex] = PackedOffsetNum;
	}
}

StructuredBuffer LightTileAllocatorPerLight;
RWStructuredBuffer RWLightTileOffsetsPerLight;

 

FLumenLight LoadLumenLight(uint LightIndex, float3 PreViewTranslation)
{
	FLumenPackedLight PackedLight = LumenPackedLights[LightIndex];

	FDeferredLightData DeferredLightData = (FDeferredLightData)0;
	DeferredLightData.TranslatedWorldPosition = PackedLight.WorldPosition + PreViewTranslation;
	DeferredLightData.InvRadius = PackedLight.InvRadius;
	DeferredLightData.Color = PackedLight.Color;
	DeferredLightData.FalloffExponent = PackedLight.FalloffExponent;
	DeferredLightData.Direction = PackedLight.Direction;
	DeferredLightData.Tangent = PackedLight.Tangent;
	DeferredLightData.SpotAngles = PackedLight.SpotAngles;
	DeferredLightData.SourceRadius = PackedLight.SourceRadius;
	DeferredLightData.SourceLength = PackedLight.SourceLength;
	DeferredLightData.SoftSourceRadius = PackedLight.SoftSourceRadius;
	DeferredLightData.SpecularScale = PackedLight.SpecularScale;
	DeferredLightData.ContactShadowLength = 0.0f;
	DeferredLightData.ContactShadowLengthInWS = false;
	DeferredLightData.DistanceFadeMAD = 0.0f;
	DeferredLightData.ShadowMapChannelMask = 0.0f;
	DeferredLightData.ShadowedBits = 0;
	DeferredLightData.RectLightBarnCosAngle = PackedLight.RectLightBarnCosAngle;
	DeferredLightData.RectLightBarnLength = PackedLight.RectLightBarnLength;
	DeferredLightData.RectLightAtlasUVScale = PackedLight.SinCosConeAngleOrRectLightAtlasUVScale;
	DeferredLightData.RectLightAtlasUVOffset = PackedLight.RectLightAtlasUVOffset;
	DeferredLightData.RectLightAtlasMaxLevel = PackedLight.RectLightAtlasMaxLevel;
	DeferredLightData.bInverseSquared = PackedLight.FalloffExponent == 0.0f;
	DeferredLightData.bRadialLight = PackedLight.LightType != LIGHT_TYPE_DIRECTIONAL;
	DeferredLightData.bSpotLight = PackedLight.LightType == LIGHT_TYPE_SPOT;
	DeferredLightData.bRectLight = PackedLight.LightType == LIGHT_TYPE_RECT;

	FLumenLight LumenLight = (FLumenLight)0;
	LumenLight.DeferredLightData = DeferredLightData;
	LumenLight.InfluenceSphere = PackedLight.InfluenceSphere;
	LumenLight.ProxyPosition = PackedLight.ProxyPosition;
	LumenLight.ProxyRadius = PackedLight.ProxyRadius;
	LumenLight.ProxyDirection = PackedLight.ProxyDirection;
	LumenLight.CosConeAngle = PackedLight.SinCosConeAngleOrRectLightAtlasUVScale.y;
	LumenLight.SinConeAngle = PackedLight.SinCosConeAngleOrRectLightAtlasUVScale.x;
	LumenLight.VirtualShadowMapId = PackedLight.VirtualShadowMapId;
	LumenLight.bHasShadowMask = PackedLight.bHasShadowMask;
	LumenLight.LightingChannelMask = PackedLight.LightingChannelMask;
	LumenLight.Type = PackedLight.LightType;
	return LumenLight;
}
bool DoesLightAffectCardPageUVRange(FLumenLight LumenLight, FLumenCardPageData CardPage, FLumenCardData Card, float2 UVMin, float2 UVMax, inout float3 OutCardPageWorldCenter)
{
	// Lighting channels test
	if (!(Card.LightingChannelMask & LumenLight.LightingChannelMask))
	{
		return false;
	}

	float3 CardPageLocalCenter;
	float3 CardPageLocalExtent;
	GetCardLocalBBox(CardPage, Card, UVMin, UVMax, CardPageLocalCenter, CardPageLocalExtent);

	float3 CardPageWorldCenter = mul(Card.WorldToLocalRotation, CardPageLocalCenter) + Card.Origin;
	float3 CardPageWorldExtent = mul(abs(Card.WorldToLocalRotation), CardPageLocalExtent);
	float CardPageWorldBoundingSphere = length(CardPageLocalExtent);
	OutCardPageWorldCenter = CardPageWorldCenter;

	float4 InfluenceSphere = LumenLight.InfluenceSphere;
	float3 LightInfluenceSphereLocalCenter = mul(InfluenceSphere.xyz - Card.Origin, Card.WorldToLocalRotation);
	const float BoxDistanceSq = ComputeSquaredDistanceFromBoxToPoint(CardPageLocalCenter, CardPageLocalExtent, LightInfluenceSphereLocalCenter);
	const bool bCardAffectedByInfluenceSphere = BoxDistanceSq < InfluenceSphere.w * InfluenceSphere.w;

	const uint LightType = LumenLight.Type;
	const float3 LightPosition = LumenLight.ProxyPosition;
	const float3 LightDirection = LumenLight.ProxyDirection;
	const float LightRadius = LumenLight.ProxyRadius;

	// Fast out
	if (LightType != LIGHT_TYPE_DIRECTIONAL && !bCardAffectedByInfluenceSphere)
	{
		return false;
	}

	if (LightType == LIGHT_TYPE_DIRECTIONAL)
	{
		return true;
	}
	else if (LightType == LIGHT_TYPE_POINT)
	{
		// Point light
		return bCardAffectedByInfluenceSphere;
	}
	else if (LightType == LIGHT_TYPE_SPOT)
	{
		float CosConeAngle = LumenLight.CosConeAngle;
		float SinConeAngle = LumenLight.SinConeAngle;

		float ConeAxisDistance = dot(CardPageWorldCenter - LightPosition, LightDirection);
		float2 ConeAxisDistanceMinMax = float2(ConeAxisDistance + CardPageWorldBoundingSphere, ConeAxisDistance - CardPageWorldBoundingSphere);

		// Spot light
		return bCardAffectedByInfluenceSphere
			&& SphereIntersectCone(float4(CardPageWorldCenter, CardPageWorldBoundingSphere), LightPosition, LightDirection, CosConeAngle, SinConeAngle)
			&& ConeAxisDistanceMinMax.x > 0 && ConeAxisDistanceMinMax.y < LightRadius;
	}
	else if (LightType == LIGHT_TYPE_RECT)
	{
		// Rect light
		float4 BackPlane = float4(LightDirection, dot(LightPosition, LightDirection));
		float DistanceFromBoxCenterToPlane = dot(BackPlane.xyz, CardPageWorldCenter) - BackPlane.w;
		float MaxExtent = dot(CardPageWorldExtent, abs(BackPlane.xyz));
		bool bInFrontOfPlane = DistanceFromBoxCenterToPlane + MaxExtent > 0.0f;
		return bCardAffectedByInfluenceSphere && bInFrontOfPlane;
	}

	// Error: Unknown light type
	return false;
}

/** Computes squared distance from a point in space to an AABB. */
MaterialFloat ComputeSquaredDistanceFromBoxToPoint(MaterialFloat3 BoxCenter, MaterialFloat3 BoxExtent, MaterialFloat3 InPoint)
{
	MaterialFloat3 AxisDistances = max(abs(InPoint - BoxCenter) - BoxExtent, 0);
	return dot(AxisDistances, AxisDistances);
}

void GetCardLocalBBox(FLumenCardPageData CardPage, FLumenCardData Card, float2 UVMin, float2 UVMax, out float3 CardPageLocalCenter, out float3 CardPageLocalExtent)
{
	float2 CardUVMin = lerp(CardPage.CardUVRect.xw, CardPage.CardUVRect.zy, UVMin);
	float2 CardUVMax = lerp(CardPage.CardUVRect.xw, CardPage.CardUVRect.zy, UVMax);
	float3 CardPageLocalBoxMin = GetCardLocalPosition(Card.LocalExtent, CardUVMin, 1.0f);
	float3 CardPageLocalBoxMax = GetCardLocalPosition(Card.LocalExtent, CardUVMax, 0.0f);

	CardPageLocalCenter = 0.5f * (CardPageLocalBoxMax + CardPageLocalBoxMin);
	CardPageLocalExtent = 0.5f * (CardPageLocalBoxMax - CardPageLocalBoxMin);
}

float3 GetCardLocalPosition(float3 CardLocalExtent, float2 CardUV, float Depth)
{
	CardUV.x = 1.0f - CardUV.x;

	float3 LocalPosition;
	LocalPosition.xy = CardLocalExtent.xy * (1.0f - 2.0f * CardUV);
	LocalPosition.z = -(2.0f * Depth - 1.0f) * CardLocalExtent.z;

	return LocalPosition;
}

 

float GetLightWeight(FLumenLight LumenLight, float3 TranslatedWorldPosition)
{
	FDeferredLightData LightData = LumenLight.DeferredLightData;
	float Weight = Luminance(LightData.Color);

	if (LightData.bRadialLight)
	{
		float3 L = LightData.Direction;
		float3 ToLight = L;
		Weight *= GetLocalLightAttenuation(TranslatedWorldPosition, LightData, ToLight, L);

		float Attenuation = 1.0f;
		if (LightData.bRectLight)
		{
			FRect Rect = GetRect(ToLight, LightData);
			Attenuation = IntegrateLight(Rect);
		}
		else
		{
			FCapsuleLight Capsule = GetCapsule(ToLight, LightData);
			Capsule.DistBiasSqr = 0;
			Attenuation = IntegrateLight(Capsule, LightData.bInverseSquared);
		}
		Weight *= Attenuation;
	}

	return Weight;
}
// Build a list of light tiles for future processing
	{
		FBuildLightTilesCS::FParameters* PassParameters = GraphBuilder.AllocParameters();
		PassParameters->IndirectArgBuffer = DispatchCardTilesIndirectArgs;
		PassParameters->View = Views[0].ViewUniformBuffer;
		PassParameters->LumenCardScene = LumenCardSceneUniformBuffer;
		PassParameters->LumenPackedLights = GraphBuilder.CreateSRV(LumenPackedLights);
		PassParameters->RWLightTileAllocator = GraphBuilder.CreateUAV(LightTileAllocator);
		PassParameters->RWLightTileAllocatorForPerCardTileDispatch = GraphBuilder.CreateUAV(LightTileAllocatorForPerCardTileDispatch);
		PassParameters->RWLightTiles = GraphBuilder.CreateUAV(LightTiles);
		PassParameters->RWLightTileAllocatorPerLight = GraphBuilder.CreateUAV(LightTileAllocatorPerLight);
		PassParameters->RWLightTileOffsetNumPerCardTile = GraphBuilder.CreateUAV(LightTileOffsetNumPerCardTile);
		PassParameters->CardTileAllocator = GraphBuilder.CreateSRV(CardTileAllocator);
		PassParameters->CardTiles = GraphBuilder.CreateSRV(CardTiles);
		PassParameters->MaxLightsPerTile = MaxLightsPerTile;
		PassParameters->NumLights = GatheredLights.Num();
		PassParameters->NumViews = Views.Num();
		check(Views.Num() <= PassParameters->WorldToClip.Num());

		for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
		{
			PassParameters->WorldToClip[ViewIndex] = FMatrix44f(Views[ViewIndex].ViewMatrices.GetViewProjectionMatrix());
			PassParameters->PreViewTranslation[ViewIndex] = FVector4f((FVector3f)Views[ViewIndex].ViewMatrices.GetPreViewTranslation(), 0.0f);
		}

		FBuildLightTilesCS::FPermutationDomain PermutationVector;
		PermutationVector.Set(MaxLightsPerTile);

		auto ComputeShader = GlobalShaderMap->GetShader(PermutationVector);

		FComputeShaderUtils::AddPass(
			GraphBuilder,
			RDG_EVENT_NAME("BuildLightTiles"),
			ComputePassFlags,
			ComputeShader,
			PassParameters,
			DispatchCardTilesIndirectArgs,
			(uint32)ELumenDispatchCardTilesIndirectArgsOffset::OneThreadPerCardTile);
	}

你可能感兴趣的:(#,UE之Lumen,UE)