three.js: Bug in default shader with normal map
Description of the problem
There are rending issues due to the default shader (checked with MeshStandardMaterial and MeshPhongMaterial) when using the normal map if all the texture coordinates for the face are exactly the same.
I had exactly the same issue with other shaders and this was related to the dFdx(uv)
and dFdy(uv)
shader functions returning 0 and leading to a division by 0.
Live example:
- jsfiddle (dev branch)
Three.js version
- Dev
- r108
- r104
Browser
- All of them
- Chrome
- Firefox
- Internet Explorer
OS
- All of them
- Windows
- macOS
- Linux
- Android
- iOS
Hardware Requirements (graphics card, VR Device, …)
OpenGL vendor: NVIDIA Corporation (0x10de)
OpenGL renderer: GeForce RTX 2060/PCIe/SSE2 (0x1f08)
OpenGL version: 4.6.0 NVIDIA 430.40
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Comments: 32 (8 by maintainers)
This is what I believe is happening…
Even if the uv’s at each vertex are identical, interpolation of uv’s across the face of the primitive can result in different values due to numerical roundoff.
Consequently,
may not be the zero vector we would hope it would be.
The next line
will return - 1, 0, or 1.
And the following line is normalizing something that is very close to zero
which just amplifies the numerical errors since it returns a unit-length vector.
@Mugen87 The OP is only trying to help locate the issue at this point.
I found out that the problematic operation is the
normalize
function with zero-vector here (bothS
andT
): https://github.com/mrdoob/three.js/blob/84f9c5145548f67ffebf6e82478df97118c7bfd3/src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl.js#L26-L32if I change line 31 and 32 to the following the weird effect is solved:
It seems like the current implementation of the
normalize
function of the Nvidia driver I use doesn’t handle zero-vectors.@Mugen87 I think @WestLangley means that it’s better to not worry about performance issues while we try to pinpoint where the artifacts are coming from.
This is what I see on my iPhone.
I fixed the last fiddle to fix the CORS error: https://jsfiddle.net/q4rwtvjy/
If I have some time I will try to find out where does the issue come from and detect if there are invalid operation (at least on my system).
You can tweak these shaders directly by modifying
THREE.ShaderChunk.normalmap_pars_fragment
and/orTHREE.ShaderChunk.normal_fragment_begin
before creating a material.Let us know if you find a workaround that solves the bug in your system and depending on the performance implications we can consider it.
Fixing the driver issue is definitely more expedient than building something around it.
Unfortunately seems to be a bug in the driver and/or device. You may want to report the issue to Nvidia instead.
Can you please share a screenshot that shows how the fiddle is rendered on your computer? I’m not sure I can see them. The triangle looks like so on my iMac:
TBH, I do not understand the bug. Especially since
uv_grid_opengl.jpg
is not a normal map. It’s a map for debugging texture coordinates. Why do you assign it to.normalMap
?