带有IES的SpotLight的pixelshader流程

IES灯光计算方法:

void UpdateLightDataColor(inout FDeferredLightData LightData, FInputParams InputParams, FDerivedParams DerivedParams)
{
	const float Attenuation = ComputeLightProfileMultiplier(DerivedParams.TranslatedWorldPosition, GetDeferredLightTranslatedWorldPosition(), -DeferredLightUniforms_Direction, DeferredLightUniforms_Tangent);
	const float3 AttenuationRGB = Attenuation * GetAtmosphereAndCloudAttenuation(GetStableTranslatedLargeWorldPosition(InputParams.PixelPos, LookupDeviceZ(InputParams.ScreenUV)), InputParams.ScreenUV);

	LightData.Color *= AttenuationRGB;
}


Texture2D IESTexture;
SamplerState IESTextureSampler;


float ComputeLightProfileMultiplier(float3 WorldPosition, float3 LightPosition, float3 LightDirection, float3 LightTangent)
{

	float3 LightBitangent = normalize( cross( LightTangent, LightDirection ) );

	float4x4 LightTransform = float4x4( float4(LightDirection.xyz, 0), float4(LightBitangent.xyz, 0), float4(LightTangent.xyz, 0), float4(0, 0, 0, 1) );
	float4x4 InvLightTransform = transpose(LightTransform);

	float3 ToLight = normalize(LightPosition - WorldPosition);
	float3 LocalToLight = mul(float4(ToLight.xyz, 0), InvLightTransform).xyz;


	float DotProd = dot(ToLight, LightDirection);

	float Angle = asin(DotProd);

	float NormAngle = Angle / PI + 0.5f;

	float TangentAngle = atan2( -LocalToLight.z, -LocalToLight.y );
	float NormTangentAngle = TangentAngle / (PI * 2.f) + 0.5f;

	return Texture2DSampleLevel(IESTexture, IESTextureSampler, float2(NormAngle, NormTangentAngle), 0).r;



}

 灯光衰减算法:

float GetLocalLightAttenuation(
	float3 TranslatedWorldPosition,
	FDeferredLightData LightData,
	inout float3 ToLight,
	inout float3 L)
{
	ToLight = LightData.TranslatedWorldPosition - TranslatedWorldPosition;

	float DistanceSqr = dot( ToLight, ToLight );
	L = ToLight * rsqrt( DistanceSqr );

	float LightMask;
	if (LightData.bInverseSquared)
	{
		LightMask = Square( saturate( 1 - Square( DistanceSqr * Square(LightData.InvRadius) ) ) );
	}
	else
	{
		LightMask = RadialAttenuation(ToLight * LightData.InvRadius, LightData.FalloffExponent);
	}

	if (LightData.bSpotLight)
	{
		LightMask *= SpotAttenuation(L, -LightData.Direction, LightData.SpotAngles);
	}

	if( LightData.bRectLight )
	{

		LightMask = dot( LightData.Direction, L ) < 0 ? 0 : LightMask;
	}

	return LightMask;
}

float SpotAttenuationMask(float3 L, float3 SpotDirection, float2 SpotAngles)
{
	return saturate((dot(L, -SpotDirection) - SpotAngles.x) * SpotAngles.y);
}
float SpotAttenuation(float3 L, float3 SpotDirection, float2 SpotAngles)
{
	float ConeAngleFalloff = Square(SpotAttenuationMask(L, SpotDirection, SpotAngles));
	return ConeAngleFalloff;
}

float CalcSceneDepth(float2 ScreenUV)
{
	return ConvertFromDeviceZ(Texture2DSampleLevel(SceneTexturesStruct_SceneDepthTexture,  SceneTexturesStruct_PointClampSampler , ScreenUV, 0).r);

}

float ConvertFromDeviceZ(float DeviceZ)
{
	return DeviceZ * View_InvDeviceZToWorldZTransform[0] + View_InvDeviceZToWorldZTransform[1] + 1.0f / (DeviceZ * View_InvDeviceZToWorldZTransform[2] - View_InvDeviceZToWorldZTransform[3]);
}

