MaterialLayout implementation that packs each material into a single
contiguous byte blob (array-of-structs) via pack(), grouping materials
by their packed size into separate buckets - materials using different
strategies with different field sets don’t have to share a stride.
Computes std430-compatible byte offsets for fields, in order, and the
total size of the packed struct, rounded up to a 16-byte multiple as
std430 requires for a struct used as an SSBO array element.