Interleaved vs Planar Vertex Data in glTF

In 3D graphics rendering with glTF assets, structuring vertex attributes in either an interleaved or planar layout directly impacts memory bandwidth, GPU cache efficiency, and runtime rendering throughput. This article examines the core performance trade-offs between interleaved and planar (separate) vertex data layouts in glTF files, detailing how each format behaves during general rasterization, specialized rendering passes, dynamic updates, and cross-platform GPU pipelines.

Understanding Vertex Data Layouts

Vertex data defines the geometry of a 3D model through multiple attributes, including position, normal, tangent, texture coordinates, and joint weights. In glTF, these attributes are stored in binary buffers (bufferViews) and referenced via accessors in two primary ways:

  • Interleaved Data: All attributes for a single vertex are stored contiguously in memory ([Pos0, Norm0, UV0, Pos1, Norm1, UV1, ...]).
  • Planar Data (Separate Streams): Each attribute type is stored in its own dedicated, contiguous array ([Pos0, Pos1, ...], [Norm0, Norm1, ...], [UV0, UV1, ...]).

Cache Coherency and Standard Rendering

For general rendering passes where the vertex shader processes all or most vertex attributes simultaneously, interleaved data is significantly more efficient.

GPUs fetch memory in discrete cache lines, typically 32, 64, or 128 bytes wide. When vertex attributes are interleaved, reading the position of a vertex automatically pulls the vertex's normals, tangents, and UVs into the L1/L2 cache. This maximizes spatial locality, reduces memory latency, and ensures high utilization of each fetched cache line.

Conversely, planar data spreads the attributes across different memory addresses. A vertex shader consuming four distinct attributes must issue read operations across four separate memory locations simultaneously. This increases cache pressure, causes higher cache miss rates, and can degrade vertex shader execution throughput.

Bandwidth Efficiency in Depth and Shadow Passes

While interleaved data optimizes full-attribute passes, it introduces performance penalties during passes that require only a subset of attributes. Common examples include:

  • Depth Pre-Passes: Only require vertex positions to populate the depth buffer.
  • Cascaded Shadow Maps: Typically need only position data to compute occluder depth.
  • Position-Only Visibility Buffers: Common in modern deferred rendering and virtualized geometry architectures.

When executing a depth-only pass with interleaved data, the GPU fetches full cache lines containing unused normals, UVs, and vertex colors just to read the position vector. This results in wasted memory bandwidth and cache thrashing.

Planar data avoids this issue entirely. By isolating positions into a single contiguous buffer, depth passes read only the exact bytes required, reducing memory bandwidth usage by 50% to 75% depending on the total vertex footprint.

Dynamic Updates and Streaming

When vertex attributes need to be modified at runtime—such as CPU-driven procedural mesh deformation, dynamic vertex coloring, or morph targets—planar layouts provide superior flexibility and performance.

  • Partial Buffer Updates: With a planar layout, an application can upload a new stream of positions or normals without re-uploading unchanged attributes, minimizing PCIe bus traffic.
  • Interleaved Updates: Modifying a single attribute in an interleaved buffer requires either rewriting the entire interleaved structure or performing fragmented memory writes, which degrades transfer speeds between the CPU and GPU.

Optimal Hybrid Strategy

To balance both cache locality and bandwidth efficiency, modern glTF workflows often adopt a hybrid approach:

  1. Position Stream (Planar): Store positions in a separate, isolated buffer view (bufferView). This provides peak bandwidth efficiency for depth passes, shadow mapping, and occlusion culling.
  2. Rendering Attributes (Interleaved): Interleave the remaining attributes (normals, tangents, texture coordinates, colors) into a second shared buffer view. These attributes are always consumed together during main shading passes.
  3. Skinning Data (Optional Separation): Joint indices and weights can either be interleaved with general shading data or placed in a dedicated stream, depending on whether compute-shader skinning or hardware vertex skinning is employed.

This split layout prevents bandwidth waste during depth rendering while maintaining strong GPU cache utilization during full-geometry rendering passes.