Skip to content

Texture occupancy

Sebastien DUMETZ edited this page Oct 20, 2026 · 1 revision

Texture occupancy calculation

The README documents the inspect command and report. This page describes how texture coverage is computed.

Sampling footprints, transforms and wrapping

Texture occupancy is the fraction of base-color texture texels a renderer reads when drawing the model, counting texels shared by several triangles once. Padding and unused atlas space are excluded.

A texel counts when sampling some point of a UV triangle reads it from the full-resolution level, following the texture's glTF sampler as engines do. With linear filtering (the default, and what import writes) that is the 2×2 texels around the point: every texel whose center is less than one texel away on each axis, so charts extend half a texel beyond their edges. With nearest filtering (magFilter and minFilter both nearest) it is the texel containing the point.

UV transforms and wrapping

UVs go through the texture's KHR_texture_transform first, when it has one: offset, rotation, scale and texCoord override, as the extension's reference shader applies them. Wrap modes (repeat, mirrored repeat, clamp) apply to these footprints too, so with repeat a chart touching an edge also reads the opposite edge. The global figure is used texels over total texels; each image also reports its own size and occupancy. A triangle that repeats its texture more than 64 times vertically is left out with a warning.

Why filtering changes the count

This follows how GPUs filter textures. OpenGL, OpenGL ES, WebGL and Vulkan define linear filtering at texel coordinate u as a blend of texels ⌊u − ½⌋ and ⌊u − ½⌋ + 1 on each axis, whose weights vanish only exactly at a texel center. So a texel is read whenever a sample falls less than one texel from its center. glTF leaves unset filters to the implementation, and common engines such as three.js and Babylon.js default to linear filtering, with mipmaps for minification. Counting only texels whose center a triangle covers would miss texels engines do read: along chart borders, and under triangles smaller than a texel. Lower mipmap levels are not counted: they are derived from the base level, padding included.

Coverage maps and image metadata

Coverage uses one bit per texel in a sparse workspace file for each image, memory-mapped like the import spools. A 16k × 16k texture needs a 32 MiB coverage map. Overlapping triangles set the same bits, so shared texels count once.

Geometry buffers are mapped read-only. Image dimensions come from file headers without decoding pixels. OBJ and VRML inputs are imported privately with images referenced in place, avoiding conversion before inspection.

How it works · Documentation home

Clone this wiki locally