#compression #vector #normal #memory #bandwidth #vertex-shader #3d

normal_pack

Compresses normal vectors (or any 3D unit vector) using Octahedron encoding

5 releases

0.1.4 Jul 22, 2024
0.1.3 Jul 18, 2024
0.1.2 Jul 18, 2024
0.1.1 Jul 18, 2024
0.1.0 Jul 18, 2024

#590 in Encoding

34 downloads per month

MIT license

20KB
194 lines

Compresses normal vectors (or any 3D unit vector) using Octahedron encoding.

Crates.io Documentation License: MIT

This lossy compression scheme is able to achieve a compression ratio as high as 6:1 with an average error rate of less than 1 degree, depending on which representation is chosen.

Example:

let normal = [-0.5082557, 0.54751796, 0.6647558];

let encoded = normal_pack::EncodedUnitVector3U8::encode(normal);
let decoded = encoded.decode();

assert_eq!(decoded, [-0.52032965, 0.5473598, 0.6554802]);

Why compress my normals?

It is common for 3D renderers to be bottlenecked by memory bandwidth, such as when loading normals from VRAM for high-poly meshes to supply to your vertex shader. A smaller memory footprint for your normals corresponds to memory bandwidth savings and higher FPS in such scenarios.

How bad is 1 degree of error?

The teapot example generates a reference visual and contains the wgsl code required to decode the vector in a shader.

Standard [f32; 3] representation

teapot_packed_u8

Packed into a [u8; 2]

teapot_no_packing

As a video

normal_pack_error

The skybox used in the example is the work of Emil Persson, aka Humus. http://www.humus.name

Dependencies

~0–0.8MB
~16K SLoC