OpenGL纹理坐标和小浮点数的精度问题

4
我正在使用浮点数来指定纹理坐标,范围在0-1之间。OpenGL喜欢这个范围,我很满意以这种方式指定坐标,但我担心当我开始使用更大的纹理(比如4096或8192像素)时,我可能会开始失去精度。例如,如果我想在一个8192x8192px的纹理中指定一个坐标为(1,1),那么它将映射到1/8192=0.0001220703125。然而,作为浮点数,它似乎评估为0.000122070313...我担心我的OpenGL着色器不会将其映射到我预期的相同像素。
我可以暂时将坐标保持为像素中的整数,但迟早我必须将其转换(可能是在着色器本身)。有没有解决方法,或者这是我应该关注的问题?
将其乘回去,我得到1.000000004096,我猜这仍然会被解释为1?实际上,如果不是整数,OpenGL会进行混合吗?也许不是用“最近邻”,但用“线性”应该可以。
1/4096f * 4096 =   1, error = 0
1/8192f * 8192 =   1.000000004096, error =  0.000000004096
1/16384f * 16384 = 1.0000000008192, error = 0.0000000008192
1/32768f * 32768 = 0.9999999991808, error = 0.0000000008192
...
1/1048576f * 1048576 = 0.9999999827968, error = 0.0000000172032

我正在使用Visual Studio的调试器计算浮点数,然后再用计算器将其乘回去。

这里的教训是对于任何合理大小的纹理来说,误差都是可以忽略不计的吗?


我相信是这样的。我确实使用了一些非常大的纹理,唯一让精度失效的方法就是将纹理缩放到屏幕上基本看到像素的程度,即使如此,它仍然可以正常渲染。 - Jesus Ramos
2/8192 = 0.000244140625,而这个数与1/8192之间的差距在单精度范围内,不是吗? - Matt Phillips
@MattPhillips:是的...我想它会回到同一个像素,但我想知道它是否会在某个点崩溃。 - mpen
1个回答

3
似乎转换为浮点数后是0.000122070313...我担心我的OpenGL着色器无法将其映射到我想要的像素。 您不必担心。浮点数之所以称为浮点数,是因为小数部分“浮动”。您可以获得大约7位数字的精度,无论浮点数的大小如何。
浮点数并未存储为0.000122070313;它存储为1.22070313x10^-4。尾数为1.22070313,指数为-4。如果指数为-8,则会有相同的精度。
使用单精度浮点数,指数可以下降到+/- 38。也就是说,在尾数的第一个非零数字和小数点之间可以有38个零。
因此,您不必担心。
唯一需要关注的是插值值的精度和纹理获取的精度。但这些与存储纹理坐标数据的精度无关。

我已经了解了一些有关浮点数在内部存储的知识,但我想我从未意识到分别存储尾数和指数的影响。这是一个很好的特性!谢谢你的解释。 - mpen
尼古拉,我遇到了你在帖子末尾描述的问题。我失去了插值到像素着色器的UV坐标的精度(当相机非常接近一些巨大的三角形时,当相机平移时暴露出UV精度问题)。您有关于克服这个问题的任何建议吗?我首先想到的是在vs中将u坐标分散在xy上,v坐标分散在zw上的float4中,但我想插值器会把它搞砸,因为它会将其作为4个分量进行插值。有没有办法增加精度?我不想只是因为这个原因就细分巨大的三角形。 - shadow_map

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接