Skip to content

Commit ad4dcfd

Browse files
committed
IBL Math hardening
1 parent 23fc1d4 commit ad4dcfd

5 files changed

Lines changed: 50 additions & 22 deletions

File tree

jme3-core/src/main/resources/Common/IBL/IBLKernels.frag

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77
#import "Common/ShaderLib/GLSLCompat.glsllib"
88
#import "Common/IBL/Math.glsl"
9-
9+
#import "Common/ShaderLib/Math.glsllib"
1010
in vec2 TexCoords;
1111
in vec3 LocalPos;
1212

@@ -15,12 +15,12 @@ uniform float m_Roughness;
1515
uniform int m_FaceId;
1616

1717
void brdfKernel(){
18-
float NdotV=TexCoords.x;
19-
float roughness=TexCoords.y;
18+
float NdotV = Math_saturate(TexCoords.x);
19+
float roughness = Math_saturate(TexCoords.y);
2020
float alpha = roughness * roughness;
2121

2222
vec3 V;
23-
V.x = sqrt(1.0 - NdotV*NdotV);
23+
V.x = sqrt(Math_saturate(1.0 - NdotV * NdotV));
2424
V.y = 0.0;
2525
V.z = NdotV;
2626
float A = 0.0;
@@ -36,8 +36,9 @@ void brdfKernel(){
3636
float VdotH = max(dot(V, H), 0.0);
3737
if(NdotL > 0.0){
3838
float G = GeometrySmith(N, V, L, alpha);
39-
float G_Vis = (G * VdotH) / (NdotH * NdotV);
40-
float Fc = pow(1.0 - VdotH, 5.0);
39+
float G_Vis = (G * VdotH) / max(NdotH * NdotV, IBL_EPSILON);
40+
float oneMinusVdotH = 1.0 - Math_saturate(VdotH);
41+
float Fc = oneMinusVdotH * oneMinusVdotH * oneMinusVdotH * oneMinusVdotH * oneMinusVdotH;
4142
A += (1.0 - Fc) * G_Vis;
4243
B += Fc * G_Vis;
4344
}
@@ -52,8 +53,8 @@ void irradianceKernel(){
5253
// the sample direction equals the hemisphere's orientation
5354
vec3 N = normalize(LocalPos);
5455
vec3 irradiance = vec3(0.0);
55-
vec3 up = vec3(0.0, 1.0, 0.0);
56-
vec3 right = cross(up, N);
56+
vec3 up = abs(N.y) < 0.999 ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0);
57+
vec3 right = normalize(cross(up, N));
5758
up = cross(N, right);
5859
float sampleDelta = 0.025;
5960
float nrSamples = 0.0;
@@ -72,7 +73,7 @@ void irradianceKernel(){
7273
}
7374

7475
void prefilteredEnvKernel(){
75-
vec3 N = normalize(LocalPos);
76+
vec3 N = normalize(LocalPos);
7677
vec3 R = N;
7778
vec3 V = R;
7879

jme3-core/src/main/resources/Common/IBL/Math.glsl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* https://learnopengl.com/PBR/IBL/Specular-IBL
55
* - Riccardo Balbo
66
*/
7+
#import "Common/ShaderLib/Math.glsllib"
78
const float PI = 3.14159265359;
89

910
float RadicalInverse_VdC(uint bits) {
@@ -58,6 +59,9 @@ vec4 Hammersley(uint i, uint N){
5859
//
5960
// ImportanceSampleGGX() and GeometrySmith() both expect alpha.
6061
const float MIN_GGX_ALPHA = 0.0064;
62+
const float IBL_EPSILON = 1e-6;
63+
64+
6165

6266
float SafeGGXAlpha(float alpha) {
6367
return max(alpha, MIN_GGX_ALPHA);
@@ -66,8 +70,8 @@ float SafeGGXAlpha(float alpha) {
6670
vec3 ImportanceSampleGGX(vec4 Xi, float alpha, vec3 N){
6771
alpha = SafeGGXAlpha(alpha);
6872
float alpha2 = alpha * alpha;
69-
float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (alpha2 - 1.0) * Xi.y));
70-
float sinTheta = sqrt(1.0 - cosTheta*cosTheta);
73+
float cosTheta = sqrt(Math_saturate((1.0 - Xi.y) / (1.0 + (alpha2 - 1.0) * Xi.y)));
74+
float sinTheta = sqrt(Math_saturate(1.0 - cosTheta * cosTheta));
7175

7276
// from spherical coordinates to cartesian coordinates
7377
vec3 H;

jme3-core/src/main/resources/Common/IBLSphH/IBLSphH.frag

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,11 @@ vec3 getVectorFromCubemapFaceTexCoord(float x, float y, float mapSize, int face)
4242

4343

4444
// Warp texel centers in the proximity of the edges.
45-
float a = pow(mapSize, 2.0) / pow(mapSize - 1., 3.0);
45+
float warpDenom = max(mapSize - 1.0, 1.0);
46+
float a = (mapSize * mapSize) / (warpDenom * warpDenom * warpDenom);
4647

47-
u = a * pow(u, 3.) + u;
48-
v = a * pow(v, 3.) + v;
48+
u = a * u * u * u + u;
49+
v = a * v * v * v + v;
4950
//compute vector depending on the face
5051
// Code from Nvtt : https://github.com/castano/nvidia-texture-tools/blob/master/src/nvtt/CubeSurface.cpp#L101
5152
vec3 o =vec3(0);

jme3-core/src/main/resources/Common/ShaderLib/Math.glsllib

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,7 @@ void Math_lengthAndNormalize(in vec3 vec,out float outLength,out vec3 outNormal)
1818
outLength=invl*dotv;
1919
}
2020

21-
21+
float Math_saturate(float value) {
22+
return clamp(value, 0.0, 1.0);
23+
}
2224
#endif

jme3-core/src/main/resources/Common/ShaderLib/PBR.glsllib

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,28 @@
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.
1314
const 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

174192
vec3 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

Comments
 (0)