Lumen Directlighting: Lights

Shader

RWTexture2D<float3> RWDirectLightingAtlas;
StructuredBuffer<uint> CardTiles;
StructuredBuffer<uint> LightTileOffsetNumPerCardTile;
StructuredBuffer<uint2> LightTilesPerCardTile;

[numthreads( 8 ,  8 , 1)]
void LumenCardBatchDirectLightingCS(
	uint3 GroupId : SV_GroupID,
	uint3 GroupThreadId : SV_GroupThreadID)
{
	uint CardTileIndex = GroupId.x;
	uint2 TexelCoordInTile = GroupThreadId.xy;

	uint PackedOffsetNum = LightTileOffsetNumPerCardTile[CardTileIndex];
	uint LightTilesOffset = BitFieldExtractU32(PackedOffsetNum, 24, 0);
	uint NumLightTiles = BitFieldExtractU32(PackedOffsetNum, 8, 24);

	FCardTileData CardTile = UnpackCardTileData(CardTiles[CardTileIndex]);
	FLumenCardPageData CardPage = GetLumenCardPageData(CardTile.CardPageIndex);

	uint2 CoordInCardPage =  8  * CardTile.TileCoord + TexelCoordInTile;
	uint2 AtlasCoord = CardPage.PhysicalAtlasCoord + CoordInCardPage;

	float2 AtlasUV = CardPage.PhysicalAtlasUVRect.xy + CardPage.PhysicalAtlasUVTexelScale * (CoordInCardPage + 0.5);
	float2 CardUV = CardPage.CardUVRect.xy + CardPage.CardUVTexelScale * (CoordInCardPage + 0.5);

	FLumenCardData Card = GetLumenCardData(CardPage.CardIndex);
	FLumenSurfaceCacheData SurfaceCacheData = GetSurfaceCacheData(Card, CardUV, AtlasUV);

	if (NumLightTiles == 0 || !SurfaceCacheData.bValid)
	{
		RWDirectLightingAtlas[AtlasCoord] = 0;
		return;
	}

	float3 Irradiance = 0.0f;

	for (uint CulledLightIndex = 0; CulledLightIndex < NumLightTiles; ++CulledLightIndex)
	{
		FLightTileForLightPass LightTile = UnpackLightTileForLightPass(LightTilesPerCardTile[LightTilesOffset + CulledLightIndex]);

		FShadowMaskRay ShadowMaskRay;
		ShadowMaskRay.bShadowFactorComplete = true;
		ShadowMaskRay.ShadowFactor = 1.0f;

		if (LightTile.ShadowMaskIndex != 0xffffffff)
		{
			ReadShadowMaskRay(LightTile.ShadowMaskIndex, TexelCoordInTile, ShadowMaskRay);
		}

		if (ShadowMaskRay.ShadowFactor > 0.0f)
		{
			uint ViewIndex =  0  ? LightTile.ViewIndex : 0;
			Irradiance += GetIrradianceForLight(LightTile.LightIndex, SurfaceCacheData,  LWCToFloat(PreViewTranslation[ViewIndex]) .xyz, ShadowMaskRay.ShadowFactor);


		}
	}

	RWDirectLightingAtlas[AtlasCoord] = Irradiance;
}
#ifdef LUMEN_CARD_DATA_STRIDE
FLumenSurfaceCacheData GetSurfaceCacheData(FLumenCardData Card, float2 CardUV, float2 AtlasUV)
{
	float Depth = Texture2DSampleLevel(LumenCardScene.DepthAtlas, GlobalPointClampedSampler, AtlasUV, 0).x;

	FLumenSurfaceCacheData SurfaceCacheData;
	SurfaceCacheData.Depth = Depth;
	SurfaceCacheData.bValid = IsSurfaceCacheDepthValid(Depth);
	SurfaceCacheData.Albedo = float3(0.0f, 0.0f, 0.0f);
	SurfaceCacheData.Emissive = float3(0.0f, 0.0f, 0.0f);

	float2 NormalXY = float2(0.5f, 0.5f);

	if (SurfaceCacheData.bValid)
	{
		SurfaceCacheData.Albedo = DecodeSurfaceCacheAlbedo(Texture2DSampleLevel(LumenCardScene.AlbedoAtlas, GlobalPointClampedSampler, AtlasUV, 0).xyz);
		SurfaceCacheData.Emissive = Texture2DSampleLevel(LumenCardScene.EmissiveAtlas, GlobalPointClampedSampler, AtlasUV, 0).x;
		NormalXY = Texture2DSampleLevel(LumenCardScene.NormalAtlas, GlobalPointClampedSampler, AtlasUV, 0).xy;
	}

	SurfaceCacheData.WorldNormal = DecodeSurfaceCacheNormal(Card, NormalXY);
	SurfaceCacheData.WorldPosition = GetCardWorldPosition(Card, CardUV, SurfaceCacheData.Depth);

	return SurfaceCacheData;
}
#endif

