diff --git a/Templates/BaseGame/game/core/rendering/shaders/brdf.hlsl b/Templates/BaseGame/game/core/rendering/shaders/brdf.hlsl index 2fb7d221a..050bf82c5 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/brdf.hlsl +++ b/Templates/BaseGame/game/core/rendering/shaders/brdf.hlsl @@ -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 diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/brdf.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/brdf.glsl index b1b054d70..b74fcc88c 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/gl/brdf.glsl +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/brdf.glsl @@ -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 diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/lighting.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/lighting.glsl index 68e30785b..7412245ce 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/gl/lighting.glsl +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/lighting.glsl @@ -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 ) diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/torque.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/torque.glsl index f542d09a8..7740ab867 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/gl/torque.glsl +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/torque.glsl @@ -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, diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting.hlsl index cfb89bf8a..9d7d4c19b 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting.hlsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting.hlsl @@ -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 ); diff --git a/Templates/BaseGame/game/core/rendering/shaders/torque.hlsl b/Templates/BaseGame/game/core/rendering/shaders/torque.hlsl index f4555ec78..27a04a093 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/torque.hlsl +++ b/Templates/BaseGame/game/core/rendering/shaders/torque.hlsl @@ -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,