We are dealing with three related but different issues at the same time.
The first issue is that of range: are channels stored as values in the range [0, 1] or [0, 255] or [0, 65535]. Scaling (multiplying and possibly clamping) is what you do to convert from one range to another.
The second issue is that of raw sample size: how many bits do you use to store the value. This doesn't necessarily have to be the binary logarithm of the size of the range. For example, if your range is [0, 255], you could store the values in 8 bits where the least significant bits represents increments of 1, or in 6 bits where the least significant bit represents increments of 4, or in 10 bits where the least significant bit represents increments of 0.25. In fact, as we will see in the next issue, the increments do not have to be fixed.
The third and final issue is that of encoding: fixed point or floating point. When we say that we store values of [0, 255] in 8 bits or values of [0, 65535] in 16 bits, we usually mean integer encoding (a special case of fixed point where the least significant bit represents fixed increments of 1). When values are stored in the range [0, 1] however, regardless of the raw sample size, usually this implies floating point storage (where most bits are used to store the significand, while a few bits are reserved to store the size of the increment associated with the least significant bit). When we speak of "half precision", "single precision", "double precision", "extended precision" and so forth we also invariably mean floating point encoding.
So here is the catch: OpenEXR uses floating point encoding, in a format that is not built in to most programming languages. Most modern languages only have 64-bit floats, and if they offer anything else it's usually 32-bit floats (respectively double
and float
in the C family), but 16-bit floats are almost never available out of the box.
Half precision can represent values in the range [-65505, 65504], with 11 bits (slightly better than 3 decimal digits) of precision, while also being able to represent values as small as 2^-14. However, given that OpenEXR is a HDR format, you are probably not really expected to use the entire range because the number encoding is chosen to accomodate for (extreme) over- or underexposure. That is, unless your camera actually produces such an enormous dynamic range of values.
So you might not actually need to scale your channel values. However, given that you already start with values in [0, 1], you probably have floating point numbers stored in single or double precision and you'll have to transcode them to half precision. Depending on the programming language, the libraries and even the hardware platform that you use, there might be an off-the-shelf solution or you might need to do some bit-fiddling of your own. As a starting point I can only offer you this DuckDuckGo search.