FDerivedParams GetDerivedParams(in FInputParams Input, in float SceneDepth)
{
	FDerivedParams Out;
	float2 ClipPosition = Input.ScreenPosition.xy / Input.ScreenPosition.w * (View_ViewToClip[3][3] < 1.0f ? SceneDepth : 1.0f);
	Out.TranslatedWorldPosition = mul(float4(ClipPosition, SceneDepth, 1), View_ScreenToTranslatedWorld).xyz;
	Out.CameraVector = normalize(Out.TranslatedWorldPosition - View_TranslatedWorldCameraOrigin);
	return Out;
}
void DeferredLightPixelMain(

	float4 InScreenPosition : TEXCOORD0,
	float4 SVPos : SV_POSITION,
	out float4 OutColor : SV_Target0
	)
{
    FInputParams InputParams = (FInputParams)0;
	InputParams.PixelPos = SVPos.xy;

	InputParams.ScreenPosition = InScreenPosition;
	InputParams.ScreenUV = InScreenPosition.xy / InScreenPosition.w *View_ScreenPositionScaleBias.xy + View_ScreenPositionScaleBias.wz;
	InputParams.ScreenVector = 0;
    FScreenSpaceData ScreenSpaceData = GetScreenSpaceData(InputParams.ScreenUV);
	[branch]  if (ScreenSpaceData.GBuffer.ShadingModelID > 0)
	{
		const float SceneDepth = CalcSceneDepth(InputParams.ScreenUV);
		const FDerivedParams DerivedParams = GetDerivedParams(InputParams, SceneDepth);
		FDeferredLightData LightData = SetupLightDataForStandardDeferred();
		UpdateLightDataColor(LightData, InputParams, DerivedParams);
		float Dither = InterleavedGradientNoise(InputParams.PixelPos, View_StateFrameIndexMod8);
		float SurfaceShadow = 1.0f;
		float4 LightAttenuation = GetLightAttenuationFromShadow(InputParams, SceneDepth);
		float4 Radiance = GetDynamicLighting(DerivedParams.TranslatedWorldPosition, DerivedParams.CameraVector, ScreenSpaceData.GBuffer, ScreenSpaceData.AmbientOcclusion, ScreenSpaceData.GBuffer.ShadingModelID, LightData, LightAttenuation, Dither, uint2(InputParams.PixelPos), SurfaceShadow);
		OutColor += Radiance;
	}

    OutColor.rgba *= GetExposure();
}

FScreenSpaceData GetScreenSpaceData(float2 UV, bool bGetNormalizedNormal = true)
{
	FScreenSpaceData Out;

	Out.GBuffer = GetGBufferData(UV, bGetNormalizedNormal);
	float4 ScreenSpaceAO = Texture2DSampleLevel(SceneTexturesStruct_ScreenSpaceAOTexture,  SceneTexturesStruct_PointClampSampler , UV, 0);

	Out.AmbientOcclusion = ScreenSpaceAO.r;

	return Out;
}

FGBufferData GetGBufferData(float2 UV, bool bGetNormalizedNormal = true)
{

	return DecodeGBufferDataUV(UV,bGetNormalizedNormal);
}

FGBufferData DecodeGBufferDataUV(float2 UV, bool bGetNormalizedNormal = true)
{
	float CustomNativeDepth = Texture2DSampleLevel(SceneTexturesStruct_CustomDepthTexture,  SceneTexturesStruct_PointClampSampler , UV, 0).r;
	int2 IntUV = (int2)trunc(UV * View_BufferSizeAndInvSize.xy * View_BufferToSceneTextureScale.xy);
	uint CustomStencil = SceneTexturesStruct_CustomStencilTexture.Load(int3(IntUV, 0))  .g ;
	float SceneDepth = CalcSceneDepth(UV);
	float4 AnisotropicData = Texture2DSampleLevel(SceneTexturesStruct_GBufferFTexture,  SceneTexturesStruct_PointClampSampler , UV, 0).xyzw;

	float4 InMRT1 = Texture2DSampleLevel(SceneTexturesStruct_GBufferATexture,  SceneTexturesStruct_PointClampSampler , UV, 0).xyzw;
	float4 InMRT2 = Texture2DSampleLevel(SceneTexturesStruct_GBufferBTexture,  SceneTexturesStruct_PointClampSampler , UV, 0).xyzw;
	float4 InMRT3 = Texture2DSampleLevel(SceneTexturesStruct_GBufferCTexture,  SceneTexturesStruct_PointClampSampler , UV, 0).xyzw;
	float4 InMRT4 = Texture2DSampleLevel(SceneTexturesStruct_GBufferVelocityTexture,  SceneTexturesStruct_PointClampSampler , UV, 0).xyzw;
	float4 InMRT5 = Texture2DSampleLevel(SceneTexturesStruct_GBufferDTexture,  SceneTexturesStruct_PointClampSampler , UV, 0).xyzw;
	float4 InMRT6 = Texture2DSampleLevel(SceneTexturesStruct_GBufferETexture,  SceneTexturesStruct_PointClampSampler , UV, 0).xyzw;

	FGBufferData Ret = DecodeGBufferDataDirect(InMRT1,
		InMRT2,
		InMRT3,
		InMRT4,
		InMRT5,
		InMRT6,

		CustomNativeDepth,
		AnisotropicData,
		CustomStencil,
		SceneDepth,
		bGetNormalizedNormal,
		CheckerFromSceneColorUV(UV));

	return Ret;
}

