Sampling 2D Texture Arrays in GLSL
Sampling layered 2D texture arrays from multi-layer render targets in GLSL involves using dedicated array samplers and a three-component texture coordinate system. This article explains how to declare the proper sampler types, configure three-dimensional coordinates where the third component represents the layer slice, choose between normalized and unnormalized fetching functions, and avoid common pitfalls when reading from layered framebuffers.
Declaring the Sampler
To read from a 2D texture array (GL_TEXTURE_2D_ARRAY)
attached to a multi-layer framebuffer, declare a uniform using the
sampler2DArray type in your fragment shader:
uniform sampler2DArray u_LayeredTexture;For integer-based render targets, use isampler2DArray or
usampler2DArray. For depth comparison textures, use
sampler2DArrayShadow.
Coordinate Structure
Unlike standard 2D textures that require a vec2
coordinate, a 2D texture array requires a vec3:
- Component 1 (
soru): Horizontal normalized coordinate along the target layer, typically in the range[0.0, 1.0]. - Component 2 (
torv): Vertical normalized coordinate along the target layer, typically in the range[0.0, 1.0]. - Component 3 (
porlayer): A floating-point layer index referencing the zero-based layer slice (e.g.,0.0for layer 0,1.0for layer 1).
Normalized Sampling with
texture()
When using linear or nearest-neighbor filtering with normalized
coordinates, call the texture() function passing the
sampler2DArray and the vec3 coordinate:
in vec2 v_TexCoord;
uniform int u_TargetLayer;
out vec4 FragColor;
void main()
{
vec3 coords = vec3(v_TexCoord, float(u_TargetLayer));
FragColor = texture(u_LayeredTexture, coords);
}The layer index is rounded to the nearest integer layer during
sampling, and OpenGL clamps it to the range
[0, maxLayers - 1]. Filtering modes such as
GL_LINEAR interpolate only within the selected 2D slice;
they do not filter across adjacent layers.
Unnormalized
Direct Fetching with texelFetch()
For post-processing passes, deferred rendering G-buffers, or exact
pixel operations where filtering is undesirable, use
texelFetch(). This function bypasses filtering and operates
on integer coordinates:
ivec2 pixelCoord = ivec2(gl_FragCoord.xy);
int layerIndex = 2;
int lod = 0;
vec4 data = texelFetch(u_LayeredTexture, ivec3(pixelCoord, layerIndex), lod);The third vector component of the ivec3 directly
specifies the integer layer index.
Framebuffer Setup Considerations
Before reading, the texture array must be unlinked from the active
write framebuffer or bound to a separate texture unit after rendering to
avoid read-after-write hazards. When rendering to layers initially, the
target is bound to an FBO via glFramebufferTexture() for
layered rendering via geometry shaders or multiview extensions, or via
glFramebufferTextureLayer() for per-layer rendering passes.
Once drawing commands complete, bind the texture to an active texture
unit using glBindTextureUnit() or
glBindTexture(GL_TEXTURE_2D_ARRAY, ...), update the sampler
uniform, and execute your sampling shader.