How GLSL textureGatherOffset Fetches Texels with Offset
The textureGatherOffset function in GLSL retrieves a
four-component vector containing a single color channel from the four
texels that would be used in standard bilinear filtering, while shifting
the sampling footprint by a specified integer texel offset. This
built-in function enables shaders to efficiently sample a \(2 \times 2\) grid of neighboring values in
a single operation without performing multiple texture lookups or manual
floating-point coordinate arithmetic. By allowing precise integer-based
offsets directly in texel space, it simplifies algorithms such as
Percentage-Closer Filtering (PCF) for shadows, ambient occlusion, and
custom reconstruction filters.
Sampling Footprint and the Integer Offset
When sampling a 2D texture, normalized floating-point coordinates \((u, v)\) locate a point in continuous coordinate space. In standard bilinear filtering, the hardware identifies the four nearest texel centers surrounding this continuous position.
textureGatherOffset alters this process by accepting an
ivec2 offset argument alongside the standard texture
sampler and coordinate. The offset values represent whole texels and are
added directly to the unnormalized texel coordinates before determining
the \(2 \times 2\) sampling
footprint:
\[\text{Target Texel Base} = \lfloor \text{coord} \times \text{textureSize} - 0.5 \rfloor + \text{offset}\]
Because the offset is applied directly to discrete texel indices, it
avoids floating-point precision inaccuracies that can occur when
converting normalized UV coordinates back and forth. The hardware
enforces compile-time or runtime bounds on this offset, typically
constrained within the range \([-8,
7]\) as defined by the implementation's
GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET and
GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET.
Texel Layout in the Returned Vector
Unlike standard texture lookups that return an interpolated RGBA
color, textureGatherOffset samples only one selected color
component (specified by the optional comp parameter,
defaulting to channel 0 / Red) across all four neighboring texels.
The returned vec4 maps the four neighboring texels in a
counter-clockwise order relative to the base texel \((i_0, j_0)\):
xcomponent: Texel at \((i_0, j_1)\) — bottom-left in coordinate systems where \(v\) increases downward, or top-left in standard OpenGL UV space where \(v\) increases upward.ycomponent: Texel at \((i_1, j_1)\) — adjacent toxin the positive \(u\) direction.zcomponent: Texel at \((i_1, j_0)\) — adjacent toyin the negative \(v\) direction.wcomponent: Texel at \((i_0, j_0)\) — base texel with the lowest \(u\) and \(v\) indices.
Here, \(i_1 = i_0 + 1\) and \(j_1 = j_0 + 1\).
Example Usage
#version 450 core
uniform sampler2D shadowMap;
in vec2 uvCoords;
out vec4 outTexels;
void main()
{
// Fetches the red component from a 2x2 grid shifted by (-1, 2) texels
ivec2 offset = ivec2(-1, 2);
outTexels = textureGatherOffset(shadowMap, uvCoords, offset, 0);
}Performance Benefits
Using textureGatherOffset significantly reduces memory
bandwidth and instruction overhead. Fetching four discrete texels
typically requires four separate texelFetch or
texture calls, consuming four texture pipeline cycles.
textureGatherOffset executes the retrieval in a single
texture fetch instruction, providing direct access to raw neighbor data
for fast hardware-accelerated filtering and image processing
pipelines.