The Interactive & Immersive HQ

TexelFetch() vs texture() in GLSL

Texturing in GLSL can be performed in different ways. That’s why today we will have a look at the differences between the texelFetch() and texture() functions. Let’s go.

GLSL OpenGL Shading Language – is one of the most powerful tools for visual development. It is a C-style language and performs high-level operations on shaders, to say functions that calculates position and color of pixels.

This is just a basic definition. GLSL is a complex world with lots of great features. And of course we can get the most out of GLSL in TouchDesigner through the dedicated GLSL TOP operator.

In this article we will talk about the primary ways to work with textures in GLSL. This is where the texture() and texelFetch() functions come into play.

The texture() function

texture() is the most common used function for texturing in GLSL. It allows us to handle filter and normalized texture in the 0-1 domain.

texture() works with normalized floating point texture coordinates between 0 and 1, from left to bottom and from right to the top. It can perform wrapping – the coordinates can exceed the 0-1 range – and filtering, to say getting the exact texel color is not required. It is important to underline as well that the texture() function is infinitely interpolating.

Two arguments are required as input. The first one is the texture (sampler2D) and the second is the UV coordinate to sample. So a typical texture() function looks like this:

in vec2 TexCoords; //uv coordinates
out vec4 FragColor;
uniform sampler2D myTexture; //the texture

void main() {
    vec4 texColor = texture(myTexture, TexCoords);
    FragColor = texColor;
}

texture() is somehow the traditional approach to texturing in GLSL. But sometimes we need to perform operations in the integer domain. That is why we can switch to the texelFetch() function.

Get Our 7 Core TouchDesigner Templates, FREE

We’re making our 7 core project file templates available – for free.

These templates shed light into the most useful and sometimes obtuse features of TouchDesigner.

They’re designed to be immediately applicable for the complete TouchDesigner beginner, while also providing inspiration for the advanced user.

The texelFetch() function

There are several differences between the texture() and the texelFetch() function.

texelFetch() accesses a texel – an element containing information about colors and alpha values – directly. It does not perform filtering or wrapping and works on non-normalized coordinates. So, while texture() is in the 0-1 domain, the texelFetch() works with the texture integer coordinates.

Let’s suppose we want to access a texel in the middle of a 512×512 texture. texture() coords will be 0.5-0.5, while texelFetch() coords will be 256-256.

So it is important to remember that texture() works with normalized texture coordinates (0 to 1) while texelFetch() works with texel space, ranging from 0 to the size of the texture.

The texelFetch() function takes three arguments as input. The first one is the texture (sampler2D), the second is the UV coordinate in integer pixels, the third is the so called LOD (Level of Detail), which is the level of detail in the mipmap. To keep the original size we can pass 0 to this argument.

So a typical texelFetch() function looks like this:

in vec2 TexCoords; //uv coordinates
out vec4 FragColor;
uniform sampler2D myTexture; //the texture
uniform ivec2 textureSize; //the texture size

void main() {
ivec2 texelCoord = ivec2(TexCoords * vec2(textureSize)); //convert uv coordinates in integer pixels
vec4 texColor = texelFetch(myTexture, texelCoord, 0);
FragColor = texColor;
}

texture() VS texelFetch()

There are several cases when it is advantageous to switch from texture() to texelFetch().

We can use texelFetch() when we need to access a precise texel or array of texels without interpolation. This function can be useful when we do not need mipmaps and we want to access the texture layer without changes.

texelFetch() is really useful as well when working with techniques that require access to specific pixels, like path tracing and advanced simulations.

Wrap Up

Texturing is the foundation layer of working with GLSL. So it is pivotal to fully understand all the functions we have at our disposal to maximize our work. texture() and texelFetch() perform different tasks according to needs and we can get the most out of them thus increasing our project efficiency.