from jeff and tim: review of lighting impacts

(with a focus on fresnel)
also adds BRDF_GetDebugXXX methods gl side
This commit is contained in:
AzaezelX 2020-07-16 16:36:13 -05:00
parent b62ea8c701
commit ea206b48b2
6 changed files with 110 additions and 113 deletions

View file

@ -30,9 +30,14 @@
// Charles de Rousiers - Electronic Arts Frostbite
// SIGGRAPH 2014
float pow5(float x) {
float x2 = x * x;
return x2 * x2 * x;
}
float3 F_Schlick(in float3 f0, in float f90, in float u)
{
return f0 + (f90 - f0) * pow(1.f - u, 5.f);
return f0 + (f90 - f0) * pow5(1.f - u);
}
float3 F_Fresnel(float3 SpecularColor, float VoH)
@ -68,7 +73,7 @@ float Fr_DisneyDiffuse(float NdotV, float NdotL, float LdotH, float linearRoughn
return lightScatter * viewScatter * energyFactor;
}
float V_SmithGGXCorrelated(float NdotL, float NdotV, float alphaG2)
float V_SmithGGXCorrelated(float NdotL, float NdotV, float roughness)
{
// Original formulation of G_SmithGGX Correlated
// lambda_v = (-1 + sqrt(alphaG2 * (1 - NdotL2) / NdotL2 + 1)) * 0.5f;
@ -81,18 +86,32 @@ float V_SmithGGXCorrelated(float NdotL, float NdotV, float alphaG2)
//float alphaG2 = alphaG * alphaG;
// Caution: the "NdotL *" and "NdotV *" are explicitely inversed , this is not a mistake.
float Lambda_GGXV = NdotL * sqrt((-NdotV * alphaG2 + NdotV) * NdotV + alphaG2);
float Lambda_GGXL = NdotV * sqrt((-NdotL * alphaG2 + NdotL) * NdotL + alphaG2);
//float Lambda_GGXV = NdotL * sqrt((-NdotV * alphaG2 + NdotV) * NdotV + alphaG2);
//float Lambda_GGXL = NdotV * sqrt((-NdotL * alphaG2 + NdotL) * NdotL + alphaG2);
return 0.5f / (Lambda_GGXV + Lambda_GGXL);
//return 0.5f / (Lambda_GGXV + Lambda_GGXL);
float a2 = roughness * roughness;
float lambdaV = NdotL * sqrt((NdotV - a2 * NdotV) * NdotV + a2);
float lambdaL = NdotV * sqrt((NdotL - a2 * NdotL) * NdotL + a2);
float v = 0.5 / (lambdaV + lambdaL);
return v;
}
float D_GGX(float NdotH, float m2)
float D_GGX(float NdotH, float roughness)
{
// Divide by PI is apply later
//float m2 = m * m;
float f = (NdotH * m2 - NdotH) * NdotH + 1;
return m2 / (f * f);
//float f = (NdotH * m2 - NdotH) * NdotH + 1;
//return m2 / (f * f);
float oneMinusNdotHSquared = 1.0 - NdotH * NdotH;
float a = NdotH * roughness;
float k = roughness / (oneMinusNdotHSquared + a * a);
float d = k * k * M_1OVER_PI_F;
return d;
}
#endif

View file