FDeferredLightData SetupLightDataForStandardDeferred()
{
	FDeferredLightData LightData;
	LightData.TranslatedWorldPosition = GetDeferredLightTranslatedWorldPosition();
	LightData.InvRadius = DeferredLightUniforms_InvRadius;
	LightData.Color = DeferredLightUniforms_Color;
	LightData.FalloffExponent = DeferredLightUniforms_FalloffExponent;
	LightData.Direction = DeferredLightUniforms_Direction;
	LightData.Tangent = DeferredLightUniforms_Tangent;
	LightData.SpotAngles = DeferredLightUniforms_SpotAngles;
	LightData.SourceRadius = DeferredLightUniforms_SourceRadius;
	LightData.SourceLength =  1  > 0 ? DeferredLightUniforms_SourceLength : 0;
    LightData.SoftSourceRadius = DeferredLightUniforms_SoftSourceRadius;
	LightData.SpecularScale = DeferredLightUniforms_SpecularScale;
	LightData.ContactShadowLength = abs(DeferredLightUniforms_ContactShadowLength);
	LightData.ContactShadowLengthInWS = DeferredLightUniforms_ContactShadowLength < 0.0f;
	LightData.ContactShadowNonShadowCastingIntensity = DeferredLightUniforms_ContactShadowNonShadowCastingIntensity;
	LightData.DistanceFadeMAD = DeferredLightUniforms_DistanceFadeMAD;
	LightData.ShadowMapChannelMask = DeferredLightUniforms_ShadowMapChannelMask;
	LightData.ShadowedBits = DeferredLightUniforms_ShadowedBits;
	LightData.bInverseSquared =  1  > 0 && DeferredLightUniforms_FalloffExponent == 0;
	LightData.bRadialLight =  1  > 0;

	LightData.bSpotLight =  1  > 0;
	LightData.bRectLight =  1  == 2;

	LightData.RectLightBarnCosAngle = DeferredLightUniforms_RectLightBarnCosAngle;
	LightData.RectLightBarnLength = DeferredLightUniforms_RectLightBarnLength;
	LightData.RectLightAtlasMaxLevel = DeferredLightUniforms_RectLightAtlasMaxLevel;
	LightData.RectLightAtlasUVOffset = DeferredLightUniforms_RectLightAtlasUVOffset;
	LightData.RectLightAtlasUVScale = DeferredLightUniforms_RectLightAtlasUVScale;

	LightData.HairTransmittance = InitHairTransmittanceData();
	return LightData;
}

