66 #define NB_PROBES 0
77#endif
88
9+ #import "Common/ShaderLib/Math.glsllib"
910// Internal GGX stability floor. This does not change the user-facing
1011// roughness convention or probe LOD mapping; it only prevents extremely sharp
1112// microfacet lobes from reaching pathological peaks that can destabilize some
1213// drivers and screenshot-test software renderers.
1314const float MIN_GGX_ALPHA = 0.0064;
15+ const float PBR_EPSILON = 1e-6;
16+
17+ float pbrNonZero(float value) {
18+ if (abs(value) < PBR_EPSILON) {
19+ return value < 0.0 ? -PBR_EPSILON : PBR_EPSILON;
20+ }
21+ return value;
22+ }
23+
24+ vec3 pbrSafeReciprocal(vec3 value) {
25+ return vec3(
26+ 1.0 / pbrNonZero(value.x),
27+ 1.0 / pbrNonZero(value.y),
28+ 1.0 / pbrNonZero(value.z)
29+ );
30+ }
1431
1532// BEGIN-@jhonkkk,Specular AA --------------------------------------------------------------
1633// see:http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA(slides).pdf
@@ -165,16 +182,18 @@ vec3 ApproximateSpecularIBL(samplerCube envMap,sampler2D integrateBRDF, vec3 Spe
165182 // The specular bake stores roughness quadratically across mip levels:
166183 // mipNorm = mip / (nbMipMaps - 1), roughness = mipNorm * mipNorm.
167184 // Runtime therefore samples with sqrt(roughness) to recover mipNorm.
168- float Lod = sqrt( Roughness ) * (nbMipMaps - 1.0);
185+ float roughness = Math_saturate(Roughness);
186+ float Lod = sqrt(roughness) * max(nbMipMaps - 1.0, 0.0);
169187 vec3 PrefilteredColor = textureCubeLod(envMap, refVec.xyz,Lod).rgb;
170- vec2 EnvBRDF = texture2D(integrateBRDF,vec2(ndotv, Roughness )).rg;
188+ vec2 EnvBRDF = texture2D(integrateBRDF,vec2(Math_saturate( ndotv), roughness )).rg;
171189 return PrefilteredColor * ( SpecularColor * EnvBRDF.x+ EnvBRDF.y );
172190}
173191
174192vec3 ApproximateSpecularIBLPolynomial(samplerCube envMap, vec3 SpecularColor , float Roughness, float ndotv, vec3 refVec, float nbMipMaps){
175- float Lod = sqrt( Roughness ) * (nbMipMaps - 1.0);
193+ float roughness = Math_saturate(Roughness);
194+ float Lod = sqrt(roughness) * max(nbMipMaps - 1.0, 0.0);
176195 vec3 PrefilteredColor = textureCubeLod(envMap, refVec.xyz, Lod).rgb;
177- return PrefilteredColor * integrateBRDFApprox(SpecularColor, Roughness, ndotv);
196+ return PrefilteredColor * integrateBRDFApprox(SpecularColor, roughness, clamp( ndotv, 0.0, 1.0) );
178197}
179198
180199
@@ -203,7 +222,7 @@ float renderProbe(vec3 viewDir, vec3 worldPos, vec3 normal, vec3 norm, float Rou
203222 // mat3_sub our compat wrapper for mat3(mat4)
204223 mat3 wToLocalRot = inverse(mat3_sub(lightProbeData));
205224
206- vec3 scale = vec3(lightProbeData[0][3], lightProbeData[1][3], lightProbeData[2][3]);
225+ vec3 scale = max(abs( vec3(lightProbeData[0][3], lightProbeData[1][3], lightProbeData[2][3])), vec3(PBR_EPSILON) );
207226 #if NB_PROBES >= 2
208227 // probe blending
209228 // compute fragment position in probe local space
@@ -223,8 +242,9 @@ float renderProbe(vec3 viewDir, vec3 worldPos, vec3 normal, vec3 norm, float Rou
223242 positionLs /= scale;
224243
225244 vec3 unit = vec3(1.0);
226- vec3 firstPlaneIntersect = (unit - positionLs) / rayLs;
227- vec3 secondPlaneIntersect = (-unit - positionLs) / rayLs;
245+ vec3 invRayLs = pbrSafeReciprocal(rayLs);
246+ vec3 firstPlaneIntersect = (unit - positionLs) * invRayLs;
247+ vec3 secondPlaneIntersect = (-unit - positionLs) * invRayLs;
228248 vec3 furthestPlane = max(firstPlaneIntersect, secondPlaneIntersect);
229249 float distance = min(min(furthestPlane.x, furthestPlane.y), furthestPlane.z);
230250
0 commit comments