@ -30,9 +30,14 @@
// Charles de Rousiers - Electronic Arts Frostbite
// SIGGRAPH 2014
float pow5(float x) {
float x2 = x * x;
return x2 * x2 * x;
}
vec3 F_Schlick(in vec3 f0, in float f90, in float u)
{
return f0 + (f90 - f0) * pow(1.f - u, 5.f);
return f0 + (f90 - f0) * pow5(1.f - u);
}
vec3 F_Fresnel(vec3 SpecularColor, float VoH)
@ -68,7 +73,7 @@ float Fr_DisneyDiffuse(float NdotV, float NdotL, float LdotH, float linearRoughn
return lightScatter * viewScatter * energyFactor;
}
float V_SmithGGXCorrelated(float NdotL, float NdotV, float alphaG2)
float V_SmithGGXCorrelated(float NdotL, float NdotV, float roughness)
{
// Original formulation of G_SmithGGX Correlated
// lambda_v = (-1 + sqrt(alphaG2 * (1 - NdotL2) / NdotL2 + 1)) * 0.5f;
@ -80,19 +85,24 @@ float V_SmithGGXCorrelated(float NdotL, float NdotV, float alphaG2)
// This is the optimized version
//float alphaG2 = alphaG * alphaG;
// Caution: the "NdotL *" and "NdotV *" are explicitely inversed , this is not a mistake.
float Lambda_GGXV = NdotL * sqrt((-NdotV * alphaG2 + NdotV) * NdotV + alphaG2);
float Lambda_GGXL = NdotV * sqrt((-NdotL * alphaG2 + NdotL) * NdotL + alphaG2);
float a2 = roughness * roughness;
return 0.5f / (Lambda_GGXV + Lambda_GGXL);
float lambdaV = NdotL * sqrt((NdotV - a2 * NdotV) * NdotV + a2);
float lambdaL = NdotV * sqrt((NdotL - a2 * NdotL) * NdotL + a2);
float v = 0.5f / (lambdaV + lambdaL);
return v;
}
float D_GGX(float NdotH, float m2)
float D_GGX(float NdotH, float roughness)
{
// Divide by PI is apply later
//float m2 = m * m;
float f = (NdotH * m2 - NdotH) * NdotH + 1;
return m2 / (f * f);
float oneMinusNdotHSquared = 1.0 - NdotH * NdotH;
float a = NdotH * roughness;
float k = roughness / (oneMinusNdotHSquared + a * a);
float d = k * k * M_1OVER_PI_F;
return d;
}
#endif

View file