FGBufferData DecodeGBufferDataDirect(float4 InMRT1,
	float4 InMRT2,
	float4 InMRT3,
	float4 InMRT4,
	float4 InMRT5,
	float4 InMRT6,

	float CustomNativeDepth,
	float4 AnisotropicData,
	uint CustomStencil,
	float SceneDepth,
	bool bGetNormalizedNormal,
	bool bChecker)
{
	FGBufferData Ret = (FGBufferData)0;
	float3 WorldNormal_Compressed = 0.0f;
	WorldNormal_Compressed.x = InMRT1.x;
	WorldNormal_Compressed.y = InMRT1.y;
	WorldNormal_Compressed.z = InMRT1.z;
	Ret.PerObjectGBufferData.x = InMRT1.w;
	Ret.Metallic.x = InMRT2.x;
	Ret.Specular.x = InMRT2.y;
	Ret.Roughness.x = InMRT2.z;
	Ret.ShadingModelID.x = (((uint((float(InMRT2.w) * 255.0f) + .5f) >> 0) & 0x0f) << 0);
	Ret.SelectiveOutputMask.x = (((uint((float(InMRT2.w) * 255.0f) + .5f) >> 4) & 0x0f) << 0);
	Ret.BaseColor.x = InMRT3.x;
	Ret.BaseColor.y = InMRT3.y;
	Ret.BaseColor.z = InMRT3.z;
	Ret.GenericAO.x = InMRT3.w;
	Ret.Velocity.x = InMRT4.x;
	Ret.Velocity.y = InMRT4.y;
	Ret.Velocity.z = InMRT4.z;
	Ret.Velocity.w = InMRT4.w;
	Ret.PrecomputedShadowFactors.x = InMRT6.x;
	Ret.PrecomputedShadowFactors.y = InMRT6.y;
	Ret.PrecomputedShadowFactors.z = InMRT6.z;
	Ret.PrecomputedShadowFactors.w = InMRT6.w;
	Ret.CustomData.x = InMRT5.x;
	Ret.CustomData.y = InMRT5.y;
	Ret.CustomData.z = InMRT5.z;
	Ret.CustomData.w = InMRT5.w;

	Ret.WorldNormal = DecodeNormalHelper(WorldNormal_Compressed);
	Ret.WorldTangent = AnisotropicData.xyz;
	Ret.Anisotropy = AnisotropicData.w;

	GBufferPostDecode(Ret,bChecker,bGetNormalizedNormal);

	Ret.CustomDepth = ConvertFromDeviceZ(CustomNativeDepth);
	Ret.CustomStencil = CustomStencil;
	Ret.Depth = SceneDepth;


	return Ret;
}
FLightAccumulator AccumulateDynamicLighting(
	float3 TranslatedWorldPosition,  float3  CameraVector, FGBufferData GBuffer,  float  AmbientOcclusion, uint ShadingModelID,
	FDeferredLightData LightData,  float4  LightAttenuation, float Dither, uint2 SVPos,
	inout float SurfaceShadow)
{
	FLightAccumulator LightAccumulator = (FLightAccumulator)0;

	float3  V = -CameraVector;
	float3  N = GBuffer.WorldNormal;
	[branch]  if( GBuffer.ShadingModelID ==  4  &&  0 )
	{
		const float2 oct1 = ((float2(GBuffer.CustomData.a, GBuffer.CustomData.z) * 4) - (512.0/255.0)) + UnitVectorToOctahedron(GBuffer.WorldNormal);
		N = OctahedronToUnitVector(oct1);
	}

	float3 L = LightData.Direction;
	float3 ToLight = L;
	float3 MaskedLightColor = LightData.Color;
	float LightMask = 1;
	if (LightData.bRadialLight)
	{
		LightMask = GetLocalLightAttenuation( TranslatedWorldPosition, LightData, ToLight, L );
		MaskedLightColor *= LightMask;
	}

	LightAccumulator.EstimatedCost += 0.3f;

	[branch]
	if( LightMask > 0 )
	{
		FShadowTerms Shadow;
		Shadow.SurfaceShadow = AmbientOcclusion;
		Shadow.TransmissionShadow = 1;
		Shadow.TransmissionThickness = 1;
		Shadow.HairTransmittance.OpaqueVisibility = 1;
		const float ContactShadowOpacity = GBuffer.CustomData.a;
		GetShadowTerms(GBuffer.Depth, GBuffer.PrecomputedShadowFactors, GBuffer.ShadingModelID, ContactShadowOpacity,
			LightData, TranslatedWorldPosition, L, LightAttenuation, Dither, Shadow);
		SurfaceShadow = Shadow.SurfaceShadow;
		LightAccumulator.EstimatedCost += 0.3f;
		[branch]
		if( Shadow.SurfaceShadow + Shadow.TransmissionShadow > 0 )
		{
			const bool bNeedsSeparateSubsurfaceLightAccumulation = UseSubsurfaceProfile(GBuffer.ShadingModelID);
			FDirectLighting Lighting;
			if (LightData.bRectLight)
			{
				FRect Rect = GetRect( ToLight, LightData );
				const FRectTexture SourceTexture = InitRectTexture(LightData);
				Lighting = IntegrateBxDF( GBuffer, N, V, Rect, Shadow, SourceTexture);

			}
			else
			{
				FCapsuleLight Capsule = GetCapsule( ToLight, LightData );
				Lighting = IntegrateBxDF( GBuffer, N, V, Capsule, Shadow, LightData.bInverseSquared );

			}

			Lighting.Specular *= LightData.SpecularScale;

			LightAccumulator_AddSplit( LightAccumulator, Lighting.Diffuse, Lighting.Specular, Lighting.Diffuse, MaskedLightColor * Shadow.SurfaceShadow, bNeedsSeparateSubsurfaceLightAccumulation );
			LightAccumulator_AddSplit( LightAccumulator, Lighting.Transmission, 0.0f, Lighting.Transmission, MaskedLightColor * Shadow.TransmissionShadow, bNeedsSeparateSubsurfaceLightAccumulation );

			LightAccumulator.EstimatedCost += 0.4f;

		}

	}
	return LightAccumulator;
}
FCapsuleLight GetCapsule( float3 ToLight, FDeferredLightData LightData )
{
	FCapsuleLight Capsule;
	Capsule.Length = LightData.SourceLength;
	Capsule.Radius = LightData.SourceRadius;
	Capsule.SoftRadius = LightData.SoftSourceRadius;
	Capsule.DistBiasSqr = 1;
	Capsule.LightPos[0] = ToLight - 0.5 * Capsule.Length * LightData.Tangent;
	Capsule.LightPos[1] = ToLight + 0.5 * Capsule.Length * LightData.Tangent;
	return Capsule;
}
FDirectLighting IntegrateBxDF( FGBufferData GBuffer,  float3  N,  float3  V, FCapsuleLight Capsule, FShadowTerms Shadow, bool bInverseSquared )
{
	GBuffer.Roughness = max( GBuffer.Roughness, View_MinRoughness );
	FAreaLightIntegrateContext Context = CreateCapsuleIntegrateContext(GBuffer.Roughness, N, V, Capsule, bInverseSquared);
	return IntegrateBxDF( GBuffer, N, V, Context.L, Context.Falloff, Context.NoL, Context.AreaLight, Shadow );
}

