mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-02-05 12:31:01 +00:00
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:
parent
b62ea8c701
commit
ea206b48b2
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in a new issue