For context, my renderer first does an ambient pass, and then individiual lighting passes with additive blending.
I don’t even know where to begin, to be honest. Here’s my vertex shader and fragment shader. Both of them are compiled twice, for the ambient and directional light pass which has the DIRECTIONAL_LIGHT macro defined by the rendering engine.
Firstly, notice how I ignore the normal mapping, even though the shaders work in tangent space. This is just to be sure that the normal mapping isn’t the problem. The UVs aren’t the problem either, so this must be some basic mistake I’ve done in the diffuse part.
Here’s a video which showcases what happens: https://streamable.com/matvm. See how the right half of the ball seems to be lit fine, while the left side is weirdly darker (the model sits at identity and the light moves around it).
I also tried not doing the ambient pass, and immediately doing the lighting pass right after clearing the buffers (still with additive blending, but the object color is now completely white), which also produced something strange: https://streamable.com/ezgfc. Stare at the right half of the ball and see four different quarters of the right half be different (transparent black, transparent white, solid black, solid white).
GLSL has an inverse() function. There’s nothing wrong with your version, although the built-in may be more efficient. But it would be better to pass in the normal matrix as a separate uniform rather than computing it anew for each vertex.
The tangent vector should be transformed by the model matrix, not the normal matrix. The whole point of using the inverse-transpose is that it preserves dot products (i.e. dot(inverse(transpose(M))*n,M*v)=dot(n,v)) even if M isn’t orthonormal.
If the model matrix consists solely of rotation, uniform scaling, and/or translation (no non-uniform scaling or shear), all of this is moot; you don’t need a separate normal matrix.
Uh, not really. Can you elaborate?
From that, it looks like the UVs are mirrored. There shouldn’t be a visible seam between the quadrants. Also: do you have the components in the correct order? The normal map should be predominantly blue (<128,128,255> = #8080FF), i.e. normals should mostly be aligned with the surface normal.
Well those don’t look right. Are you storing tangents in the model, or calculating them from the UVs?
Well, the tangents appear to be mostly continuous except for the poles (where you’d expect there to be issues if you’re just mapping U to longitude and V to latitude) and that one weird bit with the 3 triangles which don’t match each other or their surroundings.
So the discontinuities at the quadrant boundaries suggest that the UVs are discontinuous (which isn’t necessarily a problem, but you’d expect the tangents to also be discontinuous at those points). But even that wouldn’t have much of an effect if the normal map was mostly flat, which is why I suspect that the components may be mis-ordered. The blue channel should be the normal, with red and green for T and B. Swapping T and B wouldn’t have much effect in areas where the normal map is flat, but using either T or B for the normal would. Are you loading a BGR texture as RGB?
I mean… it has to be something in the diffuse part probably, the artifacts are still there even when I don’t read any textures and draw just the diffuse value (Same artifacts as this video I’ve already showed in OP, where some quadrants have lower diffuse values for no apparent reason).