How glTF References External Image Files

The glTF (GL Transmission Format) specification allows 3D assets to reference external textures rather than bundling them into binary containers or Base64-encoded strings. By utilizing the top-level images array within the model's core JSON document, glTF assigns external Uniform Resource Identifiers (URIs) to texture assets. This article explains the JSON schema mechanisms behind external image referencing, the texture-to-material linking pipeline, and how runtime engines resolve these assets.

The images Array and the uri Property

In a standard .gltf file, image definitions are organized in a top-level JSON array named images. When images are not embedded in a binary buffer via a bufferView, each image object specifies a uri property that points directly to the external file location.

{
  "images": [
    {
      "uri": "textures/albedo.png"
    },
    {
      "uri": "textures/roughness_metallic.jpg"
    }
  ]
}

The uri string follows the RFC 3986 standard. In practical workflows, this is almost always a relative file path pointing to an asset located in the same directory as the .gltf file or in a designated subfolder (such as textures/). Absolute web URLs (e.g., https://example.com/textures/albedo.png) are also valid according to the specification.

Connecting Images to Materials

An external image is not directly assigned to a 3D mesh. Instead, glTF follows an indexed reference chain that links geometries to visual properties:

  1. Materials (materials): A material references a texture index for specific slots, such as baseColorTexture or metallicRoughnessTexture.
  2. Textures (textures): A texture object combines an image source with a sampler, defining how the image is filtered and wrapped. It references the index of the image via the source property.
  3. Images (images): The image entry contains the uri to the external asset.
{
  "materials": [
    {
      "name": "WoodMaterial",
      "pbrMetallicRoughness": {
        "baseColorTexture": {
          "index": 0
        }
      }
    }
  ],
  "textures": [
    {
      "sampler": 0,
      "source": 0
    }
  ],
  "images": [
    {
      "uri": "textures/wood_baseColor.png"
    }
  ]
}

In this structure, baseColorTexture points to textures[0], which in turn sets source: 0, directing the rendering engine to load images[0] from textures/wood_baseColor.png.

Runtime Path Resolution

When a 3D runtime engine (such as Three.js, Babylon.js, or a custom OpenGL/Vulkan loader) parses a .gltf file, it resolves relative URIs against the base URI of the .gltf document itself.

For example, if the model is fetched from https://assets.example.com/models/chair/scene.gltf and an image entry specifies textures/wood.png, the engine constructs the fully qualified URL https://assets.example.com/models/chair/textures/wood.png to download the texture asynchronously.

Format Handling and MIME Types

Standard glTF 2.0 natively supports PNG and JPEG formats for external images. An optional mimeType property can be included within the image object:

{
  "uri": "textures/normal_map.png",
  "mimeType": "image/png"
}

While loaders typically infer the format from the file extension or the external file's response headers, explicitly specifying mimeType removes ambiguity for custom loaders or environments where file extensions are omitted.

Advantages of External Referencing

Referencing external images provides several functional benefits over embedding:

  • Efficient Caching: Browsers and runtimes can cache individual image files independently of the 3D scene geometry.
  • Shared Assets: Multiple separate glTF files can point to the same texture files on disk or over the network, reducing duplication.
  • Asset Pipeline Flexibility: High-resolution source images can be replaced, compressed, or generated as web-optimized variants (such as WebP or KTX2 textures via extensions) without rewriting the binary geometry buffers.