You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Also FViewInfo now accumulates a mask of all lightingprofiles used in a given view during the relevancy calculation. #codereview daniel.wright,martin.mittring [CL 2505772 by Marcus Wassmer in Main branch]
574 lines
17 KiB
Plaintext
574 lines
17 KiB
Plaintext
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
PostprocessAmbient.usf: To apply a ambient cubemap as a postprocess
|
|
=============================================================================*/
|
|
|
|
#include "Common.usf"
|
|
#include "PostProcessCommon.usf"
|
|
#include "DeferredShadingCommon.usf"
|
|
#include "CubemapCommon.usf"
|
|
#include "Random.usf"
|
|
#include "BRDF.usf"
|
|
#include "MonteCarlo.usf"
|
|
|
|
#define IMPORTANCE_SAMPLE 0
|
|
|
|
float3 DiffuseIBL( uint2 Random, float3 DiffuseColor, float Roughness, float3 N, float3 V )
|
|
{
|
|
N = normalize( N );
|
|
V = normalize( V );
|
|
|
|
float3 DiffuseLighting = 0;
|
|
|
|
float NoV = saturate( dot( N, V ) );
|
|
|
|
const uint NumSamples = 32;
|
|
for( uint i = 0; i < NumSamples; i++ )
|
|
{
|
|
float2 E = Hammersley( i, NumSamples, Random );
|
|
float3 L = TangentToWorld( CosineSampleHemisphere( E ).xyz, N );
|
|
float3 H = normalize(V + L);
|
|
|
|
float NoL = saturate( dot( N, L ) );
|
|
float NoH = saturate( dot( N, H ) );
|
|
float VoH = saturate( dot( V, H ) );
|
|
|
|
if( NoL > 0 )
|
|
{
|
|
float3 SampleColor = AmbientCubemap.SampleLevel( AmbientCubemapSampler, L, 0 ).rgb;
|
|
|
|
float FD90 = ( 0.5 + 2 * VoH * VoH ) * Roughness;
|
|
//float FD90 = 0.5 + 2 * VoH * VoH * Roughness;
|
|
float FdV = 1 + (FD90 - 1) * pow( 1 - NoV, 5 );
|
|
float FdL = 1 + (FD90 - 1) * pow( 1 - NoL, 5 );
|
|
|
|
#if 1
|
|
// lambert = DiffuseColor * NoL / PI
|
|
// pdf = NoL / PI
|
|
DiffuseLighting += SampleColor * DiffuseColor * FdV * FdL * ( 1 - 0.3333 * Roughness );
|
|
#else
|
|
DiffuseLighting += SampleColor * DiffuseColor;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return DiffuseLighting / NumSamples;
|
|
}
|
|
|
|
float3 SpecularIBL( uint2 Random, float3 SpecularColor, float Roughness, float3 N, float3 V )
|
|
{
|
|
float3 SpecularLighting = 0;
|
|
|
|
const uint NumSamples = 32;
|
|
for( uint i = 0; i < NumSamples; i++ )
|
|
{
|
|
float2 E = Hammersley( i, NumSamples, Random );
|
|
float3 H = TangentToWorld( ImportanceSampleGGX( E, Roughness ).xyz, N );
|
|
float3 L = 2 * dot( V, H ) * H - V;
|
|
|
|
float NoV = saturate( dot( N, V ) );
|
|
float NoL = saturate( dot( N, L ) );
|
|
float NoH = saturate( dot( N, H ) );
|
|
float VoH = saturate( dot( V, H ) );
|
|
|
|
if( NoL > 0 )
|
|
{
|
|
float3 SampleColor = AmbientCubemap.SampleLevel( AmbientCubemapSampler, L, 0 ).rgb;
|
|
|
|
float Vis = Vis_SmithJointApprox( Roughness, NoV, NoL );
|
|
float Fc = pow( 1 - VoH, 5 );
|
|
float3 F = (1 - Fc) * SpecularColor + Fc;
|
|
|
|
// Incident light = SampleColor * NoL
|
|
// Microfacet specular = D*G*F / (4*NoL*NoV) = D*Vis*F
|
|
// pdf = D * NoH / (4 * VoH)
|
|
SpecularLighting += SampleColor * F * ( NoL * Vis * (4 * VoH / NoH) );
|
|
}
|
|
}
|
|
|
|
return SpecularLighting / NumSamples;
|
|
}
|
|
|
|
float3 StandardShading( FGBufferData GBuffer, float Roughness, float3 L, float3 V, half3 N )
|
|
{
|
|
float3 H = normalize(V + L);
|
|
float NoL = saturate( dot(N, L) );
|
|
float NoV = saturate( dot(N, V) );
|
|
float NoH = saturate( dot(N, H) );
|
|
float VoH = saturate( dot(V, H) );
|
|
|
|
// Generalized microfacet specular
|
|
float D = D_GGX( Roughness, NoH );
|
|
float Vis = Vis_SmithJointApprox( Roughness, NoV, NoL );
|
|
float3 F = F_Schlick( GBuffer.SpecularColor, VoH );
|
|
|
|
float3 Diffuse = Diffuse_Burley( GBuffer.DiffuseColor, Roughness, NoV, NoL, VoH );
|
|
|
|
return Diffuse + (D * Vis) * F;
|
|
}
|
|
|
|
float3 ClearCoatShading( FGBufferData GBuffer, float Roughness, float3 L, float3 V, half3 N )
|
|
{
|
|
const float ClearCoat = GBuffer.CustomData.x;
|
|
const float ClearCoatRoughness = GBuffer.CustomData.y;
|
|
const float Film = 1 * ClearCoat;
|
|
const float MetalSpec = 0.9;
|
|
|
|
#if 0
|
|
float3 H = normalize(V + L);
|
|
float NoL = saturate( dot(N, L) );
|
|
float NoV = saturate( dot(N, V) );
|
|
float NoH = saturate( dot(N, H) );
|
|
float VoH = saturate( dot(V, H) );
|
|
|
|
// Generalized microfacet specular
|
|
float D = D_GGX( ClearCoatRoughness, NoH );
|
|
float Vis = Vis_Kelemen( VoH );
|
|
|
|
// F_Schlick
|
|
float F0 = 0.04;
|
|
float Fc = pow( 1 - VoH, 5 );
|
|
float F = Fc + (1 - Fc) * F0;
|
|
F *= ClearCoat;
|
|
|
|
float Fr1 = D * Vis * F;
|
|
|
|
float LayerAttenuation = (1 - F);
|
|
|
|
// Generalized microfacet specular
|
|
float D2 = D_GGX( Roughness, NoH );
|
|
float Vis2 = Vis_Schlick( Roughness, NoV, NoL );
|
|
float3 F2 = saturate( 50.0 * GBuffer.SpecularColor.g ) * Fc + (1 - Fc) * GBuffer.SpecularColor;
|
|
|
|
float3 Fr2 = Diffuse_Lambert( GBuffer.DiffuseColor ) + (D2 * Vis2) * F2;
|
|
|
|
return Fr1 + Fr2 * LayerAttenuation;
|
|
#else
|
|
float3 H = normalize(V + L);
|
|
float NoL = saturate( dot(N, L) );
|
|
float NoV = saturate( dot(N, V) );
|
|
float NoH = saturate( dot(N, H) );
|
|
float VoH = saturate( dot(V, H) );
|
|
|
|
// Hard coded IOR of 1.5
|
|
|
|
// Generalized microfacet specular
|
|
float D = D_GGX( ClearCoatRoughness, NoH );
|
|
float Vis = Vis_Kelemen( VoH );
|
|
|
|
// F_Schlick
|
|
float F0 = 0.04;
|
|
float Fc = pow( 1 - VoH, 5 );
|
|
float F = Fc + (1 - Fc) * F0;
|
|
|
|
float Fr1 = D * Vis * F;
|
|
|
|
#if 1
|
|
// Refract rays
|
|
float3 L2 = refract( -L, -H, 1 / 1.5 );
|
|
float3 V2 = refract( -V, -H, 1 / 1.5 );
|
|
|
|
// LoH == VoH
|
|
float RefractBlend = sqrt( 4 * VoH*VoH + 5 ) / 3 + 2.0 / 3 * VoH;
|
|
//float3 L2 = RefractBlend * H - L / 1.5;
|
|
//float3 V2 = RefractBlend * H - V / 1.5;
|
|
|
|
float3 H2 = normalize( V2 + L2 );
|
|
float NoL2 = saturate( dot(N, L2) );
|
|
float NoV2 = saturate( dot(N, V2) );
|
|
float NoH2 = saturate( dot(N, H2) );
|
|
float VoH2 = saturate( dot(V2, H2) );
|
|
#else
|
|
// Approximation
|
|
float RefractBlend = (0.22 * VoH + 0.7) * VoH + 0.745; // 2 mad
|
|
// Dot products distribute. No need for L2 and V2.
|
|
float RefractNoH = RefractBlend * NoH; // 1 mul
|
|
float NoL2 = saturate( RefractNoH - (1 / 1.5) * NoL ); // 1 mad
|
|
float NoV2 = saturate( RefractNoH - (1 / 1.5) * NoV ); // 1 mad
|
|
// Should refract H too but unimportant
|
|
#endif
|
|
|
|
NoL2 = max( 0.001, NoL2 );
|
|
NoV2 = max( 0.001, NoV2 );
|
|
|
|
float3 AbsorptionColor = (1 - Film) + GBuffer.BaseColor * ( Film * (1 / MetalSpec) );
|
|
float AbsorptionDist = rcp(NoV2) + rcp(NoL2);
|
|
float3 Absorption = pow( AbsorptionColor, 0.5 * AbsorptionDist );
|
|
|
|
// Approximation
|
|
//float AbsorptionDist = ( NoV2 + NoL2 ) / ( NoV2 * NoL2 );
|
|
//float3 Absorption = AbsorptionColor * ( AbsorptionColor * (AbsorptionDist * 0.5 - 1) + (2 - 0.5 * AbsorptionDist) );
|
|
//float3 Absorption = AbsorptionColor + AbsorptionColor * (AbsorptionColor - 1) * (AbsorptionDist * 0.5 - 1); // use for shared version
|
|
|
|
#if 1
|
|
float F21 = F_Schlick( 0.04, saturate( dot(V2, H) ) );
|
|
|
|
float k = Square( Roughness ) * 0.5;
|
|
float G_SchlickV2 = NoV2 / ( NoV2 * (1 - k) + k );
|
|
float G_SchlickL2 = NoL2 / ( NoL2 * (1 - k) + k );
|
|
float TotalInternalReflection = 1 - F21 * G_SchlickV2 * G_SchlickL2;
|
|
float3 LayerAttenuation = ( (1 - F) * TotalInternalReflection ) * Absorption;
|
|
#else
|
|
// Approximation
|
|
float3 LayerAttenuation = (1 - F) * Absorption;
|
|
#endif
|
|
|
|
// Approximation for IOR == 1.5
|
|
//SpecularColor = ChangeBaseMedium( SpecularColor, 1.5 );
|
|
//SpecularColor = saturate( ( 0.55 * SpecularColor + (0.45 * 1.08) ) * SpecularColor - (0.45 * 0.08) );
|
|
// Treat SpecularColor as relative to IOR. Artist compensates.
|
|
|
|
// Generalized microfacet specular
|
|
#if 1
|
|
float D2 = D_GGX( Roughness, NoH2 );
|
|
float Vis2 = Vis_Schlick( Roughness, NoV2, NoL2 );
|
|
float3 F2 = F_Schlick( MetalSpec, VoH2 );
|
|
#else
|
|
// Approximation
|
|
float D2 = D_GGX( Roughness, NoH );
|
|
float Vis2 = Vis_Schlick( Roughness, NoV2, NoL2 );
|
|
float3 F2 = F_Schlick( GBuffer.SpecularColor, VoH );
|
|
#endif
|
|
|
|
float3 Fr2 = Diffuse_Lambert( GBuffer.DiffuseColor ) + (D2 * Vis2) * F2;
|
|
|
|
return Fr1 + Fr2 * LayerAttenuation;
|
|
#endif
|
|
}
|
|
|
|
|
|
float3 ImageBasedLightingMIS( FGBufferData GBuffer, float3 V, float3 N, uint2 Random )
|
|
{
|
|
float3 Lighting = 0;
|
|
|
|
float Roughness1 = GBuffer.Roughness;
|
|
float Roughness2 = 0.1;
|
|
|
|
uint NumSamples[] =
|
|
{
|
|
16,
|
|
16,
|
|
0,
|
|
};
|
|
|
|
UNROLL
|
|
for( uint Set = 0; Set < 3; Set++ )
|
|
{
|
|
LOOP
|
|
for( uint i = 0; i < NumSamples[ Set ]; i++ )
|
|
{
|
|
float2 E = Hammersley( i, NumSamples[ Set ], Random );
|
|
|
|
float3 L, H;
|
|
if( Set == 0 )
|
|
{
|
|
L = TangentToWorld( CosineSampleHemisphere( E ).xyz, N );
|
|
H = normalize(V + L);
|
|
}
|
|
else if( Set == 1 )
|
|
{
|
|
H = TangentToWorld( ImportanceSampleGGX( E, Roughness1 ).xyz, N );
|
|
L = 2 * dot( V, H ) * H - V;
|
|
}
|
|
else
|
|
{
|
|
H = TangentToWorld( ImportanceSampleGGX( E, Roughness2 ).xyz, N );
|
|
L = 2 * dot( V, H ) * H - V;
|
|
}
|
|
|
|
float NoL = saturate( dot(N, L) );
|
|
float NoH = saturate( dot(N, H) );
|
|
float VoH = saturate( dot(V, H) );
|
|
|
|
if( NoL > 0 && VoH > 0 )
|
|
{
|
|
float3 SampleColor = AmbientCubemap.SampleLevel( AmbientCubemapSampler, L, 0 ).rgb;
|
|
|
|
float PDF[] =
|
|
{
|
|
NoL / PI,
|
|
D_GGX( Roughness1, NoH ) * NoH / (4 * VoH),
|
|
D_GGX( Roughness2, NoH ) * NoH / (4 * VoH),
|
|
};
|
|
|
|
// MIS balance heuristic
|
|
float InvWeight = 0;
|
|
UNROLL for( uint j = 0; j < 3; j++ )
|
|
{
|
|
InvWeight += PDF[j] * NumSamples[j];
|
|
}
|
|
float Weight = rcp( InvWeight );
|
|
|
|
float3 Shading = 0;
|
|
#if USE_CLEARCOAT
|
|
BRANCH if( GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT )
|
|
{
|
|
Shading = ClearCoatShading( GBuffer, GBuffer.Roughness, L, V, N );
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
Shading = StandardShading( GBuffer, GBuffer.Roughness, L, V, N );
|
|
}
|
|
|
|
Lighting += SampleColor * Shading * ( NoL * Weight );
|
|
}
|
|
}
|
|
}
|
|
|
|
return Lighting;
|
|
}
|
|
|
|
float3 FilterEnvMap( uint2 Random, float Roughness, float3 N, float3 V )
|
|
{
|
|
float3 FilteredColor = 0;
|
|
float Weight = 0;
|
|
|
|
const uint NumSamples = 64;
|
|
for( uint i = 0; i < NumSamples; i++ )
|
|
{
|
|
float2 E = Hammersley( i, NumSamples, Random );
|
|
float3 H = TangentToWorld( ImportanceSampleGGX( E, Roughness ).xyz, N );
|
|
float3 L = 2 * dot( V, H ) * H - V;
|
|
|
|
float NoL = saturate( dot( N, L ) );
|
|
if( NoL > 0 )
|
|
{
|
|
FilteredColor += AmbientCubemap.SampleLevel( AmbientCubemapSampler, L, 0 ).rgb * NoL;
|
|
Weight += NoL;
|
|
}
|
|
}
|
|
|
|
return FilteredColor / max( Weight, 0.001 );
|
|
}
|
|
|
|
float3 PrefilterEnvMap( uint2 Random, float Roughness, float3 R )
|
|
{
|
|
float3 FilteredColor = 0;
|
|
float Weight = 0;
|
|
|
|
const uint NumSamples = 64;
|
|
for( uint i = 0; i < NumSamples; i++ )
|
|
{
|
|
float2 E = Hammersley( i, NumSamples, Random );
|
|
float3 H = TangentToWorld( ImportanceSampleGGX( E, Roughness ).xyz, R );
|
|
float3 L = 2 * dot( R, H ) * H - R;
|
|
|
|
float NoL = saturate( dot( R, L ) );
|
|
if( NoL > 0 )
|
|
{
|
|
FilteredColor += AmbientCubemap.SampleLevel( AmbientCubemapSampler, L, 0 ).rgb * NoL;
|
|
Weight += NoL;
|
|
}
|
|
}
|
|
|
|
return FilteredColor / max( Weight, 0.001 );
|
|
}
|
|
|
|
float3 IntegrateBRDF( uint2 Random, float Roughness, float NoV )
|
|
{
|
|
float3 V;
|
|
V.x = sqrt( 1.0f - NoV * NoV ); // sin
|
|
V.y = 0;
|
|
V.z = NoV; // cos
|
|
|
|
float A = 0;
|
|
float B = 0;
|
|
float C = 0;
|
|
|
|
const uint NumSamples = 64;
|
|
for( uint i = 0; i < NumSamples; i++ )
|
|
{
|
|
float2 E = Hammersley( i, NumSamples, Random );
|
|
|
|
{
|
|
float3 H = ImportanceSampleGGX( E, Roughness ).xyz;
|
|
float3 L = 2 * dot( V, H ) * H - V;
|
|
|
|
float NoL = saturate( L.z );
|
|
float NoH = saturate( H.z );
|
|
float VoH = saturate( dot( V, H ) );
|
|
|
|
if( NoL > 0 )
|
|
{
|
|
float Vis = Vis_SmithJointApprox( Roughness, NoV, NoL );
|
|
|
|
float a = Square( Roughness );
|
|
float a2 = a*a;
|
|
float Vis_SmithV = NoL * sqrt( NoV * (NoV - NoV * a2) + a2 );
|
|
float Vis_SmithL = NoV * sqrt( NoL * (NoL - NoL * a2) + a2 );
|
|
//float Vis = 0.5 * rcp( Vis_SmithV + Vis_SmithL );
|
|
|
|
// Incident light = NoL
|
|
// pdf = D * NoH / (4 * VoH)
|
|
// NoL * Vis / pdf
|
|
float NoL_Vis_PDF = NoL * Vis * (4 * VoH / NoH);
|
|
|
|
float Fc = pow( 1 - VoH, 5 );
|
|
A += (1 - Fc) * NoL_Vis_PDF;
|
|
B += Fc * NoL_Vis_PDF;
|
|
}
|
|
}
|
|
|
|
{
|
|
float3 L = CosineSampleHemisphere( E ).xyz;
|
|
float3 H = normalize(V + L);
|
|
|
|
float NoL = saturate( L.z );
|
|
float NoH = saturate( H.z );
|
|
float VoH = saturate( dot( V, H ) );
|
|
|
|
float FD90 = ( 0.5 + 2 * VoH * VoH ) * Roughness;
|
|
float FdV = 1 + (FD90 - 1) * pow( 1 - NoV, 5 );
|
|
float FdL = 1 + (FD90 - 1) * pow( 1 - NoL, 5 );
|
|
C += FdV * FdL * ( 1 - 0.3333 * Roughness );
|
|
}
|
|
}
|
|
|
|
return float3( A, B, C ) / NumSamples;
|
|
}
|
|
|
|
float3 ApproximateSpecularIBL( uint2 Random, float3 SpecularColor, float Roughness, float3 N, float3 V )
|
|
{
|
|
// Function replaced with prefiltered environment map sample
|
|
float3 R = 2 * dot( V, N ) * N - V;
|
|
float3 PrefilteredColor = PrefilterEnvMap( Random, Roughness, R );
|
|
//float3 PrefilteredColor = FilterEnvMap( Random, Roughness, N, V );
|
|
|
|
// Function replaced with 2D texture sample
|
|
float NoV = saturate( dot( N, V ) );
|
|
float2 AB = IntegrateBRDF( Random, Roughness, NoV );
|
|
|
|
return PrefilteredColor * ( SpecularColor * AB.x + AB.y );
|
|
}
|
|
|
|
void MainPS(in float4 UVAndScreenPos : TEXCOORD0, out float4 OutColor : SV_Target0)
|
|
{
|
|
float2 UV = UVAndScreenPos.xy;
|
|
|
|
FScreenSpaceData ScreenSpaceData = GetScreenSpaceData(UV);
|
|
FGBufferData GBuffer = ScreenSpaceData.GBuffer;
|
|
float AbsoluteDiffuseMip = AmbientCubemapMipAdjust.z;
|
|
|
|
// screen position in [-1, 1] screen space
|
|
float2 ScreenSpacePos = UVAndScreenPos.zw;
|
|
int2 PixelPos = int2(UVAndScreenPos.zw * ScreenPosToPixel.xy + ScreenPosToPixel.zw + 0.5f);
|
|
|
|
float3 ScreenVector = normalize(mul(float4(ScreenSpacePos, 1, 0), View.ScreenToWorld).xyz);
|
|
|
|
float3 N = GBuffer.WorldNormal;
|
|
float3 V = -ScreenVector;
|
|
float3 R = 2 * dot( V, N ) * N - V;
|
|
|
|
float NoV = abs( dot(N, V) ) + 1e-5;
|
|
|
|
// Point lobe in off-specular peak direction
|
|
float a = Square( GBuffer.Roughness );
|
|
R = lerp( N, R, (1 - a) * ( sqrt(1 - a) + a ) );
|
|
|
|
uint2 Random = ScrambleTEA( PixelPos );
|
|
Random.x ^= View.Random;
|
|
Random.y ^= View.Random;
|
|
|
|
float3 NonSpecularContribution = 0;
|
|
float3 SpecularContribution = 0;
|
|
|
|
#if 1
|
|
float3 RetroReflectionDir = lerp( N, V, saturate( ( NoV * (1.02341 * a - 1.51174) + -0.511705 * a + 0.755868 ) * a ) );
|
|
float3 DiffuseLookup = TextureCubeSampleLevel(AmbientCubemap, AmbientCubemapSampler, RetroReflectionDir, AbsoluteDiffuseMip).rgb;
|
|
|
|
float3 ABC = PreIntegratedGF.SampleLevel( PreIntegratedGFSampler, float2( NoV, GBuffer.Roughness ), 0 ).rgb;
|
|
//float3 ABC = IntegrateBRDF( Random, GBuffer.Roughness, NoV );
|
|
|
|
NonSpecularContribution += GBuffer.DiffuseColor * DiffuseLookup * ABC.z;
|
|
//NonSpecularContribution += DiffuseIBL( Random, GBuffer.DiffuseColor, GBuffer.Roughness, N, V );// * ABC.z;
|
|
#else
|
|
float3 DiffuseLookup = TextureCubeSampleLevel(AmbientCubemap, AmbientCubemapSampler, N, AbsoluteDiffuseMip).rgb;
|
|
NonSpecularContribution += GBuffer.DiffuseColor * DiffuseLookup;
|
|
#endif
|
|
|
|
// Diffuse
|
|
{
|
|
// we want to access the mip with the preconvolved diffuse lighting (coneangle=90 degree)
|
|
//NonSpecularContribution += GBuffer.DiffuseColor * DiffuseLookup;
|
|
}
|
|
|
|
// Specular
|
|
{
|
|
float Mip = ComputeCubemapMipFromRoughness( GBuffer.Roughness, AmbientCubemapMipAdjust.w );
|
|
float3 SampleColor = TextureCubeSampleLevel( AmbientCubemap, AmbientCubemapSampler, R, Mip ).rgb;
|
|
|
|
#if USE_CLEARCOAT
|
|
BRANCH if( GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT )
|
|
{
|
|
float ClearCoat = GBuffer.CustomData.x;
|
|
float2 AB = PreIntegratedGF.SampleLevel( PreIntegratedGFSampler, float2( NoV, GBuffer.Roughness ), 0 ).rg;
|
|
SpecularContribution += SampleColor * ( GBuffer.SpecularColor * AB.x + AB.y * (1 - ClearCoat) );
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
SpecularContribution += SampleColor * EnvBRDF( GBuffer.SpecularColor, GBuffer.Roughness, NoV );
|
|
//SpecularContribution += ApproximateSpecularIBL( Random, GBuffer.SpecularColor, GBuffer.Roughness, GBuffer.WorldNormal, -ScreenVector );
|
|
}
|
|
}
|
|
|
|
#if USE_CLEARCOAT
|
|
BRANCH if( GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT )
|
|
{
|
|
const float ClearCoat = GBuffer.CustomData.x;
|
|
const float ClearCoatRoughness = GBuffer.CustomData.y;
|
|
|
|
float Mip = ComputeCubemapMipFromRoughness( ClearCoatRoughness, AmbientCubemapMipAdjust.w );
|
|
float3 SampleColor = TextureCubeSampleLevel( AmbientCubemap, AmbientCubemapSampler, R, Mip ).rgb;
|
|
|
|
// F_Schlick
|
|
float F0 = 0.04;
|
|
float Fc = pow( 1 - NoV, 5 );
|
|
float F = Fc + (1 - Fc) * F0;
|
|
F *= ClearCoat;
|
|
|
|
float LayerAttenuation = (1 - F);
|
|
|
|
NonSpecularContribution *= LayerAttenuation;
|
|
SpecularContribution *= LayerAttenuation;
|
|
SpecularContribution += SampleColor * F;
|
|
}
|
|
#endif
|
|
|
|
#if IMPORTANCE_SAMPLE
|
|
if( GBuffer.ShadingModelID > 0 )
|
|
{
|
|
NonSpecularContribution = 0;
|
|
SpecularContribution = ImageBasedLightingMIS( GBuffer, -ScreenVector, GBuffer.WorldNormal, Random );
|
|
}
|
|
#endif
|
|
|
|
// apply darkening from ambient occlusion (does not use PostprocessInput1 to set white texture if SSAO is off)
|
|
float AmbientOcclusion = GBuffer.GBufferAO * ScreenSpaceData.AmbientOcclusion;
|
|
|
|
// Subsurface
|
|
BRANCH if(GBuffer.ShadingModelID == SHADINGMODELID_SUBSURFACE || GBuffer.ShadingModelID == SHADINGMODELID_PREINTEGRATED_SKIN)
|
|
{
|
|
// some view dependent and some non view dependent (hard coded)
|
|
float DependentSplit = 0.5f;
|
|
|
|
float3 SubsurfaceColor = ExtractSubsurfaceColor(GBuffer);
|
|
|
|
// view independent (shared lookup for diffuse for better performance
|
|
NonSpecularContribution += DiffuseLookup * SubsurfaceColor * (DependentSplit);
|
|
// view dependent (blurriness is hard coded)
|
|
SpecularContribution += TextureCubeSampleLevel(AmbientCubemap, AmbientCubemapSampler, ScreenVector, AbsoluteDiffuseMip - 2.5f).rgb * SubsurfaceColor * (AmbientOcclusion * (1.0f - DependentSplit));
|
|
}
|
|
|
|
FLightAccumulator LightAccumulator = (FLightAccumulator)0;
|
|
|
|
LightAccumulator_Add(LightAccumulator, NonSpecularContribution, SpecularContribution, AmbientCubemapColor.rgb);
|
|
|
|
OutColor = LightAccumulator_GetResult(LightAccumulator);
|
|
|
|
OutColor *= AmbientOcclusion;
|
|
}
|
|
|