Handling Texture Atlas Border Clamping in glTF

In glTF 2.0, texture samplers apply wrapping and clamping behaviors exclusively to the entire image asset rather than to individual sub-tiles within a texture atlas. Because the specification lacks native sub-rectangle clamping parameters, sampling atlas tiles requires specific authoring techniques—such as padding, texel extrusion, or custom shader logic—to prevent visual artifacts like texture bleeding. This article explores how glTF texture samplers function, why border clamping fails on atlas tiles by default, and how to properly handle these constraints.

glTF Texture Sampler Wrap Modes

The glTF specification defines texture sampling behavior using the sampler object, which provides wrapS and wrapT properties. These properties support three standard WebGL/OpenGL wrap modes:

  • CLAMP_TO_EDGE (33071): Clamps coordinates to the range [0.0, 1.0], repeating the outermost edge texels of the full image.
  • REPEAT (10497): Tiles the texture by ignoring the integer component of the UV coordinates.
  • MIRRORED_REPEAT (33648): Tiles the texture while flipping it at every integer boundary.

These wrap modes are executed at the hardware sampler level across the complete dimensions of the assigned image file.

The Sub-Tile Clamping Problem

A texture atlas packs multiple independent textures into distinct UV sub-rectangles (e.g., from [0.0, 0.0] to [0.5, 0.5]). When a 3D model samples an atlas tile, the GPU's hardware sampler has no contextual awareness of the sub-tile's boundaries.

If a material's UV coordinates cross or touch the perimeter of an assigned atlas tile:

  1. Wrap Mode Failures: Setting the glTF sampler to CLAMP_TO_EDGE clamps UVs to the edges of the entire atlas, not the sub-tile boundaries. A UV coordinate exceeding the sub-tile border continues reading into adjacent tiles.
  2. Bilinear/Trilinear Filtering Bleed: Linear interpolation blends samples from adjacent texels. Texels right on the boundary of an atlas tile will blend with the texels of neighboring tiles.
  3. Mipmapping Artifacts: As lower-resolution mip levels are generated, texels from different tiles merge together, resulting in visible discoloration or seams around the geometry edges at distant viewing angles.

Solutions for Atlas Border Clamping in glTF

Because glTF does not offer an arbitrary tile clamp mechanism in its core specification, developers must mitigate atlas clamping issues using the following methods:

The standard and fully glTF-compliant approach is to build the atlas with safety margins around each sub-tile:

  • Gutters: Leave empty space between sub-tiles.
  • Texel Extrusion (Bilinear Padding): Duplicate the outer single-pixel edge of each sub-tile into the gutter. This ensures that linear interpolation pulls identical edge colors instead of neighboring textures.
  • Mipmap Sizing: Ensure the padding thickness is large enough for the lowest mip level used (e.g., a margin of 16 to 32 pixels for a \(2048 \times 2048\) atlas).

2. UV Range Clamping via Shaders

If rendering outside the constraints of an unextended glTF viewer, you can enforce sub-tile clamping inside the fragment shader:

vec2 clampedUV = clamp(v_UV, tileMinUV, tileMaxUV);
vec4 color = texture(u_Atlas, clampedUV);

While this restricts the UV coordinates to the tile's defined sub-rectangle, it requires passing bounding bounds per-material or per-draw call, which is not supported in the standard KHR_texture_transform extension.

3. Limitations of KHR_texture_transform

The KHR_texture_transform extension allows offset and scale controls for UV coordinates. While it can map geometry UVs to the correct sub-rectangle of an atlas, it only scales and offsets coordinates; it does not introduce boundary clamping logic.

4. Array Textures as an Alternative

When independent clamping and wrapping are strictly required without atlas bleeding, modern pipelines often abandon 2D atlases in favor of 2D Texture Arrays. Texture arrays preserve individual texture boundaries, allowing standard CLAMP_TO_EDGE behavior on every layer without cross-tile contamination.