PBR attenuation fix with proper Fresnel adjustments.

This commit is contained in:
Joey de Vries
2017-01-09 19:57:53 +01:00
parent 5042701210
commit 96ced3c198
4 changed files with 32 additions and 42 deletions

View File

@@ -95,10 +95,10 @@ int main()
glm::vec3( 10.0f, -10.0f, 10.0f), glm::vec3( 10.0f, -10.0f, 10.0f),
}; };
glm::vec3 lightColors[] = { glm::vec3 lightColors[] = {
glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(300.0f, 300.0f, 300.0f),
glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(300.0f, 300.0f, 300.0f),
glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(300.0f, 300.0f, 300.0f),
glm::vec3(2.0f, 2.0f, 2.0f) glm::vec3(300.0f, 300.0f, 300.0f)
}; };
int nrRows = 7; int nrRows = 7;
int nrColumns = 7; int nrColumns = 7;

View File

@@ -60,11 +60,6 @@ vec3 fresnelSchlick(float cosTheta, vec3 F0)
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness)
{
return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - cosTheta, 5.0);
}
// ----------------------------------------------------------------------------
void main() void main()
{ {
vec3 N = normalize(Normal); vec3 N = normalize(Normal);
@@ -75,7 +70,26 @@ void main()
// of 0.04 and if it's a metal, use their albedo color as F0 (metallic workflow) // of 0.04 and if it's a metal, use their albedo color as F0 (metallic workflow)
vec3 F0 = vec3(0.04); vec3 F0 = vec3(0.04);
F0 = mix(F0, albedo, metallic); F0 = mix(F0, albedo, metallic);
vec3 F = fresnelSchlickRoughness(max(dot(N, V), 0.0), F0, roughness); // use modified Fresnel-Schlick approximation to take roughness into account
// reflectance equation
vec3 Lo = vec3(0.0);
for(int i = 0; i < 4; ++i)
{
// calculate per-light radiance
vec3 L = normalize(lightPositions[i] - WorldPos);
vec3 H = normalize(V + L);
float distance = length(lightPositions[i] - WorldPos);
float attenuation = 1.0 / (distance * distance);
vec3 radiance = lightColors[i] * attenuation;
// Cook-Torrance BRDF
float NDF = DistributionGGX(N, H, roughness);
float G = GeometrySmith(N, V, L, roughness);
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
vec3 nominator = NDF * G * F;
float denominator = 4 * max(dot(V, N), 0.0) * max(dot(L, N), 0.0) + 0.001; // 0.001 to prevent divide by zero.
vec3 brdf = nominator / denominator;
// kS is equal to Fresnel // kS is equal to Fresnel
vec3 kS = F; vec3 kS = F;
@@ -88,25 +102,6 @@ void main()
// have no diffuse light). // have no diffuse light).
kD *= 1.0 - metallic; kD *= 1.0 - metallic;
// reflectance equation
vec3 Lo = vec3(0.0);
for(int i = 0; i < 4; ++i)
{
// calculate per-light radiance
vec3 L = normalize(lightPositions[i] - WorldPos);
vec3 H = normalize(V + L);
float distance = length(lightPositions[i] - WorldPos);
float attenuation = 1.0 / distance * distance;
vec3 radiance = lightColors[i] * attenuation;
// Cook-Torrance BRDF
float NDF = DistributionGGX(N, H, roughness);
float G = GeometrySmith(N, V, L, roughness);
vec3 nominator = NDF * G * F;
float denominator = 4 * max(dot(V, N), 0.0) * max(dot(L, N), 0.0) + 0.001; // 0.001 to prevent divide by zero.
vec3 brdf = nominator / denominator;
// scale light by NdotL // scale light by NdotL
float NdotL = max(dot(N, L), 0.0); float NdotL = max(dot(N, L), 0.0);

View File

@@ -101,7 +101,7 @@ int main()
glm::vec3(0.0, 0.0f, 10.0f), glm::vec3(0.0, 0.0f, 10.0f),
}; };
glm::vec3 lightColors[] = { glm::vec3 lightColors[] = {
glm::vec3(2.5f, 2.5f, 2.5f) glm::vec3(150.0f, 150.0f, 150.0f)
}; };
int nrRows = 7; int nrRows = 7;
int nrColumns = 7; int nrColumns = 7;

View File

@@ -82,11 +82,6 @@ vec3 fresnelSchlick(float cosTheta, vec3 F0)
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness)
{
return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - cosTheta, 5.0);
}
// ----------------------------------------------------------------------------
void main() void main()
{ {
vec3 albedo = pow(texture(albedoMap, TexCoords).rgb, vec3(2.2)); vec3 albedo = pow(texture(albedoMap, TexCoords).rgb, vec3(2.2));
@@ -102,7 +97,22 @@ void main()
// of 0.04 and if it's a metal, use their albedo color as F0 (metallic workflow) // of 0.04 and if it's a metal, use their albedo color as F0 (metallic workflow)
vec3 F0 = vec3(0.04); vec3 F0 = vec3(0.04);
F0 = mix(F0, albedo, metallic); F0 = mix(F0, albedo, metallic);
vec3 F = fresnelSchlickRoughness(max(dot(N, V), 0.0), F0, roughness); // use modified Fresnel-Schlick approximation to take roughness into account
// reflectance equation
vec3 Lo = vec3(0.0);
for(int i = 0; i < 4; ++i)
{
// calculate per-light radiance
vec3 L = normalize(lightPositions[i] - WorldPos);
vec3 H = normalize(V + L);
float distance = length(lightPositions[i] - WorldPos);
float attenuation = 1.0 / (distance * distance);
vec3 radiance = lightColors[i] * attenuation;
// Cook-Torrance BRDF
float NDF = DistributionGGX(N, H, roughness);
float G = GeometrySmith(N, V, L, roughness);
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
// kS is equal to Fresnel // kS is equal to Fresnel
vec3 kS = F; vec3 kS = F;
@@ -115,21 +125,6 @@ void main()
// have no diffuse light). // have no diffuse light).
kD *= 1.0 - metallic; kD *= 1.0 - metallic;
// reflectance equation
vec3 Lo = vec3(0.0);
for(int i = 0; i < 4; ++i)
{
// calculate per-light radiance
vec3 L = normalize(lightPositions[i] - WorldPos);
vec3 H = normalize(V + L);
float distance = length(lightPositions[i] - WorldPos);
float attenuation = 1.0 / distance * distance;
vec3 radiance = lightColors[i] * attenuation;
// Cook-Torrance BRDF
float NDF = DistributionGGX(N, H, roughness);
float G = GeometrySmith(N, V, L, roughness);
vec3 nominator = NDF * G * F; vec3 nominator = NDF * G * F;
float denominator = 4 * max(dot(V, N), 0.0) * max(dot(L, N), 0.0) + 0.001; // 0.001 to prevent divide by zero. float denominator = 4 * max(dot(V, N), 0.0) * max(dot(L, N), 0.0) + 0.001; // 0.001 to prevent divide by zero.
vec3 brdf = nominator / denominator; vec3 brdf = nominator / denominator;