Unpacking Signed Floats with GLSL unpackSnorm4x8
The unpackSnorm4x8 built-in function in the OpenGL
Shading Language (GLSL) decodes a single 32-bit unsigned integer into a
four-component floating-point vector (vec4) with values
normalized between -1.0 and 1.0. This article breaks down the internal
mechanism of unpackSnorm4x8, explaining how it segments raw
32-bit integers, interprets individual 8-bit slices as signed values,
and applies fixed-point normalization mathematics to restore coordinate
data such as surface normals or tangent vectors.
1. Bitwise Extraction
A GLSL uint consists of 32 contiguous bits. The
unpackSnorm4x8 function treats this integer as a packed
sequence of four distinct 8-bit fields. The extraction sequence maps
bits into the components of a vec4 from lowest-order byte
to highest-order byte:
- Component X: Bits 0 through 7
- Component Y: Bits 8 through 15
- Component Z: Bits 16 through 23
- Component W: Bits 24 through 31
2. Signed Integer Interpretation
Each isolated 8-bit sequence is reinterpreted as a signed two's complement integer. In this format:
- Bit values range from
0x00through0xFFin binary. - Interpreted as signed 8-bit integers (\(c\)), the numerical range extends from -128 to 127.
- Values from
0x00to0x7Frepresent0to127. - Values from
0x80to0xFFrepresent-128to-1.
3. Normalization Formula
According to the OpenGL and GLSL specifications, signed normalized
(snorm) values map to standard floating-point coordinates
using division by \(2^{b-1} - 1\),
where \(b\) is the number of bits
(\(8\)). For 8-bit precision, this
divisor is \(127.0\).
The exact formula applied to each signed 8-bit integer \(c\) is:
\[f = \max\left(\frac{c}{127.0}, -1.0\right)\]
This formula performs the following mapping:
- Positive Maximum: A value of
127yields \(127 / 127.0 = 1.0\). - Zero Point: A value of
0yields \(0 / 127.0 = 0.0\), guaranteeing an exact representation of zero. - Negative Base: A value of
-127yields \(-127 / 127.0 = -1.0\). - Asymmetry Clamping: Because an 8-bit two's
complement integer accommodates
-128, the quotient \(-128 / 127.0 \approx -1.007874\). Themaxoperation clamps this result to \(-1.0\). Both-128and-127evaluate to \(-1.0\), resolving the structural asymmetry of two's complement encoding.
Output and Applications
After processing all four bytes, unpackSnorm4x8 returns
the completed vec4(x, y, z, w) where every component
satisfies \(-1.0 \le \text{component} \le
1.0\).
This process allows graphics pipelines to pack 3D normal vectors (and an auxiliary scalar) into a single 32-bit attribute or uniform buffer entry, reducing vertex buffer memory footprint and memory bandwidth usage while preserving spatial coordinate accuracy upon shader execution.