FAreaLightIntegrateContext CreateCapsuleIntegrateContext(float Roughness,  float3  N,  float3  V, FCapsuleLight Capsule, bool bInverseSquared )
{
	FAreaLightIntegrateContext Out = InitAreaLightIntegrateContext();

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

		float3 L = Capsule.LightPos[0] * rsqrt( DistSqr );
		NoL = dot( N, L );
	}

	if( Capsule.Radius > 0 )
	{

		float SinAlphaSqr = saturate( Pow2( Capsule.Radius ) * Falloff );
		NoL = SphereHorizonCosWrap( NoL, SinAlphaSqr );
	}

	NoL = saturate( NoL );
	Falloff = bInverseSquared ? Falloff : 1;

	float3 ToLight = Capsule.LightPos[0];
	if( Capsule.Length > 0 )
	{
		float3 R = reflect( -V, N );
		ToLight = ClosestPointLineToRay( Capsule.LightPos[0], Capsule.LightPos[1], Capsule.Length, R );
	}

	float DistSqr = dot( ToLight, ToLight );
	float InvDist = rsqrt( DistSqr );
	float3 L = ToLight * InvDist;

	Roughness = max( Roughness, View_MinRoughness );
	float a = Pow2( Roughness );
	const float SizeFadesOutDiffuseMicroRefl = 20.0;
	Out.AreaLight.SphereSinAlpha = saturate( Capsule.Radius * InvDist * (1 - a) );
	Out.AreaLight.SphereSinAlphaSoft = saturate( Capsule.SoftRadius * InvDist );
	Out.AreaLight.LineCosSubtended = LineCosSubtended;
	Out.AreaLight.FalloffColor = 1;
	Out.AreaLight.Rect = (FRect)0;
	Out.AreaLight.Texture = InitRectTexture();
	Out.AreaLight.IsRectAndDiffuseMicroReflWeight = 0;
	SetIsRectLight(Out.AreaLight, false);
	SetAreaLightDiffuseMicroReflWeight(Out.AreaLight, saturate(1.0f - max(Capsule.Length, Capsule.Radius) / SizeFadesOutDiffuseMicroRefl));
	Out.NoL = NoL;
	Out.Falloff = Falloff;
	Out.L = L;
	return Out;
}
FDirectLighting IntegrateBxDF( FGBufferData GBuffer,  float3  N,  float3  V,  float3  L, float Falloff,  float  NoL, FAreaLight AreaLight, FShadowTerms Shadow )
{
	switch( GBuffer.ShadingModelID )
	{
		case  1 :
		case  10 :
		case  11 :
			return DefaultLitBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
		case  2 :
			return SubsurfaceBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
		case  3 :
			return PreintegratedSkinBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
		case  4 :
			return ClearCoatBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
		case  5 :
			return SubsurfaceProfileBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
		case  6 :
			return TwoSidedBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
		case  7 :
			return HairBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
		case  8 :
			return ClothBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
		case  9 :
			return EyeBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
		default:
			return (FDirectLighting)0;
	}
}

