UE4 RectLightIntegrate.ush

RectLightIntegrate.ush

// Copyright Epic Games, Inc. All Rights Reserved.

#define CHEAP_RECT	0

#include "DeferredShadingCommon.ush"
#include "MonteCarlo.ush"
#include "ShadingModels.ush"
#include "RectLight.ush"

float3 ClampToRect( float3 L, FRect Rect )
{
	// Bias toward plane
	//L -= Rect.Axis[2] * saturate( 0.001 + dot( Rect.Axis[2], L ) );
	//L = normalize( L );

	// Intersect ray with plane
	float3 PointOnPlane = L * ( dot( Rect.Axis[2], Rect.Origin ) / dot( Rect.Axis[2], L ) );
	//float3 PointOnPlane = L * ( dot( Rect.Axis[2], Rect.Origin ) / -saturate( 0.001 - dot( Rect.Axis[2], L ) ) );

	float2 PointInRect;
	PointInRect.x = dot( Rect.Axis[0], PointOnPlane - Rect.Origin );
	PointInRect.y = dot( Rect.Axis[1], PointOnPlane - Rect.Origin );

	// Clamp point to rect
	PointInRect = clamp( PointInRect, -Rect.Extent, Rect.Extent );

	float3 ToRect = Rect.Origin;
	ToRect += PointInRect.x * Rect.Axis[0];
	ToRect += PointInRect.y * Rect.Axis[1];

	return normalize( ToRect );
}

bool RayHitRect( float3 L, FRect Rect )
{
	// Intersect ray with plane
	float t = dot( Rect.Axis[2], Rect.Origin ) / dot( Rect.Axis[2], L );
	float3 PointOnPlane = L * t;

	bool InExtentX = abs( dot( Rect.Axis[0], PointOnPlane - Rect.Origin ) ) <= Rect.Extent.x;
	bool InExtentY = abs( dot( Rect.Axis[1], PointOnPlane - Rect.Origin ) ) <= Rect.Extent.y;

	return t >= 0 && InExtentX && InExtentY;
}

float IntegrateLight( FRect Rect, FRectTexture SourceTexture )
{
	// No visibile rect light due to barn door occlusion
	if (Rect.Extent.x == 0 || Rect.Extent.y == 0) return 0;

	float NoL;
	float Falloff;

#if 0	// Reference quality
	float3 L = RectIrradianceRef( 0, Rect, Falloff, NoL );
#elif !CHEAP_RECT	// Optimized Lambert
	float3 L = RectIrradianceLambert( 0, Rect, Falloff, NoL );
#elif 1	// Karis
	float3 L = RectIrradianceApproxKaris( 0, Rect, Falloff, NoL );
#elif 1	// Lagarde
	float3 L = RectIrradianceApproxLagarde( 0, Rect, Falloff, NoL );
#else	// Drobot
	float3 L = RectIrradianceApproxDrobot( 0, Rect, Falloff, NoL );
#endif

	float3 FalloffColor = SampleSourceTexture( L, Rect, SourceTexture);
	
	return Falloff;
}

