texel中心坐标处的textureGather()行为 [英] textureGather() behavior at texel center coordinates

查看:241
本文介绍了texel中心坐标处的textureGather()行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我具有100x100的纹理,并且执行以下操作:

Suppose I have a 100x100 texture and I do the following:

vec4 texelQuad = textureGather(sampler, vec2(50.5)/vec2(100.0));

我要的坐标正好位于texel(50,50)的中心.因此,我将得到由(49,49)和(50,50)界定的四像素或由(50,50)和(51,51)界定的四像素.规格在这个问题上是回避的.它仅声明以下内容:

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:

将LINEAR缩小过滤器的规则应用于 识别四个选定的纹理像素.

The rules for the LINEAR minification filter are applied to identify the four selected texels.

规范的相关部分8.14.2 Coordinate Wrapping and Texel Selection 也不是很清楚.我最好的假设如下:

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) 

另一种情况:

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) 

由于texel中心坐标上的不可预测行为,使textureGather()无效吗?一点也不!.尽管您可能无法预测在某些特定情况下它将返回哪4个纹理像素,但是您仍然可以通过为其提供所需的这4个纹理像素之间的坐标来强制它返回所需的4个纹理像素.也就是说,如果我想要由(49,49)和(50,50)界定的纹素,我会打电话给

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);

由于我这次请求的坐标是4个纹理像素的交汇点,因此任何实现方式肯定会返回我这4个纹理像素.

Since the coordinate I am requesting this time is the point where 4 texels meet, any implementation will surely return me those 4 texels.

现在,问题是:我的分析正确吗?是否每个使用textureGather()的人都强迫它返回特定的四边形纹理,而不是自己计算出将返回哪些纹理呢?如果是这样,那就太可惜了,没有任何文档反映出来.

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.

编辑

有人指出,OpenGL无法保证在不同硬件上划分相同浮点数的结果相同.因此,有必要提到在我的实际代码中我使用的是vec2(50.5)/vec2(textureSize(sampler, 0))而不是vec2(50.5)/vec2(100.0).这很重要,因为textureSize()的存在会阻止在着色器编译时执行该划分.

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:

假设您从黑匣子获得了归一化的纹理坐标.然后将该坐标传递给textureGather():

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);

谁能产生GLSL代码,该代码将返回texelQuad [3]中返回的texel的整数坐标对,该坐标是2x2框的下限角?以下明显的解决方案并非在所有情况下都适用:

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));

其中textureSize(sampler, 0)返回ivec2(100, 100).

推荐答案

回想一下,GL_LINEAR的纹理元素位置([OpenGL 4.6(Core)§8.14Texture Minification])是通过以下公式选择的:

Recall that the texel locations for GL_LINEAR ([OpenGL 4.6 (Core) §8.14 Texture Minification]) are selected by the following formulas:

i 0 = wrap(⌊u'-1/2⌋)

i0 = wrap(⌊u′ - 1/2⌋)

j 0 = wrap(⌊v'-1/2⌋)

j0 = wrap(⌊v′ - 1/2⌋)

...

在这种情况下(u',v')的值等于

The value of (u′,v′) in this case is equal to

(vec2(50.5) / vec2(100)) * vec2(100)

但是,请注意,这不能保证等于vec2(50.5).请参见 OpenGL阴影语言4.60§4.71范围和精度:

However, note that this is not guaranteed to be equal to vec2(50.5). See The OpenGL Shading Language 4.60 §4.71 Range and Precision:

a/b,1.0/b:b的2.5 ULP,范围为[2 -126 ,2 126 ].

因此,u'的值可能略大于50.5,略小于50.5,或者恰好是50.5.没有承诺!好吧,该规范承诺不超过2.5 ULP,但这没什么好说的.您会看到,减去0.5并取下一个底数时,您将得到49或50,具体取决于数字的舍入方式.

So the value of u′ might be slightly larger than 50.5, slightly smaller than 50.5, or it might be 50.5 exactly. No promises! Well, the spec promises no more than 2.5 ULP, but that's nothing to write home about. You can see that when you subtract 0.5 and take the floor, you are either going to get 49 or 50, depending on how the number was rounded.

i 0 = wrap(⌊(50.5/100)* 100-1/2⌋)

i0 = wrap(⌊(50.5 / 100) * 100 - 1/2⌋)

i 0 = wrap(⌊(.505±误差)* 100-1/2⌋)

i0 = wrap(⌊(.505 ± error) * 100 - 1/2⌋)

i 0 = wrap(⌊50.5±错误-1/2⌋)

i0 = wrap(⌊50.5 ± error - 1/2⌋)

i 0 = wrap(⌊50±错误⌋)

i0 = wrap(⌊50 ± error⌋)

i 0 = 50(如果错误> = 0)或49(如果错误< 0)

i0 = 50 (if error >= 0) or 49 (if error < 0)

因此,实际上不是textureGather()行为异常.不可预测的部分是尝试除以100时的舍入误差,这在GLSL规范和经典文章

So in fact it is not textureGather() that is behaving unpredictably. The unpredictable part is the rounding error when you try to divide by 100, which is explained in the GLSL spec and in the classic article, WhatEvery Computer Scientist Should Know About Floating-Point Numbers.

换句话说,textureGather()始终会为您提供相同的结果,但50.5/100.0却不会.

Or in other words, textureGather() always gives you the same result, but 50.5/100.0 does not.

请注意,如果纹理是2的幂,则可以得到准确的结果,因为可以使用50.5 * 0.0078125来计算50.5 / 128,并且结果将是正确的,因为乘法正确地取整并且0.0078125是幂的两个.

Note that you could get exact results if your texture were a power of two, since you could use 50.5 * 0.0078125 to compute 50.5 / 128, and the result would be exactly correct, since multiplication is correctly rounded and 0.0078125 is a power of two.

这篇关于texel中心坐标处的textureGather()行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