Three.js: Logarithmic Depth Artifacts

Created on 1 Oct 2019  路  17Comments  路  Source: mrdoob/three.js

Description of the problem

Logarithmic depth appears to be broken in [email protected]. Possibly related: #17442.

On my system, I see lots of depth artifacts in setups that use logarithmicDepthBuffer. I don't know if this problem is hardware-related; would be cool if someone could verify!

Screenshots

logarithmicdepthbuffer example

logdepthbuf

I get the same artifacts in one of my projects where I use logarithmic depth for testing purposes:

| r108 (worked fine) | r109 (broken) |
|------|------|
| logdepthbuf1 | logdepthbuf2 |

Three.js version

  • [x] Dev
  • [x] r109
  • [ ] r108

Browser

  • [x] All of them
  • [ ] Chrome
  • [ ] Firefox
  • [ ] Internet Explorer
  • [ ] Edge

OS

  • [ ] All of them
  • [x] Windows 10 Pro, 64-bit
  • [ ] macOS
  • [ ] Linux
  • [ ] Android
  • [ ] iOS

Hardware Requirements (graphics card, VR Device, ...)

GPU: NVIDIA GTX 1060 6GB

Drivers

Graphics Driver: 436.30 (Standard Type)

Regression

All 17 comments

Hmm that PR shouldn't have affected any of the logarithmic depth buffer logic when using a perspective camera. Because of how noisy the output is my best guess is that it's something to do with the varying vIsPerspective value comparison that is causing the issue?

Unfortunately I can't reproduce the problem even when forcing low shader precision but if you can maybe try changing this fragment shader line to be a looser comparison in case the values 1.0 or 0.0 we expect here are somehow losing precision when they're interpolated. I would change vIsPerspective == 1.0 to vIsPerspective > 0.5:

gl_FragDepthEXT = vIsPerspective > 0.5 ? log2( vFragDepth ) * logDepthBufFC * 0.5 : gl_FragCoord.z;

Thanks for the quick response!

I changed the comparison as you suggested and that fixed the issue 馃帀

@gkjohnson What graphics card do you use?

Glad to hear that fixed it! Just made a PR (#17631).

@gkjohnson What graphics card do you use?

I'm just using integrated graphics on my surface laptop and mac. I wish I had a little more insight into what was causing it but I guess it just comes down to different graphics hardware behaving differently?

@vanruesc

Please try test 1: testing for zero, instead

gl_FragDepthEXT = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;

Also, please try test2:

gl_FragDepthEXT = mix( gl_FragCoord.z, log2( vFragDepth ) * logDepthBufFC * 0.5, vIsPerspective );

@gkjohnson It is roundoff. You can't interpolate co-equal values over the face of the primitive and be guaranteed to get the value as output. It would seem to me it should work if the value is zero, however.

It is roundoff.

I see -- I guess I'm just surprised that it only happens on this hardware (so far) but it makes sense. Do you have a preference between any of the proposed solutions? Using vIsPerspective > 0.5 would account for noise at 1.0 or 0.0, though, and I'm a little hesitant to use mix because that would just propagate the noise to the depth buffer.

@WestLangley Both tests work. They produce the same visual results as vIsPerspective > 0.5.

Roundoff should not be a problem with mix.

Let's see what others think. I prefer mix.

Roundoff should not be a problem with mix.

Can you elaborate on why? Intuitively if the problem is that the vIsPerspective value is prone to rounding error when being interpolated then that would affect the result of mix, right? Unless you're suggesting that the error would be so minimal it wouldn't make any perceptible difference. It seems like this could cause noise artifacts with surfaces that are close together, though.

Wouldn't mix produce results that are slightly less accurate than they could be? I think depth wouldn't really be log2( vFragDepth ) * logDepthBufFC * 0.5 on my system with that solution.

I vote for vIsPerspective > 0.5 ? a : b or vIsPerspective < 1.0 ? b : a because vIsPerspective == 0.0 doesn't seem safe enough.

If the depth buffer has minimal precision, I guess rounding a second time could be a problem... Given that, 'test 1' would be my preference.

vIsPerspective < 1.0

vIsPerspective can be greater or less than zero due to roundoff.

vIsPerspective == 0.0 doesn't seem safe enough.

Zero times anything is zero. I think it would be perfectly safe.

Based on the facts of this thread I vote for test 1^^.

vIsPerspective can be greater or less than zero due to roundoff.

You're right, just tried it out and it didn't work 馃槗

Zero times anything is zero. I think it would be perfectly safe.

Fair enough. Then my vote goes to vIsPerspective == 0.0.

Zero times anything is zero. I think it would be perfectly safe.

Fair enough. Then my vote goes to vIsPerspective == 0.0.

Zero seems safe given this explanation of the problem. The only reason I'd lean towards using > 0.5 is because it's resilient to some other unforeseen hardware quirk that could cause noise at 0.0. Maybe it's overly cautious but I don't see a reason not to do that.

Other than that I don't have strong opinions either way. I'm happy to change the PR to whatever the preferred condition is.

I recommend test 1.

Yeah, let's change #17631 accordingly so we get this issue fixed^^.

Oops I misunderstood "test 1" to be the first test I posted originally... I just changed #17631 to use the vIsPerspective == 0.0 comparison.

Was this page helpful?
0 / 5 - 0 ratings