@ -110,7 +110,7 @@ Surface createSurface(vec4 normDepth, sampler2D colorBuffer, sampler2D matInfoBu
surface.V = normalize(wsEyePos - surface.P);
surface.baseColor = gbuffer1;
const float minRoughness=1e-4;
surface.roughness = clamp(1.0 - gbuffer2.b, minRoughness, 1.0); //t3d uses smoothness, so we convert to roughness.
surface.roughness = 1.0 - (gbuffer2.b*0.8+0.1999); //t3d uses smoothness, so we convert to roughness.
surface.roughness_brdf = surface.roughness * surface.roughness;
surface.metalness = gbuffer2.a;
surface.ao = gbuffer2.g;
@ -129,7 +129,7 @@ Surface createForwardSurface(vec4 baseColor, vec3 normal, vec4 pbrProperties, in
surface.V = normalize(wsEyePos - surface.P);
surface.baseColor = baseColor;
const float minRoughness=1e-4;
surface.roughness = clamp(1.0 - pbrProperties.b, minRoughness, 1.0); //t3d uses smoothness, so we convert to roughness.
surface.roughness = 1.0 - (pbrProperties.b*0.8+0.1999); //t3d uses smoothness, so we convert to roughness.
surface.roughness_brdf = surface.roughness * surface.roughness;
surface.metalness = pbrProperties.a;
surface.ao = pbrProperties.g;
@ -162,25 +162,20 @@ SurfaceToLight createSurfaceToLight(in Surface surface, in vec3 L)
return surfaceToLight;
}
vec3 BRDF_GetSpecular(in Surface surface, in SurfaceToLight surfaceToLight)
vec3 BRDF_GetDebugSpecular(in Surface surface, in SurfaceToLight surfaceToLight)
{
float f90 = saturate(50.0 * dot(surface.f0, vec3(0.33,0.33,0.33)));
vec3 F = F_Schlick(surface.f0, f90, surfaceToLight.HdotV);
float Vis = V_SmithGGXCorrelated(surface.NdotV, surfaceToLight.NdotL, surface.roughness_brdf);
float D = D_GGX(surfaceToLight.NdotH, surface.roughness_brdf);
vec3 Fr = D * F * Vis / M_PI_F;
return Fr;
//GGX specular
vec3 F = F_Schlick(surface.f0, surface.f90, surfaceToLight.HdotV);
float Vis = V_SmithGGXCorrelated(surface.NdotV, surfaceToLight.NdotL, surface.roughness);
float D = D_GGX(surfaceToLight.NdotH, surface.roughness);
vec3 Fr = D * F * Vis;
return Fr*M_1OVER_PI_F;
}
vec3 BRDF_GetDiffuse(in Surface surface, in SurfaceToLight surfaceToLight)
vec3 BRDF_GetDebugDiffuse(in Surface surface, in SurfaceToLight surfaceToLight)
{
//getting some banding with disney method, using lambert instead - todo futher testing
float Fd = 1.0 / M_PI_F;
//energy conservation - remove this if reverting back to disney method
vec3 kD = vec3(1.0) - surface.F;
kD *= 1.0 - surface.metalness;
vec3 diffuse = kD * surface.baseColor.rgb * Fd;
return diffuse;
vec3 Fd = surface.albedo.rgb;
return Fd*M_1OVER_PI_F;
}
//attenuations functions from "moving frostbite to pbr paper"
@ -208,26 +203,31 @@ float getDistanceAtt( vec3 unormalizedLightVector , float invSqrAttRadius )
return sqr(attenuation);
}
vec3 getDirectionalLight(in Surface surface, in SurfaceToLight surfaceToLight, vec3 lightColor, float lightIntensity, float shadow)
vec3 evaluateStandardBRDF(Surface surface, SurfaceToLight surfaceToLight)
{
vec3 factor = lightColor * max(surfaceToLight.NdotL, 0) * shadow * lightIntensity;
vec3 diffuse = BRDF_GetDiffuse(surface,surfaceToLight) * factor;
vec3 spec = BRDF_GetSpecular(surface,surfaceToLight) * factor;
//lambert diffuse
vec3 Fd = surface.albedo.rgb;
//GGX specular
vec3 F = F_Schlick(surface.f0, surface.f90, surfaceToLight.HdotV);
float Vis = V_SmithGGXCorrelated(surface.NdotV, surfaceToLight.NdotL, surface.roughness);
float D = D_GGX(surfaceToLight.NdotH, surface.roughness);
vec3 Fr = D * F * Vis;
vec3 final = max(vec3(0.0f), diffuse + spec);
return final;
return (Fd + Fr) * M_1OVER_PI_F;
}
vec3 getPunctualLight(in Surface surface, in SurfaceToLight surfaceToLight, vec3 lightColor, float lightIntensity, float radius, float shadow)
vec3 getDirectionalLight(Surface surface, SurfaceToLight surfaceToLight, vec3 lightColor, float lightIntensity, float shadow)
{
vec3 factor = lightColor * max(surfaceToLight.NdotL, 0.0f) * shadow * lightIntensity;
return evaluateStandardBRDF(surface,surfaceToLight) * factor;
}
vec3 getPunctualLight(Surface surface, SurfaceToLight surfaceToLight, vec3 lightColor, float lightIntensity, float radius, float shadow)
{
float attenuation = getDistanceAtt(surfaceToLight.Lu, radius);
vec3 factor = lightColor * max(surfaceToLight.NdotL, 0) * shadow * lightIntensity * attenuation;
vec3 diffuse = BRDF_GetDiffuse(surface,surfaceToLight) * factor;
vec3 spec = BRDF_GetSpecular(surface,surfaceToLight) * factor;
vec3 final = max(vec3(0.0f), diffuse + spec * surface.F);
return final;
vec3 factor = lightColor * max(surfaceToLight.NdotL, 0.0f) * shadow * lightIntensity * attenuation;
return evaluateStandardBRDF(surface,surfaceToLight) * factor;
}
float computeSpecOcclusion( float NdotV , float AO , float roughness )

View file

