8
$\begingroup$

While doing some reading on how real-time applications handle color under OpneGL, I noticed that some examples implemented Color as a collection of 4 floats, while others used 4 doubles. I have even seen some vertex-compression examples in the game development field that advocated saving colors as 4 short.

All this got me eager for learning more about this: what is the limit precision that OpenGl (or hardwares) handle for colors? More importantly, though, what are the limits in precision above which color differences become impossible to notice?

I have the impression that learning more carefully about that would help me better think and decide on how to implement a Color class for different applications and scenarios (e.g. making trade-off choices between memory, speed and color-variety).

Thanks for your ideas on this.

$\endgroup$
6
$\begingroup$

Colors shown on your display or saved to standard image file formats use 8 bits per component. So to store these colors it suffices to use four bytes (unsigned char). These colors are usually using sRGB color space, which includes a non-linear "gamma" transformation that redistributes precision to make it somewhat more perceptually uniform, so it's actually pretty close to the limit of how finely humans can perceive color differences already. (However, the sRGB gamut is only a subset of all the colors that are physically perceivable. Wider gamuts need more bits.)

However, if you're generating or processing colors in graphics software (and not just loading/storing them), there are various reasons you might want to use more precision.

  • Performing operations on colors, such as adjusting brightness and contrast, alpha blending, gamma correction, etc all tend to lose precision. You might want to store colors as 16-bit or more internally to give yourself more precision headroom. Otherwise, repeated rounding off to 8 bits after each operation can cause a progressive loss of quality.
  • Similarly, when working with linear colors (not the sRGB gamma-encoded colors) for lighting math, extra precision is needed to ensure you have sufficient precision when you eventually convert back to sRGB.
  • It may be faster and more convenient to work with floating-point colors instead of integer ones. This is especially true on GPUs, where integer math instructions have only a fraction of the throughput of float instructions. But even on CPUs it's certainly easier and probably faster to convert colors to float, do a bunch of operations, and then convert back to integer, rather than trying to do everything with integer fixed-point math.
  • If you do HDR rendering at all then you'll need more than 8 bits of precision to handle the larger color gamut and intensity range. The new HDR displays just starting to come out accept images with 10 or 12 bits per component.

Using double for colors is massive overkill, but using float for internal representation of colors is common for all the reasons above. When working with GPUs, half (16-bit float) is also common, as they support that format in hardware.

$\endgroup$
  • $\begingroup$ Excellent answer, thanks! I just didn't get the last part: using a half wouldn't incur in the very same problems that you mentioned before, due to the lack of precision? I though that would be particularly important at the GPU, due to the many color calculations that are frequently done in shaders $\endgroup$ – AndrewSteer Aug 28 '16 at 5:09
  • 1
    $\begingroup$ @AndrewSteer A half is 16 bits, including 11 effective bits of mantissa precision, so while not as precise as float, it's still sufficient for most color operations. (Maybe not quite sufficient if you're outputting to a high-gamut HDR display; I'm not sure.) $\endgroup$ – Nathan Reed Aug 28 '16 at 5:10

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.