Hello! I’ve been searching high and low across the internet to understand why my normal maps look red in shader graph. I found an old answer that said it was because of a bug with DirectX. But even after disabling directX, my normal maps look red! Does anyone know what’s going on? (Using Unity 2020.1.4)
Because that’s actually what Unity’s tangent space normal map textures looks like. The inspector preview is lying and showing you the reconstructed normal rather than the actual texture.
Additional note, you have the Sample Texture 2D node’s “Type” set to “Default”, so it’s sampling the texture as a regular texture, hence why you’re seeing a preview of the actual texture instead the reconstructed normal. If you change the “Type” to “Normal” it’ll show you a preview of the reconstructed normal map you’re expecting to see.
When you import a tangent space normal map into Unity, it stores the texture in one of three ways:
The first way is as is with no modifications, but it only does that for some mobile devices.
The second, and most common way, is by storing the red “X” channel of the original normal map in the alpha channel, leaving the green channel as is, and blanking out the red and blue channels to a solid white. This is usually a DXT5 texture, aka BC3, and that format is why this weird format is used. The DXT5 texture format has a very high quality alpha channel, and a not as high quality green channel that is still better than the red or blue channels. Pre Unity 5.6 it would copy the green channel to the red and blue channels. But that changed because of the third way it now can store normal maps.
The third was is with special 2 channel texture formats that were created explicitly to store tangent space normal maps. These are EAC for mobile and BC5 for desktop & consoles. The BC5 format is essentially two DXT5 alpha channels, but are the red and green channels of the texture. This has been essentially the industry standard format for tangent space normal maps since it was first supported on the Xbox 360, though Unity’s support for it wasn’t added until ~2017.
The reason for all of this is you can get better, less compressed looking normal maps by only storing two channels. Most image compression formats and compression tools aren’t designed to handle normal data, they’re designed to handle perceptual color images. When you try to compress normal maps with those same tools you get artifacts that are much more obvious than they could otherwise be. DXT1 especially gets a palette of only 4 colors per 4x4 block of pixels, and that palette isn’t any 4 colors, but instead two end point color values and two that are 33%:67% or 67%:33% blends of the end points. However for DXT5, the alpha is completely separate from the RGB and gets it’s own 8 value palette per 4x4 block, so it’s much higher quality. BC5 extends this so that both the red and green get unique 8 value palettes per 4x4 block, which is why they’re so much better looking. And for tangent space normals, the z can be reconstructed from the x and y values so it’s not even needed. A normal vector is assumed to be unit length, so all you need is a little Pythagorean to get the z from the x and y values.
Thank you so much! I assumed something was wrong with my setup since everyone elses screenshots from the shader graph shows the normals in the usual 3-color way. But your description makes perfect sense.