How Lightmaps Are Structured in glTF Models

This article explores the structural composition of lightmaps embedded in glTF (GL Transmission Format) 3D assets, examining how baked illumination data is integrated into the format's JSON hierarchy and binary payloads. It covers the storage of image and buffer data, the essential role of secondary UV texture coordinates, and the extension mechanisms used to bind baked lighting data to 3D surfaces.

Image Data and Binary Storage

Lightmaps within a glTF container are fundamentally stored as texture resources, organized across standard glTF top-level arrays: images, textures, samplers, and bufferViews.

  • The images Array: Defines the raw lightmap asset. If the glTF is stored as an embedded .gltf or binary .glb file, the image is mapped to a specific bufferView pointing to a binary chunk. Common formats include PNG, JPEG, or compressed GPU formats like KTX2 (via the KHR_texture_basisu extension) for lower memory consumption.
  • The samplers Array: Dictates filtering and wrapping behavior. Lightmaps typically use LINEAR or LINEAR_MIPMAP_LINEAR filtering with CLAMP_TO_EDGE wrapping to prevent illumination leaking across tile boundaries.
  • The textures Array: Pairs an image index with a sampler index, creating a complete texture resource that materials can reference.

UV Mapping: The Role of TEXCOORD_1

Unlike diffuse or normal maps that frequently reuse overlapping, mirrored, or tiled UV layouts, lightmaps require unique, non-overlapping UV unwraps for all static surfaces receiving baked illumination.

Inside the glTF hierarchy, this is handled under the mesh primitives:

"primitives": [
  {
    "attributes": {
      "POSITION": 0,
      "NORMAL": 1,
      "TEXCOORD_0": 2,
      "TEXCOORD_1": 3
    },
    "indices": 4,
    "material": 0
  }
]
  • TEXCOORD_0 typically carries the repeating tiling data for base color and material maps.
  • TEXCOORD_1 points to an accessor containing the dedicated, globally unique UV coordinates dedicated to reading the lightmap across the mesh surface.

Material Bindings and glTF Extensions

The core glTF 2.0 specification does not provide a native lightmapTexture property inside standard PBR materials. Consequently, lightmaps are structurally integrated through one of three primary methodologies:

  1. Vendor and Community Extensions: Extensions such as MOZ_lightmap or custom engine extensions inject a lightmapTexture object directly into the material.extensions definition. This object references the texture index and explicitly states which texCoord channel to evaluate, along with scaling factors for exposure control.
  2. Repurposed Occlusion Slots: In workflows lacking custom extension support, pipelines sometimes inject the lightmap into the standard occlusionTexture slot. While structurally compliant with core glTF 2.0, this approach limits lighting evaluation to single-channel scalar values or non-standard engine interpretations of RGB occlusion maps.
  3. Multi-Material Layering via Composition: Advanced pipelines split geometries or evaluate secondary primitive passes using unlit materials (KHR_materials_unlit) that carry the lightmap data, allowing external rendering engines to multiply the light pass against the diffuse surface pass at runtime.

Data Composition at Runtime

When an engine parses an embedded lightmap in glTF, it resolves the dependency graph from the material through the designated texture accessor, fetches the non-overlapping coordinates from TEXCOORD_1, and decodes the image binary from the underlying buffer. The rendering engine multiplies or adds this precomputed radiance directly into the fragment stage of the PBR pipeline, replacing or augmenting dynamic ambient calculations.