为什么纹理总是平方为2的幂?如果不是,那该怎么办?


53

为什么游戏中纹理的分辨率始终是2的幂(128x128、256x256、512x512、1024x1024等)?保存游戏的文件大小并使其纹理完全适合UV解包模型是否明智?

如果纹理不是2的幂,会发生什么?

具有256x512或512x1024之类的纹理会不正确吗?还是会引起非二次幂纹理可能引起的问题?


9
您的其他示例也是2的幂,只是2的幂不同。两者的幂使纹理针对图形硬件进行了优化。
MichaelHouse

1
@ Byte56我认为他的意思是2 ^ nx 2 ^ n纹理,其中n从1到无穷大。(不是真的无限。)
罗宾(Robin

另请注意,使用2的幂可以使mipmap变得微不足道。
Pubby 2012年

因为纹理通常会包裹(尽管您可以在自定义着色器中选择),所以您不需要浪费任何空间,只需将多边形uv坐标包裹在边缘周围,您就可以更轻松地利用可用空间。如果您没有紧迫的需求,则最安全的方法是坚持width = height = 2 ^ n纹理,因为它将允许更广泛的硬件使用,但会以稍微复杂一些的uv布局为代价。
丹尼尔·卡尔森

他们并不总是两个的幂。
Almo

Answers:


49

为什么游戏中纹理的分辨率始终是2的幂(128x128、256x256、512x512、1024x1024等)?

正如Byte56所暗示的,“(两个)的幂”大小限制是(每个)尺寸必须独立地为两个的幂,而不是纹理必须是正方形尺寸为两个的幂。

但是,在现代卡以及哪种现代图形API上,此“限制”已得到显着放松,以使纹理尺寸在合理范围内可以满足您的所有需求。然而:

保存游戏的文件大小并使其纹理完全适合UV解包模型是否明智?如果纹理不是2的幂,会发生什么?

通过确保纹理尺寸是2的幂,图形管线可以利用与2的幂进行效率相关的优化。例如,以两倍的幂进行除法和乘法运算可能会更快(绝对距离我们拥有专用GPU和极其聪明的优化编译器还早了几年)。在管道中使用两个简化的操作进行幂运算,例如mipmap的计算和使用(一个为2的幂将始终平均分成两半,这意味着您不必处理必须四舍五入的情况您的mipmap尺寸向上或向下)。

的确,您可以通过这种方式“浪费”一些空间,但是通常需要额外的空间来弥补渲染性能。另外,还有一些技术,例如将多个图像压缩或打包到单个纹理空间中,可以减轻一些存储浪费。


11
“的确,您以这种方式“浪费”了一些空间,但是额外的空间通常值得在渲染性能方面进行权衡。” -大约十年前,我在一家将PS2游戏移植到XBox的工作室工作。虽然PS2从技术上讲不支持非2幂幂纹理,但在某些情况下,您可以通过稍加巧妙的操作就可以强制这样做,而不会降低速度。另一方面,XBox 完全不支持它们。最终结果是,尽管XBox的RAM几乎是PS2的两倍,但我们还是必须对某些纹理进行下采样才能适应。
ZorbaTHut 2012年

我很难找到引文,但是我之前已经读过JPEG图像应为8的倍数以获得最大效率,因为除此以外的任何内容仍需要8x8的块。
鲑鱼湾2012年

1
@salmonmoose:正确;JPEG独立压缩8x8的每个块,并将边缘填充块。但这与这个问题无关。
MSalters 2012年

1
JPEG以8x8块编码,是的。但是,这实际上不是效率方面的考虑。而且也不一定是2的幂。:)
Kylotan 2012年

Android上有一个示例,其中通常非poweroftwo纹理导致白色纹理。
user717572 2012年

17

为什么纹理总是平方为2的幂?

纹理并不总是 正方形,也不总是 是2的幂。它们之所以倾向于是2的幂,通常是为了提高与施加该限制的旧显卡的兼容性。对于非正方形纹理,通常不是问题。总结一下:

  • 纹理通常不需要是正方形的 -尽管DirectX确实具有D3DPTEXTURECAPS_SQUAREONLY功能,但是即使在较旧的硬件中我也可以使用非正方形纹理,也没有问题。
  • 纹理应该是2的幂,因为许多旧的图形卡仍然需要纹理。该限制的原因是为了使他们可以对纹理映射操作执行一些优化。大多数现代图形卡也没有此限制。

