Reason:
The sky is rendered through the background layer, writing only color but not the depth and normal for the PrePass.
So the data for the sky area is:
Depth: 0
Normal RGB: (0, 0, 0)
Normal Alpha: 0
Babylon SSAO2 still performs normalize(0,0,0) on the sky’s zero normal.
WebGPU/WGSL will produce and propagate NaN for this invalid operation.
Finally, SSAO directly does:
Final color = original scene color × AO
So the abnormal sky AO ends up darkening the HDRI.
WebGL didn’t have any issues; it’s just that some WebGL drivers are more lenient with normalizing zero vectors, which doesn’t mean the calculation itself is correct.
The final fix is to add a geometry mask correction pass, using the alpha channel of the PrePass normal map to determine whether the current pixel belongs to geometry:
Normal Alpha = 0 → Sky, just use the original scene color before SSAO
Normal Alpha = 1 → Model, keep the SSAO combined result
The shader logic is basically:
if (normalData.a < 0.5) {
outputColor = originalSceneColor;
} else {
outputColor = ssaoCombinedColor;
}
You have to use a real conditional here, you can’t write it like this:
mix(originalColor, ssaoColor, geometryMask)
Because if ssaoColor already contains NaN, even a weight of 0 can still propagate NaN × 0 in WebGPU.