You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Needs some clean up still. Standard deferred reflections not implemented yet. Tiled deferred reflections needs some optimization. ClearCoat and ClearCoatRoughness needs to be exposed to the material editor. [CL 2118481 by Brian Karis in Main branch]
273 lines
7.9 KiB
Plaintext
273 lines
7.9 KiB
Plaintext
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
BRDF.usf: Bidirectional reflectance distribution functions.
|
|
=============================================================================*/
|
|
|
|
#ifndef __BRDF_COMMON__
|
|
#define __BRDF_COMMON__
|
|
|
|
|
|
// Physically based shading model
|
|
// parameterized with the below options
|
|
|
|
// Microfacet specular = D*G*F / (4*NoL*NoV) = D*Vis*F
|
|
// Vis = G / (4*NoL*NoV)
|
|
|
|
// Diffuse model
|
|
// 0: Lambert
|
|
// 1: Burley
|
|
// 2: Oren-Nayar
|
|
#define PHYSICAL_DIFFUSE 0
|
|
|
|
// Microfacet distribution function
|
|
// 0: Blinn
|
|
// 1: Beckmann
|
|
// 2: GGX
|
|
#define PHYSICAL_SPEC_D 2
|
|
|
|
// Geometric attenuation or shadowing
|
|
// 0: Implicit
|
|
// 1: Neumann
|
|
// 2: Kelemen
|
|
// 3: Schlick
|
|
// 4: Smith (matched to GGX)
|
|
#define PHYSICAL_SPEC_G 3
|
|
|
|
// Fresnel
|
|
// 0: None
|
|
// 1: Schlick
|
|
// 2: Fresnel
|
|
#define PHYSICAL_SPEC_F 1
|
|
|
|
|
|
float3 Diffuse_Lambert( float3 DiffuseColor )
|
|
{
|
|
return DiffuseColor / PI;
|
|
}
|
|
|
|
// [Burley 2012, "Physically-Based Shading at Disney"]
|
|
float3 Diffuse_Burley( float3 DiffuseColor, float Roughness, float NoV, float NoL, float VoH )
|
|
{
|
|
float FD90 = 0.5 + 2 * VoH * VoH * Roughness;
|
|
float FdV = 1 + (FD90 - 1) * exp2( (-5.55473 * NoV - 6.98316) * NoV );
|
|
float FdL = 1 + (FD90 - 1) * exp2( (-5.55473 * NoL - 6.98316) * NoL );
|
|
return DiffuseColor / PI * FdV * FdL;
|
|
}
|
|
|
|
// [Gotanda 2012, "Beyond a Simple Physically Based Blinn-Phong Model in Real-Time"]
|
|
float3 Diffuse_OrenNayar( float3 DiffuseColor, float Roughness, float NoV, float NoL, float VoH )
|
|
{
|
|
float VoL = 2 * VoH - 1;
|
|
float m = Roughness * Roughness;
|
|
float m2 = m * m;
|
|
float C1 = 1 - 0.5 * m2 / (m2 + 0.33);
|
|
float Cosri = VoL - NoV * NoL;
|
|
float C2 = 0.45 * m2 / (m2 + 0.09) * Cosri * ( Cosri >= 0 ? min( 1, NoL / NoV ) : NoL );
|
|
return DiffuseColor / PI * ( NoL * C1 + C2 );
|
|
}
|
|
|
|
// [Blinn 1977, "Models of light reflection for computer synthesized pictures"]
|
|
float D_Blinn( float Roughness, float NoH )
|
|
{
|
|
float m = Roughness * Roughness;
|
|
float m2 = m * m;
|
|
float n = 2 / m2 - 2;
|
|
return (n+2) / (2*PI) * PhongShadingPow( NoH, n ); // 1 mad, 1 exp, 1 mul, 1 log
|
|
}
|
|
|
|
// [Beckmann 1963, "The scattering of electromagnetic waves from rough surfaces"]
|
|
float D_Beckmann( float Roughness, float NoH )
|
|
{
|
|
float m = Roughness * Roughness;
|
|
float m2 = m * m;
|
|
float NoH2 = NoH * NoH;
|
|
return exp( (NoH2 - 1) / (m2 * NoH2) ) / ( PI * m2 * NoH2 * NoH2 );
|
|
}
|
|
|
|
// GGX / Trowbridge-Reitz
|
|
// [Walter et al. 2007, "Microfacet models for refraction through rough surfaces"]
|
|
float D_GGX( float Roughness, float NoH )
|
|
{
|
|
float m = Roughness * Roughness;
|
|
float m2 = m * m;
|
|
float d = ( NoH * m2 - NoH ) * NoH + 1; // 2 mad
|
|
return m2 / ( PI*d*d ); // 4 mul, 1 rcp
|
|
}
|
|
|
|
// Anisotropic GGX
|
|
// [Burley 2012, "Physically-Based Shading at Disney"]
|
|
float D_GGXaniso( float RoughnessX, float RoughnessY, float NoH, float3 H, float3 X, float3 Y )
|
|
{
|
|
float mx = RoughnessX * RoughnessX;
|
|
float my = RoughnessY * RoughnessY;
|
|
float XoH = dot( X, H );
|
|
float YoH = dot( Y, H );
|
|
float d = XoH*XoH / (mx*mx) + YoH*YoH / (my*my) + NoH*NoH;
|
|
return 1 / ( PI * mx*my * d*d );
|
|
}
|
|
|
|
float Vis_Implicit()
|
|
{
|
|
return 0.25;
|
|
}
|
|
|
|
// [Neumann et al. 1999, "Compact metallic reflectance models"]
|
|
float Vis_Neumann( float NoV, float NoL )
|
|
{
|
|
return 1 / ( 4 * max( NoL, NoV ) );
|
|
}
|
|
|
|
// [Kelemen 2001, "A microfacet based coupled specular-matte brdf model with importance sampling"]
|
|
float Vis_Kelemen( float VoH )
|
|
{
|
|
return rcp( 4 * VoH * VoH );
|
|
}
|
|
|
|
// Tuned to match behavior of Vis_Smith
|
|
// [Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering"]
|
|
float Vis_Schlick( float Roughness, float NoV, float NoL )
|
|
{
|
|
float k = Square( Roughness ) * 0.5;
|
|
float Vis_SchlickV = NoV * (1 - k) + k;
|
|
float Vis_SchlickL = NoL * (1 - k) + k;
|
|
return 0.25 / ( Vis_SchlickV * Vis_SchlickL );
|
|
}
|
|
|
|
// Smith term for GGX
|
|
// [Smith 1967, "Geometrical shadowing of a random rough surface"]
|
|
float Vis_Smith( float Roughness, float NoV, float NoL )
|
|
{
|
|
float a = Square( Roughness );
|
|
float a2 = a*a;
|
|
|
|
float Vis_SmithV = NoV + sqrt( NoV * (NoV - NoV * a2) + a2 );
|
|
float Vis_SmithL = NoL + sqrt( NoL * (NoL - NoL * a2) + a2 );
|
|
return rcp( Vis_SmithV * Vis_SmithL );
|
|
}
|
|
|
|
float3 F_None( float3 SpecularColor )
|
|
{
|
|
return SpecularColor;
|
|
}
|
|
|
|
// [Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering"]
|
|
// [Lagarde 2012, "Spherical Gaussian approximation for Blinn-Phong, Phong and Fresnel"]
|
|
float3 F_Schlick( float3 SpecularColor, float VoH )
|
|
{
|
|
float Fc = pow( 1 - VoH, 5 ); // 1 sub, 3 mul
|
|
//float Fc = exp2( (-5.55473 * VoH - 6.98316) * VoH ); // 1 mad, 1 mul, 1 exp
|
|
//return Fc + (1 - Fc) * SpecularColor; // 1 add, 3 mad
|
|
|
|
// Anything less than 2% is physically impossible and is instead considered to be shadowing
|
|
return saturate( 50.0 * SpecularColor.g ) * Fc + (1 - Fc) * SpecularColor;
|
|
|
|
}
|
|
|
|
float3 F_Fresnel( float3 SpecularColor, float VoH )
|
|
{
|
|
float3 SpecularColorSqrt = sqrt( clamp( float3(0, 0, 0), float3(0.99, 0.99, 0.99), SpecularColor ) );
|
|
float3 n = ( 1 + SpecularColorSqrt ) / ( 1 - SpecularColorSqrt );
|
|
float3 g = sqrt( n*n + VoH*VoH - 1 );
|
|
return 0.5 * Square( (g - VoH) / (g + VoH) ) * ( 1 + Square( ((g+VoH)*VoH - 1) / ((g-VoH)*VoH + 1) ) );
|
|
}
|
|
|
|
|
|
float3 Diffuse( float3 DiffuseColor, float Roughness, float NoV, float NoL, float VoH )
|
|
{
|
|
#if PHYSICAL_DIFFUSE == 0
|
|
return Diffuse_Lambert( DiffuseColor );
|
|
#elif PHYSICAL_DIFFUSE == 1
|
|
return Diffuse_Burley( DiffuseColor, Roughness, NoV, NoL, VoH );
|
|
#elif PHYSICAL_DIFFUSE == 2
|
|
return Diffuse_OrenNayar( DiffuseColor, Roughness, NoV, NoL, VoH );
|
|
#endif
|
|
}
|
|
|
|
float Distribution( float Roughness, float NoH )
|
|
{
|
|
#if PHYSICAL_SPEC_D == 0
|
|
return D_Blinn( Roughness, NoH );
|
|
#elif PHYSICAL_SPEC_D == 1
|
|
return D_Beckmann( Roughness, NoH );
|
|
#elif PHYSICAL_SPEC_D == 2
|
|
return D_GGX( Roughness, NoH );
|
|
#endif
|
|
}
|
|
|
|
// Vis = G / (4*NoL*NoV)
|
|
float GeometricVisibility( float Roughness, float NoV, float NoL, float VoH )
|
|
{
|
|
#if PHYSICAL_SPEC_G == 0
|
|
return Vis_Implicit();
|
|
#elif PHYSICAL_SPEC_G == 1
|
|
return Vis_Neumann( NoV, NoL );
|
|
#elif PHYSICAL_SPEC_G == 2
|
|
return Vis_Kelemen( VoH );
|
|
#elif PHYSICAL_SPEC_G == 3
|
|
return Vis_Schlick( Roughness, NoV, NoL );
|
|
#elif PHYSICAL_SPEC_G == 4
|
|
return Vis_Smith( Roughness, NoV, NoL );
|
|
#endif
|
|
}
|
|
|
|
float3 Fresnel( float3 SpecularColor, float VoH )
|
|
{
|
|
#if PHYSICAL_SPEC_F == 0
|
|
return F_None( SpecularColor );
|
|
#elif PHYSICAL_SPEC_F == 1
|
|
return F_Schlick( SpecularColor, VoH );
|
|
#elif PHYSICAL_SPEC_F == 2
|
|
return F_Fresnel( SpecularColor, VoH );
|
|
#endif
|
|
}
|
|
|
|
|
|
//---------------
|
|
// EnvBRDF
|
|
//---------------
|
|
|
|
Texture2D PreIntegratedGF;
|
|
SamplerState PreIntegratedGFSampler;
|
|
|
|
half3 EnvBRDF( half3 SpecularColor, half Roughness, half NoV )
|
|
{
|
|
// Importance sampled preintegrated G * F
|
|
float2 AB = Texture2DSampleLevel( PreIntegratedGF, PreIntegratedGFSampler, float2( NoV, Roughness ), 0 ).rg;
|
|
|
|
// Anything less than 2% is physically impossible and is instead considered to be shadowing
|
|
float3 GF = SpecularColor * AB.x + saturate( 50.0 * SpecularColor.g ) * AB.y;
|
|
return GF;
|
|
}
|
|
|
|
half3 EnvBRDFApprox( half3 SpecularColor, half Roughness, half NoV )
|
|
{
|
|
// [ Lazarov 2013, "Getting More Physical in Call of Duty: Black Ops II" ]
|
|
// Adaptation to fit our G term.
|
|
const half4 c0 = { -1, -0.0275, -0.572, 0.022 };
|
|
const half4 c1 = { 1, 0.0425, 1.04, -0.04 };
|
|
half4 r = Roughness * c0 + c1;
|
|
half a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;
|
|
half2 AB = half2( -1.04, 1.04 ) * a004 + r.zw;
|
|
|
|
#if !ES2_PROFILE
|
|
// Anything less than 2% is physically impossible and is instead considered to be shadowing
|
|
// In ES2 this is skipped for performance as the impact can be small
|
|
// Note: this is needed for the 'specular' show flag to work, since it uses a SpecularColor of 0
|
|
AB.y *= saturate( 50.0 * SpecularColor.g );
|
|
#endif
|
|
|
|
return SpecularColor * AB.x + AB.y;
|
|
}
|
|
|
|
half EnvBRDFApproxNonmetal( half Roughness, half NoV )
|
|
{
|
|
// Same as EnvBRDFApprox( 0.04, Roughness, NoV )
|
|
const half2 c0 = { -1, -0.0275 };
|
|
const half2 c1 = { 1, 0.0425 };
|
|
half2 r = Roughness * c0 + c1;
|
|
return min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;
|
|
}
|
|
|
|
|
|
#endif // __BRDF_COMMON__ |