12
应当指出,“旧图形卡”指的是在2006年左右之前制造的东西。
Nicol Bolas 2012年

1
@NicolBolas谢谢,我实际上是在尝试寻找有关此点的参考。
David Gouveia 2012年

7

它与显卡优化有关。它们被设计为以这种方式处理它们。如今,大多数卡允许您加载尺寸不是2的幂的纹理,但可能会对性能产生负面影响。很有可能在加载时实际上会进行转换,这会浪费您的加载时间,并且不节省任何内存。只要非正方形纹理的尺寸均为2的幂,通常就可以。

处理奇数大小纹理的一种方法是使用“ 纹理图集”。基本上,您将多个纹理放在一起形成单个纹理,并使用顶点的纹理坐标来引用所需的特定图像。这还具有其他性能优势,因为它可以避免状态更改。这种方法的常见用法是将接口的所有元素放置在单个纹理中,这意味着,如果您将接口顶点分批处理到单个缓冲对象中,则可以通过一次调用绘制整个对象,而不用切换纹理多次,并为每个单独进行抽奖。


6

问题是某些硬件对没有二维功能的纹理的支持有限。

例如,查看http://msdn.microsoft.com/zh-cn/library/windows/desktop/ff476876%28v=vs.85%29.aspx的底部,然后在此处阅读脚注3和4。

3在功能级别9_1、9_2和9_3上,显示设备支持使用二维纹理的尺寸在两种情况下都不是2的幂。首先,每个纹理只能创建一个MIP映射级别,其次,不允许纹理的环绕采样器模式(即D3D11_SAMPLER_DESC的AddressU,AddressV和AddressW成员不能设置为D3D11_TEXTURE_ADDRESS_WRAP)。

4在要素级别10_0、10_1和11_0上,显示设备无条件支持使用尺寸不是2的幂的2D纹理。


6

图形硬件针对矩阵运算,片段运算和矢量运算进行了优化。简单地说,平方矩阵更易于处理,因为可以在块中进行计算(称为片段),针对块操作对硬件进行了优化,这就是为什么存在诸如文件缓冲区之类的原因,RAM blit直到块之后才对磁盘进行blit已被填充。图形内存也是如此。

帧缓冲器由正方形的片段组成。例如,在分辨率为800x600和RGB颜色空间(0-255)的屏幕中,有800x600点,每个通道3个字节,总共3x800x600 = 1,440,000字节要在帧缓冲区中寻址。这意味着有1,875个可寻址片段,即256x256x3字节。由于纹理数据是正方形的,因此使用双三次缩放可以极大地简化从GRAM矩阵到屏幕缓冲区矩阵的映射,而如果不是正方形,则较长边的偏差将在需要时花费更多时间来计算。被缩放。

许多图形API会接受非方形纹理数据,因为它们接受UV映射坐标作为浮点数据,但是,一旦将其发送到GPU,便会向纹理数据中添加填充,因为图像的实际比例不会更改映射似乎不受影响,但是将填充添加到纹理数据中,因为GPU喜欢将其寻址为一个完美的正方形。

因此,如果使用100x1024的图像,而使用1024x1024的图像,则意味着浪费了946,176个字节。如果要进行合成,则更是如此,因为将需要添加alpha通道以指示填充数据不应影响合成纹理。


这是一个有趣的解释(关于平方矩阵的小知识),在通常的2答案(+1)次方中找不到-您是否可以提供一些引用?
Samaursa

1

我们的数字世界使用二进制计算,然后将值乘以2或除以2,然后可以将值“左移”或“右移”,即

<<  Left shift      x = 5 << 1    0101 << 1     1010     10
>>  Right shift     x = 5 >> 1    0101 >> 1     0010      2

对于CPU,使用“ 2的幂”值更容易。


0

现代硬件可以(最终)应付启用基于两种纹理的非幂的包装模式,但是,两种纹理的非幂仍会浪费GPU内存,因为它们倾向于沿宽度向上填充一定的硬件特定量(缩小至某个图块大小,或四舍五入到包含纹理的两个大小的下一个幂。

由于这取决于硬件,并且供应商通常不会涉及这些细节的细节,因此最安全的方法是继续对纹理使用二维能量,以免浪费GPU内存。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.