glTF Accessor Types: Scalar vs Vector vs Matrix

In a glTF file, accessors act as the bridge between raw binary buffer data and structured 3D graphics information. The accessor's type attribute specifies how individual data elements are grouped mathematically, defining whether an entry represents a single value, a directional coordinate, or a transformation matrix. This guide breaks down the core differences between SCALAR, vector (VEC2, VEC3, VEC4), and matrix (MAT2, MAT3, MAT4) accessor types, detailing their component structures, memory arrangements, and typical use cases in 3D rendering pipelines.

Understanding Accessors and Component Types

A glTF accessor reads raw bytes from a bufferView and structures them into usable geometry or animation data. While the componentType dictates the underlying numeric format of each number (such as FLOAT, UNSIGNED_SHORT, or BYTE), the type property determines the dimensionality—the number of scalar values grouped together to form a single element.

SCALAR

The SCALAR type represents a single numeric value per element. It has exactly one component.

  • Component Count: 1
  • Memory Structure: Each element occupies the exact byte size of its componentType (for example, 4 bytes for a FLOAT or 2 bytes for an UNSIGNED_SHORT).
  • Common Use Cases:
    • Mesh Indices: Defining the triangle vertex order (often paired with UNSIGNED_SHORT or UNSIGNED_INT).
    • Animation Timestamps: Time keys in animation samplers defining when frames occur.
    • Morph Target Weights: Intensity values controlling blend shapes.

Vector Types: VEC2, VEC3, and VEC4

Vector types represent grouped tuples of components, typically defining geometric directions, positions, or multi-channel properties.

  • VEC2 (2 Components):
    • Typically used for 2D coordinates.
    • Common Use Cases: Texture coordinates (UVs) mapped across vertex geometry.
  • VEC3 (3 Components):
    • Represents 3D Cartesian coordinates or direction vectors.
    • Common Use Cases: Vertex positions (POSITION), vertex normals (NORMAL), and 3D animation channels for translation and scaling.
  • VEC4 (4 Components):
    • Represents 4D spatial data, quaternions, or color values.
    • Common Use Cases:
      • Vertex tangents (TANGENT, where the 4th component represents the sign/handedness).
      • Rotations stored as quaternions (x, y, z, w) for nodes and skeletal joints.
      • Vertex colors (COLOR_0) containing RGBA channels.
      • Skinning attributes, such as JOINTS_0 and WEIGHTS_0, which bind up to four bones to a single vertex.

Matrix Types: MAT2, MAT3, and MAT4

Matrix types represent square arrays of numbers used to compute spatial transformations, rotations, and shear operations.

  • MAT2 (4 Components): A 2x2 matrix, rarely used in core glTF workflows.
  • MAT3 (9 Components): A 3x3 matrix, occasionally used for 2D affine transformations or custom normal transformations.
  • MAT4 (16 Components): A 4x4 affine transformation matrix.
    • Common Use Cases: Inverse bind matrices for skeletal animation (IBM), used to transform vertices from model space into the local bone space of a skeleton.

Critical Matrix Detail: Column-Major Order

glTF matrices are strictly stored in column-major order. For a MAT4, the 16 floating-point values are read down the columns rather than across rows:

\[ \begin{bmatrix} m_0 & m_4 & m_8 & m_{12} \\ m_1 & m_5 & m_9 & m_{13} \\ m_2 & m_6 & m_{10} & m_{14} \\ m_3 & m_7 & m_{11} & m_{15} \end{bmatrix} \]

In the binary buffer, the sequence appears linearly as [m0, m1, m2, m3, m4, ...].

Summary Comparison

Accessor Type Components per Element Primary Purpose Standard Example
SCALAR 1 Single values, IDs, keyframe times Primitive indices
VEC2 2 2D coordinates UV mappings (TEXCOORD_0)
VEC3 3 3D points, vectors, directions Vertex positions (POSITION)
VEC4 4 Quaternions, RGBA colors, skin weights Bone rotations, joint indices
MAT2 4 2x2 transforms 2D geometry adjustments
MAT3 9 3x3 transforms Tangent space transformations
MAT4 16 4x4 spatial transformations Inverse bind matrices

To calculate the total byte size consumed by an accessor, multiply the total accessor count by the component count of the type, and then multiply that product by the byte length of the assigned componentType.