2017-09-25 324 views
1

假設我有一個100×100的紋理和我做了以下內容:textureGather()行爲座標

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

座標我請求正是在紋理像素的中心(50,50)。那麼,我會得到由(49,49)和(50,50)或由(50,50)和(51,51)所界定的四個像素。規範在這個問題上是迴避的。它只是聲明以下內容:

LINEAR縮小過濾器的規則適用於 ,用於標識四個選定的紋元。

spec的相關部分8.14.2 Coordinate Wrapping and Texel Selection也不是很清楚。我最好的假設是:

ivec2 lowerBoundTexelCoord = ivec2(floor(textureCoord * textureSize - 0.5)); 

這個假設是否在實踐中有效?不,它沒有。事實上,沒有任何其他的假設將舉行要麼,因爲不同的硬件返回此特殊情況下,不同的結果:由於在不可預知的行爲

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) 

是否讓textureGather()沒用:

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) 

另一種情況texel中心座標?一點也不!。雖然你可能無法預測它在某些特定情況下會返回哪個4個像素,但仍然可以通過給它一個你想要的4個像素之間的座標來強制它返回你想要的像素。也就是說,如果我想在(49,49)和(50,50)界紋理元素,我會打電話:

textureGather(sampler, vec2(50.0, 50.0)/textureSize); 

由於座標我請求這一次是在哪裏4個紋理元素的交匯點,任何實現肯定會給我那4個texels。

現在,問題:我的分析是否正確?是否所有使用textureGather()的人都強制它返回一個特定的紋理像素,而不是找出它自己會返回哪個像素?如果是這樣,它是如此的恥辱,它沒有反映在任何文件。

編輯

有人指出,OpenGL圖像並不能保證同樣的結果在不同的硬件將相同的浮點數。因此,有必要提到在我的實際代碼中我有vec2(50.5)/vec2(textureSize(sampler, 0))而不是vec2(50.5)/vec2(100.0)。這很重要,因爲textureSize()的存在阻止了在着色器編譯時進行分割。

也讓我改一下這個問題:

假設你有從黑盒子標準化紋理座標。該座標隨後被傳遞到textureGather():

vec2 textureCoord = takeFromBlackBox(); 
vec4 texelQuad = textureGather(sampler, textureCoord); 

誰能產生GLSL代碼將返回整數對的紋理像素的座標在texelQuad返回[3],這是一個2×2的下限角框?顯而易見的解決方案如下並不適用於所有情況:棘手的案件

vec2 textureDims = textureSize(sampler, 0);  
ivec2 lowerBoundTexelCoord = ivec2(floor(textureCoord * textureDims - 0.5)); 

例子,其中上面的方法可能會失敗有:

vec2 textureCoord = vec2(49.5)/vec2(textureSize(sampler, 0)); 
vec2 textureCoord = vec2(50.5)/vec2(textureSize(sampler, 0)); 

其中textureSize(sampler, 0)回報ivec2(100, 100)

+1

舍入誤差,因爲'vec2(50.5)/ vec2(100.0)'不準確。 –

+0

請參閱:[每個計算機科學家應該知道什麼關於浮點數字](https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) –

+0

@DietrichEpp這真的沒有關係。你看,我不關心哪些紋理元素會在不明確的情況下返回,只要我能預測哪些元素將會出現。不幸的是,似乎無法預測這一點。 –

回答

3

回想一下,對於紋素位置GL_LINEAR([OpenGL的4.6(核心)§8.14紋理縮小])由下式選擇:

我 =渦卷(⌊u' - 1/2⌋)

Ĵ =渦卷(⌊v' - 1 /2⌋)

...

的值(U',V')在這種情況下等於

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

然而,注意,這並不保證等於vec2(50.5)。見The OpenGL Shading Language 4.60 §4.71 Range and Precision

A/B,1.0/B:2.5 ULP對於b的範圍在[2 -126,2 ]。

所以u'的值可能略大於50.5,略小於50.5,或者它可能完全是50.5。沒有保證!那麼,規格承諾不超過2.5 ULP,但這是沒有什麼可寫的。你可以看到,當你減去0.5併發言時,你要麼得到49或50,這取決於數字如何舍入。

我 =渦卷(⌊(50.5/100)* 100 - 1 /2⌋)

我 =渦卷(⌊(0.505±誤差)* 100 - 1/2⌋)

我 =渦卷(⌊50.5±誤差 - 1 /2⌋)

我 =渦卷(⌊50±error⌋)

我 = 50(如果誤差> = 0)或49(如果錯誤< 0)

所以實際上它不是textureGather()被意外現象。不可預知的部分是當您嘗試除以100時的舍入誤差,這在GLSL規範和經典文章 WhatEvery Computer Scientist Should Know About Floating-Point Numbers中進行了解釋。

或換句話說,textureGather()總會給出相同的結果,但50.5/100.0不會。

注意,如果你的紋理是二的冪,你可以得到精確的結果,因爲你可以使用50.5 * 0.0078125計算50.5/128,其結果將是完全正確的,因爲乘法是正確圓潤0.0078125是二的冪。

+0

好的,我不知道OpenGL並不能保證在不同的硬件上得到相同的結果。但是,這仍然是重點。假設你已經從黑匣子中獲得了規範化的紋理座標。 'vec2(50.5)/ vec2(100.0)'的劃分就是這樣一個黑盒子。實際上,在我的實際代碼中,它是'vec2(50.5)/ vec2(textureSize(...))',這突然間是一個重要的區別。現在,您將該座標從黑色框傳遞給textureGather()。你能產生一段能準確預測將要返回的紋理元素的代碼嗎?我無法。 –

+0

@Tulon:只要您可以準確預測您傳遞給'textureGather()'的值,就可以準確地預測將收集的紋理元素。 **這沒有什麼要做'textureGather()'** –

+0

@Tulon:爲什麼你需要完全預測事情呢?如果您的代碼依賴於浮點除法爲您提供確切的結果,那麼我們可以幫助您修復代碼,使其對實際浮點數在真實硬件上的工作方式不那麼敏感。但是,'textureGather()'在這裏沒有問題。 –