Seams with normal map and mirrored uvs
See original GitHub issueDescription of the problem
I guess it may not be just a threejs issue but I ran into a problem when using a normal map with a mesh having mirrored uvs.
With the current code, my understanding is that the RGB value (128, 128, 255) which is supposed to represent a non perturbed normal by convention is read as (0.50196, 0.50196, 1.0) - in linear color space. When converted to [-1, 1] using the function map * 2.0 - 1.0
the vector encoded in the texture becomes (0.00392, 0.00392, 1.0) when it shall be (0.0, 0.0, 1.0). This is the reason why when using a mesh with mirrored uvs and a normal texture, the two normals at a seam have different directions creating the artifact.
It can be easily proven by modifying the perturbNormal2Arb function.
Replace vec3 mapN = map * 2.0 - 1.0;
by vec3 mapN = map * 2.0 - 1.00392;
and the seams disappear. I attached two screenshots made using a fully metallic material and no roughness to make it very obvious:
Not too sure how this problem is generally solved as this is not my area of expertise.
Three.js version
- Dev
- r113
Browser
- All of them
OS
- All of them
Issue Analytics
- State:
- Created 4 years ago
- Reactions:1
- Comments:37 (14 by maintainers)
Top GitHub Comments
Can you share the model?
Some issues like this can be avoided by computing vertex tangents and setting
material.vertexTangents = true
. You can add tangents with an option in the Blender glTF exporter, or with BufferGeometryUtils.Mugen, there were a couple of hacks discussed in the thread, but no PR so far. The simplest hack offered by @njarraud shifts normal map zero level to 128, thus causing to 0 and 255 to map incorrectly as a price. I posted fiddles for both this hack and 127-based hack I think. Then the more convoluted hack that maps all of (0,127,128,255) values “correctly” but not all the other values inbetween (and the expression is ugly).