How to output 16bit depth normal map from Blender internal correctly?

See link to my stack exchange question.

Basically I was testing my texture baking addon, but noticed that all textures exported was 8 bit in depth.

So I went to read this question in how:

However, the result I get for normal maps are not what I expected.

Is there anyway to save baked normal maps(which was said to be 32 bit in depth, internally) into 16 bit, or as the original 32 bit depth while keeping the color information correct?

The problem mainly is… When I import the 16 bit version into Substance Painter and added it to a fill layer, it gives me the same Banding artifact as the 8 bit map did. While because of the color isn’t correct, it makes the normal map look worse than 8 bit.

#Update:
Somehow managed to get a correct normal map sized at 50MB with the correct visible color, and the correct bit depth, and it works perfectly in SP. (saved manually)

When I try to automate the saving process, the color become bad. Suspect some settings were incorrect when it was automated.

Nope… what I previously perceived as correct 16bit output with correct color was an imposter. It was 8 bit disguised as 16 bit. As the banding problem persists on that texture.

Maybe 16 bit-depth PNG was not supposed to have the correct visible colours of a 8 bit normal maps. Maybe the signed or unsigned float points caused this problem.

Someone in the Chinese blender community pointed out it is a problem with linearization. But if this is the case, I can’t think of a good way to convert such data into the proper data that Substance Painter can directly read, using python.

the first question is “why ?”
why do you think you NEED a 16 bit PER channel or 32 bit float PER channel Normal map

now for a Height map or DEM or displacement map a 16 bit or 32 bit float grayscale image is needed

but not for a normal

8 bit per chan is just fine for the Vector direction to be encoded in

as per color
the blue chan needs to be 65538 for a 16 bit image and
and in a float " 3.402823 × 10[SUP]38[/SUP] "

To negate the Normal map Banding artifacts during material authoring process. If I were to use the 8bit output normal map in a process that combines many many different layers of normal maps, the final output of such normal map will become significantly more “artifacted”.

This is an issue about “Perfection”, not an issue about “Good Enough”. To be honest, when more normal details are added onto the final 3D asset, those artifacts will be barely visible. But for example, if I model a lowpoly sports car, and have to use normal map to smooth out the surfaces, the un-dithered normal map(8 bit) will create banding artifacts, if I dither this 8 bit map, the final result will still have the banding effect due to the existence of the banding in the input image. If I have the 16 bit depth normal map(has no banding effect), and then dither it down into 8 bit, The banding artifacts will actually not being visible at all.(The noise still exist.)

This is the detailed demonstration of “why the 16 bit depth”.

In conclusion, for a final product, 8 bit depth normal map maybe good enough. But for material authoring pipeline(as a method in smoothing out mesh geometry/surfaces), 8 bit depth can not grant the best result. Or, in other word, is not capable of delivering the desired result.

It’s hard to think in 16bit textures ingame. It’s not bad have a 16bit output, but in really the solution is in the artist, that must know how to use custom normals.

Why not bake in Substance Painter directly?

The problem is not why how someone do something.

The problem is why something seems to be impossible to get right.

I’m using Blender’s API and open-source-ness to develop new workflow for baking/texturing. Using Substance Painter is basically saying good-bye to efficiency and automation. Not to mention I needed to manipulate mesh data for this workflow, which is impossible to do with Substance Painter.

Okay. Did you try baking in cycles instead? BI is pretty outdated at this point.

Yes, I have. They produce absolutely the same result for normal maps, float or not. Which points the problem at image output/saving process. Or something other than the bakers.

I assume the 16 bit PNG codec(is that called codec?) in Blender doesn’t have options for linearization methods?

Unless Eevee has a much better baking tool set, BI is here to stay because it bakes fast. 4096x4096 32bit float normal map baking. BI did it in the blink of an eye. Cycle did it in about 7~8 seconds. Not to mention Cycles needed a material on the active mesh to bake anything. The setup takes long, the process takes long, not a good candidate for automated, recursive bakes.

https://developer.blender.org/T52334

Seems like it’s a bug. Updating as soon as this commit is released. I wasted way too much energy trying to figure this shit out that I don’t want to believe this was actually Blender’s design flaw(technically not a bug).

Facepalm.

Have you output the supposed 16-bit output with the 8-bit output? If the 16-bit is significantly larger, it probably really is 16-bit. However, the banding is probably more related to the colorspace. Make sure the output is in linear colorspace, and I suggest trying EXR or TIF files instead of PNG.

Banding by principal can only be caused by insufficient bit depths. 16 bit maps if generated correctly, does not give banding, even if the colour space is incorrect.

With 2.78, the latest stable version, no matter what format you use, you will get the wrong colour. It’s a bug. It’s solved. And I’ve tried literally every possible setting related to image and baking inside blender. Thank you for your effort.

well i am getting the correct color on 32bit normalmap output after "normalizing the exr using gmic to values between 0 and 1
https://2-t.imgbox.com/fcTr2h5O.jpg https://6-t.imgbox.com/kxhjyfvp.jpg

the second image is in Gimp 2.9.4 DEVELOPMENT

Well, thank you for the effort. As I mentioned before, I looked for a way to automate baking process to get something I can directly use. TO SAVE TIME, using Gimp to manually fix the wronged normal output is against the principle of my actions. This problem is solved in 2.79, I hope this is the end of this discussion.

i used Gmic in the terminal to normalize it

this can be easily done in a shell script and be automated

Now that is some really useful information. Thank you very much.