FDirectLighting DefaultLitBxDF( FGBufferData GBuffer,  float3  N,  float3  V,  float3  L, float Falloff,  float  NoL, FAreaLight AreaLight, FShadowTerms Shadow )
{
	BxDFContext Context;
	FDirectLighting Lighting;
    bool bHasAnisotropy = false;
	float NoV, VoH, NoH;
	[branch]
	if (bHasAnisotropy)
	{
		float3  X = GBuffer.WorldTangent;
		float3  Y = normalize(cross(N, X));
		Init(Context, N, X, Y, V, L);

		NoV = Context.NoV;
		VoH = Context.VoH;
		NoH = Context.NoH;
	}
	else
	{
		Init(Context, N, V, L);
		NoV = Context.NoV;
		VoH = Context.VoH;
		NoH = Context.NoH;

		SphereMaxNoH(Context, AreaLight.SphereSinAlpha, true);
	}

	Context.NoV = saturate(abs( Context.NoV ) + 1e-5);
	Lighting.Diffuse = Diffuse_Lambert(GBuffer.DiffuseColor);
	Lighting.Diffuse *= AreaLight.FalloffColor * (Falloff * NoL);
	[branch]
	if (bHasAnisotropy)
	{
		Lighting.Specular = AreaLight.FalloffColor * (Falloff * NoL) * SpecularGGX(GBuffer.Roughness, GBuffer.Anisotropy, GBuffer.SpecularColor, Context, NoL, AreaLight);
	}
	else
	{
		if( IsRectLight(AreaLight) )
		{
			Lighting.Specular = RectGGXApproxLTC(GBuffer.Roughness, GBuffer.SpecularColor, N, V, AreaLight.Rect, AreaLight.Texture);
		}
		else
		{
			Lighting.Specular = AreaLight.FalloffColor * (Falloff * NoL) * SpecularGGX(GBuffer.Roughness, GBuffer.SpecularColor, Context, NoL, AreaLight);
		}
	}
	FBxDFEnergyTermsRGB  EnergyTerms =  ComputeGGXSpecEnergyTermsRGB (GBuffer.Roughness, Context.NoV, GBuffer.SpecularColor);
	Lighting.Diffuse *= ComputeEnergyPreservation(EnergyTerms);
	Lighting.Specular *= ComputeEnergyConservation(EnergyTerms);
	Lighting.Transmission = 0;
	return Lighting;
}

float3 SpecularGGX( float Roughness, float3 SpecularColor, BxDFContext Context,  float  NoL, FAreaLight AreaLight )
{
	float a2 = Pow4( Roughness );
	float Energy = EnergyNormalization( a2, Context.VoH, AreaLight );
	float D = D_GGX( a2, Context.NoH ) * Energy;
	float Vis = Vis_SmithJointApprox( a2, Context.NoV, NoL );
	float3 F = F_Schlick( SpecularColor, Context.VoH );
	return (D * Vis) * F;

}

你可能感兴趣的:(#,UE4之灯光渲染,UE)