What is the EXACT formula converting back and forth RGB (0-255) and normal? (normals/bump texture)

Hi,
I’m currently working on a sprite editor for bump map.
So far generating filters to create normals works great, but the precision seems slightly off.

I’m using this:

// RGB to normal:
normal.x = rgb.r / 127.5 - 1 ;
normal.y = rgb.g / 127.5 - 1 ;
normal.z = rgb.b / 127.5 - 1 ;

// Normal to RGB:
rgb.r = Math.round( 127.5 * ( 1 + normal.x ) ) ;
rgb.g = Math.round( 127.5 * ( 1 + normal.y ) ) ;
rgb.b = Math.round( 127.5 * ( 1 + normal.z ) ) ;

(Z could be inverted depending on left/right handed)

But there are few things that are bothering me:

  • there is no way to have a perfect orthogonal normal since R and G couldn’t be translated to exactly 0 (127 is a bit below 0 and 128 a bit above)
  • I heard that some engine have 128 as 0, and other have 127 (like the Source engine), what about Babylonjs?
  • Some existing tools I use seems to generate “exaggerated” normals, e.g. the blue channel drop below 127 (sometime around 110 or even 100), it’s supposed to create a normal aiming slightly in the backward direction: is it a bug of those tools, or am I missing something???

It would be nice if a dev could give me the exact formula for converting back and forth RGB and normals.

Adding both @PatrickRyan and @bghgary would worked quite a bit on this part.

I think you are looking to use 128.

When I did black and white heightmaps to Normal maps I used 128.

1 Like

Ok, but that means that there are 128 RGB units from -1 to 0, but only 127 RGB units from 0 to 1?

I guess yeah, I’m just pretty sure that this is the same BJs uses.

On Babylon.js side, we only need to convert the 0…1 values to -1…1 coordinates to generate the normal, so we are doing something like:

vec3 bumpNormal = normalize(texture2D(bumpSampler, vBumpUV).xyz * 2.0 - 1.0);

@Evgeni_Popov @Pryme8 Ok thanks, so I’m already doing the right thing :wink:

1 Like

This is true for Babylon.js. Most people use 128 to represent 0, but in Babylon.js, the code will do this (which is the equivalent math as what you noted):

128 / 255 * 2 - 1 = 0.003921568627451

In Babylon.js, if you want to exaggerate the normal, you can use the level property to do it. Like this:

bumpTexture.level = 2;

This will result in the X and Y components of the normal being multiplied by 2 for PBR materials.

1 Like

@bghgary Thanks a lot for the insight! :wink:

1 Like