Pārlūkot izejas kodu

Merge pull request #252 from Azaezel/alpha40_fresnelLight

from jeff and tim: review of lighting impacts
Brian Roberts 5 gadi atpakaļ
vecāks
revīzija
ba1eb59e9f

+ 27 - 8
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);
+
+	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 0.5f / (Lambda_GGXV + Lambda_GGXL);
+	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

+ 20 - 10
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

+ 31 - 31
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;
+
+   return (Fd + Fr) * M_1OVER_PI_F;
+}
 
-   vec3 final = max(vec3(0.0f), diffuse + spec);
-   return final;
+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(in Surface surface, in SurfaceToLight surfaceToLight, vec3 lightColor, float lightIntensity, float radius, float shadow)
+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 )

+ 1 - 0
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,

+ 30 - 63
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;
+
+   return (Fd + Fr) * M_1OVER_PI_F;
+}
 
-   float3 final = max(0.0f, diffuse + spec);
-   return final;
+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;
 }
 
-inline float3 getPunctualLight(in Surface surface, in SurfaceToLight surfaceToLight, float3 lightColor, float lightIntensity, float radius, float shadow)
+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 );

+ 1 - 1
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,