Suppose I have a 100x100 texture and I do the following:
vec4 texelQuad = textureGather(sampler, vec2(50.5)/vec2(100.0));
The coordinate I am requesting is exactly at the center of texel (50, 50). So, will I get a quad of texels bounded by (49, 49) and (50, 50) or the one bounded by (50, 50) and (51, 51). The spec is evasive on the subject. It merely states the following:
The rules for the LINEAR minification filter are applied to identify the four selected texels.
The relevant section 8.14.2 Coordinate Wrapping and Texel Selection of the spec is not terribly clear either. My best hypothesis would be the following:
ivec2 lowerBoundTexelCoord = ivec2(floor(textureCoord * textureSize - 0.5));
Does that hypothesis hold in practice? No, it doesn't. In fact no other hypothesis would hold either, since different hardware returns different results for this particular case:
textureSize: 100x100
textureCoord: vec2(50.5)/vec2(100.0)
Hyphotesis: (49, 49) to (50, 50)
GeForce 1050 Ti: (49, 49) to (50, 50)
Intel HD Graphics 630: (50, 50) to (51, 51)
another case:
textureSize: 100x100
textureCoord: vec2(49.5)/vec2(100.0)
Hyphotesis: (48, 48) to (49, 49)
GeForce 1050 Ti: (49, 49) to (50, 50)
Intel HD Graphics 630: (48, 48) to (49, 49)
Does that make textureGather() useless due to the unpredictable behavior at texel center coordinates? Not at all!. While you may not be able to predict which 4 texels it will return in some particular cases, you can still force it to return the ones you want, by giving it a coordinate between those 4 texels you want. That is, if I want texels bounded by (49, 49) and (50, 50), I would call:
textureGather(sampler, vec2(50.0, 50.0)/textureSize);
Since the coordinate I am requesting this time is the point where 4 texels meet, any implementation will surely return me those 4 texels.
Now, the question: Is my analysis correct? Does everyone who uses textureGather() force it to return a particular quad of texels rather then figuring out which ones it would return by itself? If so, it's such a shame it's not reflected in any documentation.
EDIT
It was pointed out that OpenGL doesn't guarantee the same result dividing identical floating point numbers on different hardware. Therefore, it becomes necessary to mention that in my actual code I had vec2(50.5)/vec2(textureSize(sampler, 0)) rather than vec2(50.5)/vec2(100.0). That's important, since the presence of textureSize() prevents that division from being carried out at shader compilation time.
Let me also rephrase the question:
Suppose you've got a normalized texture coordinate from a black box. That coordinate is then passed to textureGather():
vec2 textureCoord = takeFromBlackBox();
vec4 texelQuad = textureGather(sampler, textureCoord);
Can anyone produce GLSL code that would return the integer pair of coordinates of the texel returned in texelQuad[3], which is the lower-bound corner of a 2x2 box? The obvious solution below doesn't work in all cases:
vec2 textureDims = textureSize(sampler, 0);
ivec2 lowerBoundTexelCoord = ivec2(floor(textureCoord * textureDims - 0.5));
Examples of tricky cases where the above approach may fail are:
vec2 textureCoord = vec2(49.5)/vec2(textureSize(sampler, 0));
vec2 textureCoord = vec2(50.5)/vec2(textureSize(sampler, 0));
where textureSize(sampler, 0) returns ivec2(100, 100).
vec2(50.5)/vec2(100.0)is not exact. - Dietrich EpptextureGather, the problem is that you're passing a different value totextureGatheron different platforms, and expecting the results to be the same on those different platforms. - Dietrich Eppfloor(). - Dietrich Epp