#ifdef LUMEN_CARD_DATA_STRIDE
float3 DecodeSurfaceCacheNormal(FLumenCardData Card, float2 EncodedNormal)
{
	float3 CardSpaceNormal;
	CardSpaceNormal.xy = EncodedNormal.xy * 2.0f - 1.0f;
	CardSpaceNormal.z = sqrt(max(1.0f - length2(CardSpaceNormal.xy), 0.0001f));
	return normalize(mul(Card.WorldToLocalRotation, CardSpaceNormal));
}
#endif

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;
}

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);
}

void GetCardPageLocalBBox(FLumenCardPageData CardPage, FLumenCardData Card, out float3 CardPageLocalCenter, out float3 CardPageLocalExtent)
{
	GetCardLocalBBox(CardPage, Card, 0, 1, CardPageLocalCenter, CardPageLocalExtent);
}

float3 GetCardWorldPosition(FLumenCardData Card, float2 CardUV, float Depth)
{
	float3 LocalPosition = GetCardLocalPosition(Card.LocalExtent, CardUV, Depth);
	float3 WorldPosition = mul(Card.WorldToLocalRotation, LocalPosition) + Card.Origin;
	return WorldPosition;
}
void ReadShadowMaskRay(uint CardTileIndex, uint2 CoordInCardTile, inout FShadowMaskRay ShadowMaskRay)
{
	uint BitOffset = SHADOW_MASK_RAY_BITS * (CoordInCardTile.x + CoordInCardTile.y * CARD_TILE_SIZE);

	uint ShadowMask = ShadowMaskTiles[SHADOW_MASK_CARD_TILE_DWORDS * CardTileIndex + BitOffset / 32];
	ShadowMask = ShadowMask >> (BitOffset % 32);

	ShadowMaskRay.ShadowFactor = float(ShadowMask & SHADOW_FACTOR_BITS_MASK) / SHADOW_FACTOR_BITS_MASK;
	ShadowMaskRay.bShadowFactorComplete = (ShadowMask & SHADOW_FACTOR_COMPLETE_BITS_MASK) != 0;
}
float3 GetIrradianceForLight(
	uint LightIndex,
	FLumenSurfaceCacheData SurfaceCacheData,
	float3 PreViewTranslation,
	float ShadowFactor)
{
	FDeferredLightData LightData = GetLumenDirectLightingLightData(LightIndex, PreViewTranslation);

	float3 WorldNormal = SurfaceCacheData.WorldNormal;
	float3 WorldPosition = SurfaceCacheData.WorldPosition;
	float3 TranslatedWorldPosition = WorldPosition + PreViewTranslation;

	float3 LightColor = LightData.Color;
	float3 L = LightData.Direction;
	float3 ToLight = L;
	float3 AreaLightFalloffColor = 1;
	float CombinedAttenuation = 1;
	float NoL = saturate(dot(WorldNormal, L));

	if (LightData.bRadialLight)
	{
		FAreaLightIntegrateContext Context = (FAreaLightIntegrateContext) 0;
		float LightMask = GetLocalLightAttenuation(TranslatedWorldPosition, LightData, ToLight, L);

		float Attenuation = 0.0f;
		float Roughness = 1;
		float3 V = float3(1, 0, 0);

		if (LightData.bRectLight)
		{
			FRect Rect = GetRect(ToLight, LightData);
			Attenuation = IntegrateLight(Rect);

			if (IsRectVisible(Rect))
			{
				const FRectTexture SourceTexture = InitRectTexture(LightData);
				Context = CreateRectIntegrateContext(Roughness, WorldNormal, V, Rect, SourceTexture);
			}
		}
		else
		{
			FCapsuleLight Capsule = GetCapsule(ToLight, LightData);
			Capsule.DistBiasSqr = 0;
			Context = CreateCapsuleIntegrateContext(Roughness, WorldNormal, V, Capsule, LightData.bInverseSquared);
			Attenuation = IntegrateLight(Capsule, LightData.bInverseSquared);
		}

		CombinedAttenuation = Attenuation * LightMask;
		AreaLightFalloffColor = Context.AreaLight.FalloffColor;
		NoL = Context.NoL;
	}

	float3 Irradiance = LightColor * AreaLightFalloffColor * (CombinedAttenuation * NoL * ShadowFactor);

	return Irradiance;
}
// Should this be SH instead?
float IntegrateLight( FCapsuleLight Capsule, bool bInverseSquared )
{
	float Falloff;

	BRANCH
	if( Capsule.Length > 0 )
	{
		float NoL;
		float LineCosSubtended = 1;
		LineIrradiance( 0, Capsule.LightPos[0], Capsule.LightPos[1], Capsule.DistBiasSqr, LineCosSubtended, Falloff, NoL );
	}
	else
	{
		float3 ToLight = Capsule.LightPos[0];
		float DistSqr = dot( ToLight, ToLight );
		Falloff = rcp( DistSqr + Capsule.DistBiasSqr );
	}

	Falloff = bInverseSquared ? Falloff : 1;

	return Falloff;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值