Texture lookup when texel coordinates outside of [0,1]?

OpenGL ES 3.0. In my fragment shader I lookup texels from a texture like this

vec4 texel = texture( sampler2D , vec2(v_coord.x+u_offsets[i],v_coord.y) )

where v_coord is a vertex attribute and u_offsets[i] is an uniform array. This works, but I can see that it ‘wraps up’ the texel coordinates, i.e. it really looks like

texture( sampler2D, vec2(1.1,0.2) ) = texture( sampler2D, vec2(0.1,0.2) )

So whenever some texture coordinate is out of the [0,1] interval, the texture() function maps it into the interval and fetches a texel from there.

This behaviour is undesirable. I’d much rather have it return some pre-programmed solid color whenever the coordinates are out of [0,1]x[0,1]. I know I can program this in my shader ( test if v_coord.x+u_offsets[i] and v_coord.y are inside [0,1], if yes lookup the texel, if not - return a uniform color) - but maybe there’s a faster way?

You can use

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

to clamp the texture coordinates rather than repeating. This results in any access beyond an edge using the texels from the corresponding edge row/column of the texture.

With desktop OpenGL, there’s also the option of using GL_CLAMP_TO_BORDER and setting a border colour, but that isn’t available in OpenGL ES. If you want a solid border, you have to make it part of the texture.

1 Like

Thanks GClements, that works! Additionally I don’t really need CLAMP_TO_BORDER as my textures naturally have a solid border.

Maybe I could ask you one more question on the sidelines:

when do I need to call the ‘glTexParameteri’ ? Every time just after a call to ‘glBindTexture’ (which is what I do now and that works) or is it enough to call it only just after the very first time a given texture gets bound?

This function manipulates state stored in the texture object. Note that the state is stored there. So it will be preserved as part of the object, just like setting the value of a member of a class. So you need to call it only when you wish to change that value later.