Divergent/mods/Screen Space Shaders/gamedata/shaders/r3/pbr_brdf_ggx.h

124 lines
4.0 KiB
C

float D_GGX(float NdotH, float a2)
{
float denominator = (NdotH * a2 - NdotH) * NdotH + 1.0;
return a2 / (PI * denominator * denominator);
}
float Lambda_Smith(float NdotX, float a)
{
float a2 = a * a;
float NdotX_2 = NdotX * NdotX;
return (-1.0 + sqrt(a2 * (1.0 - NdotX_2) / NdotX_2 + 1.0)) * 0.5;
}
//Height Correlated Masking-shadowing function
float G2_Smith_Correlated(float NdotL, float NdotV, float a)
{
float lambdaV = Lambda_Smith(NdotV, a);
float lambdaL = Lambda_Smith(NdotL, a);
return 1.0 / (1.0 + lambdaV + lambdaL);
}
float G2_SmithJointApprox(float NdotL, float NdotV, float a)
{
float Vis_V = NdotL * ( NdotV * ( 1 - a ) + a );
float Vis_L = NdotV * ( NdotL * ( 1 - a ) + a );
return 0.5 * rcp( Vis_V + Vis_L );
}
float3 Lit_GGX(float NdotL, float NdotH, float NdotV, float VdotH, float3 F0, float rough)
{
//Alpha
float a = rough * rough;
float a2 = a * a;
//Normal distribution function
float D = D_GGX(NdotH, a2);
//Masking-shadowing
//float V = G2_Smith_Correlated(NdotL, NdotV, a);
float V = G2_SmithJointApprox(NdotL, NdotV, a); //denom included?
//Fresnel
float3 f90Atten = saturate(50*F0); //UE4 specular shadowing
float3 F = F_Shlick(F0, f90Atten, VdotH);
//Numerator
float3 numerator = (D * V) * F;
//Denominator
//float denominator = 4.0 * NdotV;
return numerator; //UE4 has no denom
//return numerator / denominator;
}
//UE4 mobile approx
float2 EnvBRDFApprox(float Roughness, float NoV )
{
const float4 c0 = { -1, -0.0275, -0.572, 0.022 };
const float4 c1 = { 1, 0.0425, 1.04, -0.04 };
float4 r = Roughness * c0 + c1;
float a004 = min(r.x * r.x, exp2(-9.28 * NoV ) ) * r.x + r.y;
float2 AB = float2(-1.04, 1.04 ) * a004 + r.zw;
return AB;
}
//-------------------------------------------------------------------------------------------------
// Returns scale and bias values for environment specular reflections that represents the
// integral of the geometry/visibility + fresnel terms for a GGX BRDF given a particular
// viewing angle and roughness value. The final value is computed using polynomials that were
// fitted to tabulated data generated via monte carlo integration.
//-------------------------------------------------------------------------------------------------
float2 GGXEnvironmentBRDFScaleBias(float roughness, float nDotV)
{
const float sqrtRoughness = sqrt(roughness);
const float nDotV2 = nDotV * nDotV;
const float sqrtRoughness2 = sqrtRoughness * sqrtRoughness;
const float sqrtRoughness3 = sqrtRoughness2 * sqrtRoughness;
const float delta = 0.991086418474895f + (0.412367709802119f * sqrtRoughness * nDotV2) -
(0.363848256078895f * sqrtRoughness2) -
(0.758634385642633f * nDotV * sqrtRoughness2);
const float bias = saturate((0.0306613448029984f * sqrtRoughness) + 0.0238299731830387f /
(0.0272458171384516f + sqrtRoughness3 + nDotV2) -
0.0454747751719356f);
const float scale = saturate(delta - bias);
return float2(scale, bias);
}
//LVutner ambient BRDF
float2 integrate_brdf(float roughness, float NV)
{
//Schlick's approximation
float F_partial = pow(1.0 - NV, 5.0);
//GGX
const float4 c0 = float4(-1.0, -0.0275, -0.26, 0.0109);
const float4 c1 = float4(1.0, 0.0455, 1.0417, -0.0417);
float4 r = roughness * c0 + c1;
float a004 = min(0.9 - 0.75 * roughness, F_partial) * r.x + r.y;
float2 AB = float2(-1.0417, 1.0417) * a004 + r.zw;
//Output (Scale, Bias, Burley)
return float2(AB.x, AB.y);
}
float3 EnvGGX(float3 f0, float rough, float nDotV )
{
//UE4 GGX
float3 f90Atten = saturate(50*f0); //UE4 specular shadowing
float2 AB = EnvBRDFApprox(rough, nDotV);
//Matt Pettineo GGX
//float2 AB = GGXEnvironmentBRDFScaleBias(rough, nDotV);
//LVutner GGX
//float2 AB = integrate_brdf(rough, nDotV);
return (f0 * AB.x + AB.y * f90Atten);
}