Duplicate shadow: Shadow appears below and above object (WebGPU build 167)

Note: I’m using the WebGPU build 167 of three.js for this question and JSFiddle.

Update: setting logarithmicDepthBuffer: false appears to fix the issue (credit to mjurczyk), however the logarithmic depth buffer is a requirement for my scene, so I’d like to get the shadow working with it.

See screenshot and JSFiddle. I have a simple sphere between two “floors”, with a DirectionalLight pointing straight down from above. Notice how the sphere casts a shadow on the top “floor”. How can I remove the shadow from the top floor? I don’t want to disable the top floor’s ability to receive shadows from other objects though, so I don’t want to set receiveShadow = false on the top floor mesh.

I also posted the question on StackOverflow: Three.js duplicate shadow issue (bug?) - Shadow appears below and above object (WebGPU build 167) - Stack Overflow

three.js GitHub bug report: WebGPU - Duplicate shadow when logarithmicDepthBuffer is true - Shadow appears below and above object (WebGPU build 167) · Issue #29200 · mrdoob/three.js · GitHub

Consider setting shadowCam.near / shadowCam.far to some Math.pow(10, n) value (or alternatively, disable logarithmicDepthBuffer on the renderer.)

You’re likely hitting precision issues.

I tried changing the shadowCam.near/shadowCam.far to Math.pow(10, n) and it either removed all the shadows or none at all. Is there a way to fix it without setting renderer.logarithmicDepthBuffer to false? I need logarithmicDepthBuffer for other things in my scene.

I didn’t mean you should literally set it to that value - rather to a value that’s a power of 10, ex. 10, 100, 1000, 10000, ... and so (unless you have that n defined, you’d be getting NaN as a result of pasting Math.pow(10, n) and not replacing n with some number.)

1 Like

lol I knew what you meant; I tried a near value of Math.pow(10,1) and a far value of Math.pow(10,5), and it didn’t get rid of the top shadow (I had to increase DirectionalLight’s position.y after setting the near and far values so the scene was still within the shadow’s cone).

I get the same up-shadow when using it on a browser without WebGPU, so Three.js falls back to WebGL2. However, when I switch to WebGLRenderer everything works fine. Any specific reason to use WebGPU instead of WebGL?

image

I am not sure this is a bug, but it smells like a bug. It needs more tests to confirm this is a bug with WebGPU or its fall back to WebGL2.

1 Like

I get the duplicate shadow issue with WebGPU, so if you get it for WebGL2 also, then it must be a bug for both of them.

I’m trying very hard to learn the WebGPU node-based material system, and I’m also trying to see what WebGPU is capable of. I have a massive landscape scene that requires the performance benefits of WebGPU; I tried using the standard three.js WebGLRenderer build but it could not compete with WebGPU. The massive landscape scene is also the reason I need to use logarithmicDepthBuffer; if logarithmicDepthBuffer is false at very far distances, vertices become more and more offset and “pop” up and down as the camera rotates.

I’m also trying to learn webgpu. What are your findings so far? How does it help with large terrains?

WebGPU is just a faster renderer than WebGL overall. You can reach a higher polycount in your scene than you could with WebGL, which helps with rendering huge detailed terrain meshes. I have been testing a 2048x2048 textured heightmap in three.js, and it was very slow to render with WebGL (around 20fps). When I switched to the WebGPU build of three.js, I started getting over 200fps.

Any chance you could share that demo?

I’ll be posting it on here soon.

1 Like

It looks like this particular issue has come up several times in the past with WebGL and was eventually fixed. Here are the relevant historic issues and a pull request for WebGL:

Issue: Logarithmic depth buffer gives no shadows · Issue #7815 · mrdoob/three.js · GitHub
Issue: Logarithmic Depth Buffer + Orthographic Camera · Issue #9108 · mrdoob/three.js · GitHub
Issue: ShadowMap logarithmic DepthBuffer issue · Issue #12126 · mrdoob/three.js · GitHub
Issue: Shadow problem with logarithmic depth buffer · Issue #17525 · mrdoob/three.js · GitHub
Pull Request: Fix logarithmic depth buffer result when rendering with OrthographicCamera by gkjohnson · Pull Request #17442 · mrdoob/three.js · GitHub

Hopefully the fix for WebGPU is the same?

I also found this pull request for WebGPU that appears to be related: WebGPURenderer: Depth Pixel & Logarithmic Depth Buffer by sunag · Pull Request #27243 · mrdoob/three.js · GitHub

I’ve tinkered around with the depth calculation nodes and was able to get the shadow working (somewhat) by changing this code in three.webgpu.js (excerpt is from the setupDepth() function in the NodeMaterial class):

// three.webgpu.js v168 (line 32506)
// https://unpkg.com/browse/three@0.168.0/build/three.webgpu.js
const fragDepth = modelViewProjection().w.add(1);
depthNode = fragDepth.log2().mul(cameraLogDepth).mul(0.5);

to this:

depthNode = viewZToOrthographicDepth(positionView.z, cameraNear, cameraFar);

Of course however, this makes the depth buffer non-logarithmic. But funny enough, the scene still appears to be using a logarithmic depth buffer (there is no z-fighting in my tests of a huge scene), and it fixes the shadow issue.

After making some modifications to the logarithmic depth buffer calculations and the shadowmap depth compare code, I got it working.

I submitted a pull request for the bug fix here: Fixed shadows not rendering correctly when logarithmicDepthBuffer = t… by PoseidonEnergy · Pull Request #29447 · mrdoob/three.js · GitHub

1 Like