packHalf2x16
Converts the two 32-bit floating-point components of a vec2 into 16-bit half floats and packs them into a single 32-bit unsigned integer (uint), for compact storage of two float values.
Core Advantages
Reduces bandwidth and memory usage by storing two float channels inside one uint, while delegating the actual float16 packing logic to the backend via builder.getFloatPackingMethod('float16'). This avoids hand-written bit-twiddling and keeps the implementation consistent across GLSL / WGSL and different backends.
Common Uses
Packing roughness and metallic (or other scalar PBR parameters) into a single uint in a custom G-buffer, reducing the number of color channels or the size of your render targets.
Storing pairs of parameters in storage buffers / SSBOs (for example intensity + radius, velocity + falloff) so that compute or post-processing passes can read them efficiently.
Down-converting high-precision float data to half precision for caching or transmission and later decoding it in another pass or on the CPU using the same float16 layout.
Designing custom packed formats where different 16-bit halves represent different quantities (e.g., using the high 16 bits for a time slice and the low 16 bits for an amplitude or weight).
How to adjust
packHalf2x16 itself only takes a vec2 input and exposes no extra parameters. The main tuning points are: (1) control the value range and precision of the input; half floats have less precision and a limited dynamic range, so they are best suited for normalized [0,1] parameters or data that can tolerate quantization; (2) optionally normalize or scale your values before packing (for example divide a [0,10] range by 10 before packing and multiply by 10 after unpacking); (3) remember that the output type is uint and should be treated as a packed container, not as a regular float or color—write it to uint buffers or textures and only interpret it via matching unpack logic; (4) if your pipeline uses additional packing functions (snorm/unorm variants, etc.), make sure the encode and decode sides agree on the same encoding convention.
Code Examples
1// Example: pack roughness and metallic into a single uint for compact storage
2const rmVec2 = vec2( roughnessNode, metalnessNode );
3
4// Convert both components to float16 and pack them into one uint
5const packedRM = packHalf2x16( rmVec2 );
6
7// packedRM is typically written to a uint buffer or texture
8// Here we only show how to build the node; the actual write depends on your
9// storageObject / custom pipeline and is usually decoded in a later pass.