Ambient Occlusion on UV1 with Base Color on UV0 in glTF

In glTF 2.0, materials can simultaneously utilize multiple UV sets by routing different texture maps to specific texture coordinate channels. This allows developers and 3D artists to map a tiled base color texture to the primary UV layout (UV0) while applying a baked ambient occlusion map to a secondary, non-overlapping unwrapped layout (UV1). This capability is achieved by explicitly defining the texCoord property inside the material's texture reference objects and ensuring the underlying mesh contains the corresponding vertex attributes.

The Role of the texCoord Property

Every texture reference within a glTF material is encapsulated in a texture info object. By default, any texture info object without an explicit coordinate definition targets the first UV set, represented internally as index 0.

To split coordinates between textures:

  • baseColorTexture utilizes texCoord: 0, which maps to the mesh attribute TEXCOORD_0 (UV0).
  • occlusionTexture utilizes texCoord: 1, which maps to the mesh attribute TEXCOORD_1 (UV1).

The glTF JSON Structure

Below is an excerpt demonstrating how the material and the mesh primitive must be structured within the glTF file:

{
  "materials": [
    {
      "name": "MultiUV_Material",
      "pbrMetallicRoughness": {
        "baseColorTexture": {
          "index": 0,
          "texCoord": 0
        }
      },
      "occlusionTexture": {
        "index": 1,
        "texCoord": 1,
        "strength": 1.0
      }
    }
  ],
  "meshes": [
    {
      "primitives": [
        {
          "attributes": {
            "POSITION": 0,
            "NORMAL": 1,
            "TEXCOORD_0": 2,
            "TEXCOORD_1": 3
          },
          "material": 0,
          "indices": 4
        }
      ]
    }
  ]
}

Key Implementation Steps

  1. Generate Two UV Sets on the Mesh: In your 3D modeling tool, create two separate UV channels. UV0 can contain overlapping or tiled islands optimized for high-frequency detail on the base color map. UV1 must be completely unwrapped without overlapping islands, ensuring clean baking for ambient occlusion.

  2. Verify Mesh Primitive Attributes: The mesh must export both TEXCOORD_0 and TEXCOORD_1 in its attributes dictionary. If TEXCOORD_1 is omitted from the mesh geometry, the runtime engine will fallback to TEXCOORD_0 or fail to render the ambient occlusion effect properly.

  3. Assign Texture Coordinate Indices: In the material definition, explicitly define "texCoord": 1 inside the occlusionTexture block. The baseColorTexture can explicitly state "texCoord": 0, though omitting the property also defaults to 0.

  4. Exporter Configuration: When exporting from software like Blender, ensure the material node setup routes a dedicated UV Map node set to the secondary UV channel into the vector input of the ambient occlusion texture node. Ensure that standard glTF export settings have both "UVs" and material export enabled so that both UV channels are written to the buffer views.