@ -27,6 +27,7 @@
float M_HALFPI_F = 1.57079632679489661923;
float M_PI_F = 3.14159265358979323846;
float M_2PI_F = 6.28318530717958647692;
float M_1OVER_PI_F = 0.31830988618f;
/// Calculate fog based on a start and end positions in worldSpace.
float computeSceneFog( vec3 startPos,

View file

@ -114,8 +114,7 @@ inline Surface createSurface(float4 gbuffer0, TORQUE_SAMPLER2D(gbufferTex1), TOR
surface.N = mul(invView, float4(gbuffer0.xyz,0)).xyz;
surface.V = normalize(wsEyePos - surface.P);
surface.baseColor = gbuffer1;
const float minRoughness=1e-4;
surface.roughness = clamp(1.0 - gbuffer2.b, minRoughness, 1.0); //t3d uses smoothness, so we convert to roughness.
surface.roughness = 1.0 - (gbuffer2.b*0.8+0.1999); //t3d uses smoothness, so we convert to roughness.
surface.roughness_brdf = surface.roughness * surface.roughness;
surface.metalness = gbuffer2.a;
surface.ao = gbuffer2.g;
@ -134,8 +133,7 @@ inline Surface createForwardSurface(float4 baseColor, float3 normal, float4 pbrP
surface.N = normal;
surface.V = normalize(wsEyePos - surface.P);
surface.baseColor = baseColor;
const float minRoughness=1e-4;
surface.roughness = clamp(1.0 - pbrProperties.b, minRoughness, 1.0); //t3d uses smoothness, so we convert to roughness.
surface.roughness = 1.0 - (pbrProperties.b*0.8+0.1999); //t3d uses smoothness, so we convert to roughness.
surface.roughness_brdf = surface.roughness * surface.roughness;
surface.metalness = pbrProperties.a;
surface.ao = pbrProperties.g;
@ -168,57 +166,20 @@ inline SurfaceToLight createSurfaceToLight(in Surface surface, in float3 L)
return surfaceToLight;
}
float3 BRDF_GetSpecular(in Surface surface, in SurfaceToLight surfaceToLight)
{
float f90 = saturate(50.0 * dot(surface.f0, 0.33));
float3 F = F_Schlick(surface.f0, f90, surfaceToLight.HdotV);
float Vis = V_SmithGGXCorrelated(surface.NdotV, surfaceToLight.NdotL, surface.roughness_brdf);
float D = D_GGX(surfaceToLight.NdotH, surface.roughness_brdf);
float3 Fr = D * F * Vis / M_PI_F;
return Fr;
}
float3 BRDF_GetDiffuse(in Surface surface, in SurfaceToLight surfaceToLight)
{
//getting some banding with disney method, using lambert instead - todo futher testing
float Fd = 1.0 / M_PI_F;
//energy conservation - remove this if reverting back to disney method
float3 kD = 1.0.xxx - surface.F;
kD *= 1.0 - surface.metalness;
float3 diffuse = kD * surface.baseColor.rgb * Fd;
return diffuse;
}
float3 BRDF_GetDebugSpecular(in Surface surface, in SurfaceToLight surfaceToLight)
{
float3 neutralColor = float3(0.5,0.5,0.5);
float3 f0 = lerp(0.04.xxx, neutralColor, surface.metalness);
float f90 = saturate(50.0 * dot(f0, 0.33));
float3 F = F_Schlick(f0, f90, surfaceToLight.HdotV);
float Vis = V_SmithGGXCorrelated(surface.NdotV, surfaceToLight.NdotL, surface.roughness_brdf);
float D = D_GGX(surfaceToLight.NdotH, surface.roughness_brdf);
float3 Fr = D * F * Vis / M_PI_F;
return Fr;
//GGX specular
float3 F = F_Schlick(surface.f0, surface.f90, surfaceToLight.HdotV);
float Vis = V_SmithGGXCorrelated(surface.NdotV, surfaceToLight.NdotL, surface.roughness);
float D = D_GGX(surfaceToLight.NdotH, surface.roughness);
float3 Fr = D * F * Vis;
return Fr*M_1OVER_PI_F;
}
float3 BRDF_GetDebugDiffuse(in Surface surface, in SurfaceToLight surfaceToLight)
{
float3 neutralColor = float3(0.5,0.5,0.5);
//getting some banding with disney method, using lambert instead - todo futher testing
float Fd = 1.0 / M_PI_F;
float3 f0 = lerp(0.04.xxx, neutralColor, surface.metalness);
float f90 = saturate(50.0 * dot(f0, 0.33));
float3 F = F_Schlick(f0, f90, surface.NdotV);
//energy conservation - remove this if reverting back to disney method
float3 kD = 1.0.xxx - F;
kD *= 1.0 - surface.metalness;
float3 diffuse = kD * neutralColor * Fd;
return diffuse;
float3 Fd = surface.albedo.rgb;
return Fd*M_1OVER_PI_F;
}
//attenuations functions from "moving frostbite to pbr paper"
@ -246,28 +207,34 @@ float getDistanceAtt( float3 unormalizedLightVector , float invSqrAttRadius )
return sqr(attenuation);
}
inline float3 getDirectionalLight(in Surface surface, in SurfaceToLight surfaceToLight, float3 lightColor, float lightIntensity, float shadow)
float3 evaluateStandardBRDF(Surface surface, SurfaceToLight surfaceToLight)
{
float3 factor = lightColor * max(surfaceToLight.NdotL, 0) * shadow * lightIntensity;
float3 diffuse = BRDF_GetDiffuse(surface,surfaceToLight) * factor;
float3 spec = BRDF_GetSpecular(surface,surfaceToLight) * factor;
//lambert diffuse
float3 Fd = surface.albedo.rgb;
//GGX specular
float3 F = F_Schlick(surface.f0, surface.f90, surfaceToLight.HdotV);
float Vis = V_SmithGGXCorrelated(surface.NdotV, surfaceToLight.NdotL, surface.roughness);
float D = D_GGX(surfaceToLight.NdotH, surface.roughness);
float3 Fr = D * F * Vis;
float3 final = max(0.0f, diffuse + spec);
return final;
return (Fd + Fr) * M_1OVER_PI_F;
}
inline float3 getPunctualLight(in Surface surface, in SurfaceToLight surfaceToLight, float3 lightColor, float lightIntensity, float radius, float shadow)
float3 getDirectionalLight(Surface surface, SurfaceToLight surfaceToLight, float3 lightColor, float lightIntensity, float shadow)
{
float3 factor = lightColor * max(surfaceToLight.NdotL, 0.0f) * shadow * lightIntensity;
return evaluateStandardBRDF(surface,surfaceToLight) * factor;
}
float3 getPunctualLight(Surface surface, SurfaceToLight surfaceToLight, float3 lightColor, float lightIntensity, float radius, float shadow)
{
float attenuation = getDistanceAtt(surfaceToLight.Lu, radius);
float3 factor = lightColor * max(surfaceToLight.NdotL, 0) * shadow * lightIntensity * attenuation;
float3 diffuse = BRDF_GetDiffuse(surface,surfaceToLight) * factor;
float3 spec = BRDF_GetSpecular(surface,surfaceToLight) * factor;
float3 final = max(0.0f, diffuse + spec * surface.F);
return final;
float3 factor = lightColor * max(surfaceToLight.NdotL, 0.0f) * shadow * lightIntensity * attenuation;
return evaluateStandardBRDF(surface,surfaceToLight) * factor;
}
float computeSpecOcclusion( float NdotV , float AO , float roughness )
{
return saturate (pow( abs(NdotV + AO) , exp2 ( -16.0f * roughness - 1.0f )) - 1.0f + AO );

View file

@ -28,7 +28,7 @@
static float M_HALFPI_F = 1.57079632679489661923f;
static float M_PI_F = 3.14159265358979323846f;
static float M_2PI_F = 6.28318530717958647692f;
static float M_1OVER_PI_F = 0.31830988618f;
/// Calculate fog based on a start and end positions in worldSpace.
float computeSceneFog( float3 startPos,