From 769867475cd198aebc56e77ce403430f30c298aa Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 3 Feb 2018 23:56:55 +0100 Subject: [PATCH] - Replaced max(dot(a,b), 0.0) with clamp as some rounding errors caused pow to receive negative values when then value was subtracted from 1.0 (undefined glsl behavior) - Fixed that surface angle attenuation was getting applied twice --- wadsrc/static/shaders/glsl/main.fp | 99 ++++++++++++++++-------------- 1 file changed, 52 insertions(+), 47 deletions(-) diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index 9bd1b39a48f..a768d124491 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -432,7 +432,7 @@ vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness) return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - cosTheta, 5.0); } -float pointLightAttenuationQuadratic(vec4 lightpos, float lightcolorA) +float quadraticDistanceAttenuation(vec4 lightpos) { float strength = (1.0 + lightpos.w * lightpos.w * 0.25) * 0.5; @@ -440,21 +440,17 @@ float pointLightAttenuationQuadratic(vec4 lightpos, float lightcolorA) float attenuation = strength / (1.0 + dot(distVec, distVec)); if (attenuation <= 1.0 / 256.0) return 0.0; + return attenuation; +} + +float shadowAttenuation(vec4 lightpos, float lightcolorA) +{ #ifdef SUPPORTS_SHADOWMAPS float shadowIndex = abs(lightcolorA) - 1.0; - attenuation *= shadowmapAttenuation(lightpos, shadowIndex); + return shadowmapAttenuation(lightpos, shadowIndex); +#else + return 1.0; #endif - - if (lightcolorA >= 0.0) // Sign bit is the attenuated light flag - { - return attenuation; - } - else - { - vec3 lightDirection = normalize(lightpos.xyz - pixelpos.xyz); - vec3 pixelnormal = ApplyNormalMap(); - return attenuation * diffuseContribution(lightDirection, pixelnormal); - } } vec3 applyLight(vec3 albedo, vec3 ambientLight) @@ -464,12 +460,11 @@ vec3 applyLight(vec3 albedo, vec3 ambientLight) albedo = pow(albedo, vec3(2.2)); // sRGB to linear ambientLight = pow(ambientLight, vec3(2.2)); - vec3 normal = ApplyNormalMap(); float metallic = texture(metallictexture, vTexCoord.st).r; float roughness = texture(roughnesstexture, vTexCoord.st).r; float ao = texture(aotexture, vTexCoord.st).r; - vec3 N = normalize(normal); + vec3 N = ApplyNormalMap(); vec3 V = normalize(uCameraPos.xyz - worldpos); vec3 F0 = mix(vec3(0.04), albedo, metallic); @@ -494,28 +489,33 @@ vec3 applyLight(vec3 albedo, vec3 ambientLight) vec3 L = normalize(lightpos.xyz - worldpos); vec3 H = normalize(V + L); - //float distance = length(lightpos.xyz - worldpos); - //float attenuation = 1.0 / (distance * distance); - float attenuation = pointLightAttenuationQuadratic(lightpos, lightcolor.a); + + float attenuation = quadraticDistanceAttenuation(lightpos) * shadowAttenuation(lightpos, lightcolor.a); if (lightspot1.w == 1.0) attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); + if (lightcolor.a < 0.0) + attenuation *= clamp(dot(N, L), 0.0, 1.0); // Sign bit is the attenuated light flag + + if (attenuation > 0.0) + { + attenuation *= shadowAttenuation(lightpos, lightcolor.a); - vec3 radiance = lightcolor.rgb * attenuation; + vec3 radiance = lightcolor.rgb * 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); + // cook-torrance brdf + float NDF = DistributionGGX(N, H, roughness); + float G = GeometrySmith(N, V, L, roughness); + vec3 F = fresnelSchlick(clamp(dot(H, V), 0.0, 1.0), F0); - vec3 kS = F; - vec3 kD = (vec3(1.0) - kS) * (1.0 - metallic); + vec3 kS = F; + vec3 kD = (vec3(1.0) - kS) * (1.0 - metallic); - vec3 nominator = NDF * G * F; - float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0); - vec3 specular = nominator / max(denominator, 0.001); + vec3 nominator = NDF * G * F; + float denominator = 4.0 * clamp(dot(N, V), 0.0, 1.0) * clamp(dot(N, L), 0.0, 1.0); + vec3 specular = nominator / max(denominator, 0.001); - float NdotL = max(dot(N, L), 0.0); - Lo += (kD * albedo / PI + specular) * radiance * NdotL; + Lo += (kD * albedo / PI + specular) * radiance; + } } // // subtractive lights @@ -529,28 +529,33 @@ vec3 applyLight(vec3 albedo, vec3 ambientLight) vec3 L = normalize(lightpos.xyz - worldpos); vec3 H = normalize(V + L); - //float distance = length(lightpos.xyz - worldpos); - //float attenuation = 1.0 / (distance * distance); - float attenuation = pointLightAttenuationQuadratic(lightpos, lightcolor.a); + + float attenuation = quadraticDistanceAttenuation(lightpos) * shadowAttenuation(lightpos, lightcolor.a); if (lightspot1.w == 1.0) attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); + if (lightcolor.a < 0.0) + attenuation *= clamp(dot(N, L), 0.0, 1.0); // Sign bit is the attenuated light flag - vec3 radiance = lightcolor.rgb * attenuation; + if (attenuation > 0.0) + { + attenuation *= shadowAttenuation(lightpos, lightcolor.a); - // 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 radiance = lightcolor.rgb * attenuation; - vec3 kS = F; - vec3 kD = (vec3(1.0) - kS) * (1.0 - metallic); + // cook-torrance brdf + float NDF = DistributionGGX(N, H, roughness); + float G = GeometrySmith(N, V, L, roughness); + vec3 F = fresnelSchlick(clamp(dot(H, V), 0.0, 1.0), F0); - vec3 nominator = NDF * G * F; - float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0); - vec3 specular = nominator / max(denominator, 0.001); + vec3 kS = F; + vec3 kD = (vec3(1.0) - kS) * (1.0 - metallic); - float NdotL = max(dot(N, L), 0.0); - Lo -= (kD * albedo / PI + specular) * radiance * NdotL; + vec3 nominator = NDF * G * F; + float denominator = 4.0 * clamp(dot(N, V), 0.0, 1.0) * clamp(dot(N, L), 0.0, 1.0); + vec3 specular = nominator / max(denominator, 0.001); + + Lo -= (kD * albedo / PI + specular) * radiance; + } } } } @@ -558,7 +563,7 @@ vec3 applyLight(vec3 albedo, vec3 ambientLight) // Pretend we sampled the sector light level from an irradiance map - vec3 F = fresnelSchlickRoughness(max(dot(N, V), 0.0), F0, roughness); + vec3 F = fresnelSchlickRoughness(clamp(dot(N, V), 0.0, 1.0), F0, roughness); vec3 kS = F; vec3 kD = 1.0 - kS; @@ -569,7 +574,7 @@ vec3 applyLight(vec3 albedo, vec3 ambientLight) //kD *= 1.0 - metallic; //const float MAX_REFLECTION_LOD = 4.0; //vec3 prefilteredColor = textureLod(prefilterMap, R, roughness * MAX_REFLECTION_LOD).rgb; - //vec2 envBRDF = texture(brdfLUT, vec2(max(dot(N, V), 0.0), roughness)).rg; + //vec2 envBRDF = texture(brdfLUT, vec2(clamp(dot(N, V), 0.0, 1.0), roughness)).rg; //vec3 specular = prefilteredColor * (F * envBRDF.x + envBRDF.y); //vec3 ambient = (kD * diffuse + specular) * ao;