FDirectLighting IntegrateBxDF( FGBufferData GBuffer, half3 N, half3 V, FRect Rect, FShadowTerms Shadow, FRectTexture SourceTexture )
{
	float NoL;
	float Falloff;
	
	// No-visible rect light due to barn door occlusion
	if (Rect.Extent.x == 0 || Rect.Extent.y == 0) 
        return (FDirectLighting)0;

#if 0	// Reference quality
	float3 L = RectIrradianceRef( N, Rect, Falloff, NoL );
#elif !CHEAP_RECT	// Optimized Lambert
	float3 L = RectIrradianceLambert( N, Rect, Falloff, NoL );
#elif 1	// Karis
	float3 L = RectIrradianceApproxKaris( N, Rect, Falloff, NoL );
#elif 1	// Lagarde
	float3 L = RectIrradianceApproxLagarde( N, Rect, Falloff, NoL );
#else	// Drobot
	float3 L = RectIrradianceApproxDrobot( N, Rect, Falloff, NoL );
#endif

	float3 FalloffColor = SampleSourceTexture( L, Rect, SourceTexture );

#if CHEAP_RECT
	float3 R = reflect( -V, N );

#if 0
	float NoV = saturate( dot( N, V ) );

	L = lerp( L, R, saturate( -2*dot( Rect.Axis[2], R ) ) );
	L = normalize( L );

	UNROLL
	for( int k = 0; k < 2; k++ )
	{
#if 1
		float NoL = dot( N, L );
		float NoV = dot( N, V );
		float VoL = dot( V, L );
		float NoHInvLenH = ( NoL + NoV ) / ( 2 + 2*VoL );
		float3 Gradient = ( ( N - L*NoL ) - ( V - L*VoL ) * NoHInvLenH ) * (2*NoHInvLenH);
#else
		float RoL = dot( R, L );
		float3 Gradient = 2 * RoL * ( R - L * RoL );
#endif

		Gradient -= Rect.Axis[2] * dot( Rect.Axis[2], Gradient );
		Gradient = lerp( Gradient, 0, (1 - NoV) * saturate( 2*dot( Rect.Axis[2], L ) ) );

		L = ClampToRect( L + Gradient * ( 2.0 / ( 2.0 + k ) ), Rect );
	}
#elif 1
	float3 Ls = L;

	float3 v[4];
	v[0] = Rect.Origin - Rect.Axis[0] * Rect.Extent.x - Rect.Axis[1] * Rect.Extent.y;
	v[1] = Rect.Origin + Rect.Axis[0] * Rect.Extent.x - Rect.Axis[1] * Rect.Extent.y;
	v[2] = Rect.Origin + Rect.Axis[0] * Rect.Extent.x + Rect.Axis[1] * Rect.Extent.y;
	v[3] = Rect.Origin - Rect.Axis[0] * Rect.Extent.x + Rect.Axis[1] * Rect.Extent.y;

	float3 e0 = v[0];
	float3 e1 = v[1];

	float3 MinEdgeN = 0;
	float  MinEdgeCos = 1;

	UNROLL
	for( uint i = 0; i < 4; i++ )
	{
		float3 v0 = v[i];
		float3 v1 = v[ (i+1) % 4 ];

		float3 EdgeN = normalize( cross( v0, v1 ) );
		float  EdgeCos = dot( R, EdgeN );

		if( EdgeCos < MinEdgeCos )
		{
			MinEdgeN   = EdgeN;
			MinEdgeCos = EdgeCos;

			e0 = v0;
			e1 = v1;
		}
	}

	if( MinEdgeCos > 0 )
	{
		Ls = R;
	}
	else
	{
#if 0
		Ls = SmallestAnglePointOnLineToRay( e0, e1, length( e0 - e1 ), R );
#else
		float3 Rp = R - MinEdgeCos * MinEdgeN;
		if(		dot( cross( Rp, e0 ), R ) < 0 )	Ls = e0;
		else if(dot( cross( e1, Rp ), R ) < 0 )	Ls = e1;
		else									Ls = Rp;
#endif
		Ls = normalize( Ls );
	}

	float a = Pow2( GBuffer.Roughness );
	//L = lerp( Ls, L, a );
	L = normalize( Ls );
#else
	L = R;
	if( !RayHitRect( R, Rect ) )
	{
		float3 MaxL = R;
		float  MaxNoH = -1;

		uint NumSteps = 128;
		for( uint i = 0; i < NumSteps; i++ )
		{
			float Theta = (2*PI) * i / (float)NumSteps;
			float2 p;
			p.x = cos( Theta );
			p.y = sin( Theta );

			p.xy /= dot( 1, abs(p) );
			float2 PointInRect = float2( p.x + p.y, p.x - p.y ) * Rect.Extent;

			//0.5 * sqrt( 2 + (2*sqrt(2.0)) * 

			float3 ToRect = Rect.Origin;
			ToRect += PointInRect.x * Rect.Axis[0];
			ToRect += PointInRect.y * Rect.Axis[1];

			L = normalize( ToRect );
			
			float RoL = dot( R, L );

			BxDFContext Context;
			Context.Init( N, V, L );

			if( Context.NoH > MaxNoH )
			{
				MaxNoH = Context.NoH;
				MaxL = L;
			}
		}

		L = MaxL;
	}

	for( int k = 0; k < 0; k++ )
	{
		float NoL = dot( N, L );
		float NoV = dot( N, V );
		float VoL = dot( V, L );
		float NoHInvLenH = ( NoL + NoV ) / ( 2 + 2*VoL );
		float3 Gradient = ( ( N - L*NoL ) - ( V - L*VoL ) * NoHInvLenH ) * (2*NoHInvLenH);

		L = ClampToRect( L + Gradient * ( 2.0 / ( 2.0 + k ) ), Rect );
	}
#endif
	
	GBuffer.Roughness = max( GBuffer.Roughness, 0.02 );

	FAreaLight AreaLight;
	AreaLight.SphereSinAlpha = sqrt( Falloff * (1.0 / PI) );
	AreaLight.SphereSinAlphaSoft = 0;
	AreaLight.LineCosSubtended = 1;
	AreaLight.FalloffColor = 1;
	AreaLight.Rect = Rect;
	AreaLight.Texture = SourceTexture;
	AreaLight.bIsRect = false;
#else
	FAreaLight AreaLight;
	AreaLight.SphereSinAlpha = 0;
	AreaLight.SphereSinAlphaSoft = 0;
	AreaLight.LineCosSubtended = 1;
	AreaLight.FalloffColor = FalloffColor;
	AreaLight.Rect = Rect;
	AreaLight.Texture = SourceTexture;
	AreaLight.bIsRect = true;
#endif

	return IntegrateBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值