Why is my normal map lighting stronger in one direction?

I do not know a ton about normal maps but my understanding is colors represent directions that ‘normals’ face and the lighting reacts accordingly. I’m attempting to make normal maps for 2D sprites. I painted a bridge that is symmetrical (i.e. the right side is a mirror of the left.) and then painted a simple normal map. It looked kind of weird so I used Laigter to generate a normal map from the diffuse map to ensure it was properly ‘mirrored’ as well. But the same problem exists in Unreal. The ‘right’ side is always brighter while the ‘left’ side stays shadowed, despite being perfectly mirrored.

In Laigter it is fine. Both sides are equally lit. But in Unreal as you can see in the screen capture, the left side is not as light as the right. The effect is correct, the light ‘lights up’ the sprite where it is supposed to be light, it is just much lighter on one side than the other.

lit-bridge

This is not expected so if anyone can tell me why this is happening and/or a work around that would be very helpful! Thanks.

Also, the material is a pretty simple lit translucent material with the normal map plugged into the normal pin so I don’t think it is a material problem. And the point light is a default point light I just dragged in and positioned directly in the center so also not the problem.

Either the normal map is wrong, or the tangent basis is wrong.

A normal map encodes the direction of the normal compared to the surface it’s applied to. The “0.5” value means “no change” and the “1.0” value means “maximum distortion one way” and the “0.0” value means “maximum distortion the other way.”

The red channel bends the normal in the direction of increasing U texture coordinates along the surface (for 1.0) or against that direction (for 0.0.)
The green channel bends the normal in the direction of increasing V texture coordinates along the surface.
The blue channel is calculated to make the vector made from (R, G, B) have unit length – just like a regular normal vector. Thus, it is always in the 0.5 … 1.0 range.

(There are some encoding tricks used in various places that might change the specifics, but these are the general rules you should run by.)

So, look at the normal map. Is it an even light blue? If not, something’s wrong in calculating it. If it is an even light blue, then turn on tangent basis visualization, and see if there’s something different between left and right sides in UV space.
If your mesh is mirrored, and your UV coordinates are mirrored, that could also cause it. You should never mirror your UV mapping for geometry you want to use normal maps on.

3 Likes

Thanks for answering. I’m a bit confused but I think it may have something to do with the tangent basis you mention. I did another map.

bridge-color
bridge-normal

Maybe this will be more helpful in illustrating what I am seeing. The first is the color map, the second is the normal map, and the third is a red light showing how it is lighting in the viewport.

Sorry, I’m not sure how to ‘turn on the tangent basis visualization’. I tried to find it in the Show menu and did some google searching… but I don’t see it.

I’m just dragging the sprite into the view, so no custom mesh, I assume it is just the image being rendered on a single quad. So no mirroring.

I’ll keep trying to find how to see the tangent stuff, but thought I’d go ahead and upload the images here in the meantime in case they make my problem more obvious.

That normal map looks fine and works perfectly for me. If you’ve simply plugged the Texture Sample node into the normal slot make sure that you have the sampler type set to “normal” in the material and that the image file compression setting is set to “Normal Map” as well. Also make sure that the “tangent space normal” box is ticked in the material details. All of these are defaults and should have been detected automatically but if somehow it wasn’t or they got changed they can cause an otherwise good map to do unusual things.

1 Like

Yes! Thank you. Turns out the normal map compression setting was on UserInterface2D for some reason. Changing thatt to Normalmap fixed it.

Always something small and easily overlooked. :smiley:

2 Likes

For next time, the tangent basis visualization lives in the static mesh inspector:

1 Like