Why do my image looks green/pinkish when rendering to a 16 bit color target ?

Question


«My renderer looks fine when I'm rendering to a 32 bit color target (ARGB8), but in order to make it faster on older machines I try to enable a 16 bit color target (R5G6B5), the result looks really horrible. The areas that should be neutral are now green (or pink) and colors are apparent where there shouldn't be any. Did I do something wrong ?»

Answer


It's a pretty well known problem, as you noticed R5G_6_B5, uses one extra bit to store the green value of your color. So that means that the value instead of going from 0 to 31, it goes to 0 to 63.

If you trace those values onto the brightness axis, you can see that those two ranges never match except at 0 % brightness and 100% brightness.

Because of that, a "neutral" gray value doesn't exist. So if you want to represent 50% gray, you have to choose between 16/32/16 or 15/31/15 or 16/31/16 or 15/32/15. Does that look ok to you ? look again, 16 on red/blue maps to 16/31 = 51.6% brightness, 15 maps to 15/31 = 48.4% brightness. 32 on green maps to 32/63 = 50.7% brightness, 31 on green maps to 49.2% brightness.

If you chose 16/32/16, then the magenta value (red+blue) is higher than the green value, instead of neutral gray you will have a value that tends to pinkish/magenta. If you chose 15/31/15, the green value is higher than the magenta value and you will get a pale green instead of the neutral gray that you expected.

Then what happens when you alpha blend repeatedly the same gray value : the 1% difference will grow to a 2%, then 3%, etc.. until it all looks green instead of gray or white.

R5G6B5 would be only fine, as long as it is used to display static unstretched images, that have been properly dithered : randomly select between 16/32/16 and 15/31/15 encoding of gray so that visually the adjacent colors looks neutral to you. For 3D rendering it is the plague, not suitable to texture from r5g6b5, not suitable to render directly to r5g6b5 and hardware that use dithering tends to make things look a lot worse than argb8. It's a lot less trouble to just render to argb8 which is sometimes faster on newer graphics cards.

If you want to save texture space use DXTn, if you want to render, use the fast (on modern hardware) and neutral argb8 space.


If you want to learn more..




Partner websites : LEGREG | GRAPHICS | GRAPHISME | PHOTOGRAPHY | OUT OF MY MIND | ANIMATION MENTOR | GREEN LIVING | VOXEL | RAY TRACING | GUENARDI | Add this page rank counter to your page.