OpenGL ES能否渲染非2的整数次幂大小的纹理?

15

在将我的当前渲染系统转换为openGL之前,我有一个快速的问题。我听说纹理需要是2的幂次方大小才能存储用于渲染。这是真的吗?

我的应用程序非常严格地使用内存,但大多数位图不是2的幂次方。存储非2的幂次方纹理会消耗更多的内存吗?


1
二的幂次方不等于平方。32x64是二的幂次方,不是平方,13x13是平方,不是二的幂次方。 - Bahbar
好点子。不过,无论如何它需要是非二次幂。 - Kleptine
4个回答

10

根据OpenGL ES版本的不同,这是正确的,OpenGL ES 1.0/1.1有二次幂限制。OpenGL ES 2.0没有此限制,但它对非二次幂纹理的环绕模式进行了限制。

创建更大的纹理以匹配POT尺寸会浪费纹理内存。


那么在OpenGL中没有任何方法可以渲染非2次幂大小的位图而不浪费内存吗?这真是令人恼火。哦,好吧,我很高兴我还没有开始彻底改写我的代码。 - Kleptine
顺便提一下,你应该知道OpenGL ES和OpenGL没有相同的限制,OpenGL 2.0及以上版本直接支持NPOT纹理。 - Dr. Snoopy
当使用非2的幂纹理时,OpenGL ES 2.0的包裹模式有哪些限制? - dirhem
3
只支持GL_CLAMP_TO_EDGE作为纹理包裹方式,不支持mipmaps。请参考http://www.khronos.org/opengles/sdk/docs/man/xhtml/glTexParameter.xml中的注释。 - Dr. Snoopy

6
Suresh,OpenGL中的2的幂次方限制是在计算机图形学(在可负担得起的硬件加速之前)的早期阶段就被加入的,出于性能原因。当可以为2的幂次方纹理进行硬编码时,低级渲染代码会获得相当大的性能提升。即使在现代GPU中,POT纹理仍然比NPOT纹理快,但速度差异要小得多(尽管在许多ES设备上仍然可能明显)。
GuyNoir,你应该建立一个纹理集。我自己在过去的周末为自己的Android游戏解决了这个问题。我创建了一个名为TextureAtlas的类,它的构造函数调用glTexImage2D()来创建任何大小的大纹理(传递像素值的null)。然后我可以反复调用add(id, bitmap)来打包较小的图像,该方法会调用glTexSubImage2D()。TextureAtlas类跟踪更大纹理中已使用和空闲的空间以及每个位图存储的矩形。然后,渲染代码可以调用get(id)来获取图集中图像的矩形(然后可以将其转换为纹理坐标)。
附注1:选择最佳方式来打包各种纹理大小并不是一个微不足道的任务。我选择在TextureAtlas类中使用简单的逻辑(类似于打字机+回车+换行符),并确保以最佳顺序加载图像以利用该逻辑。在我的情况下,我从最小的正方形图像开始,然后逐步增加到中等大小的正方形图像。然后我加载任何短而宽的图像,强制执行CR + LF,然后加载任何长而瘦的图像。我最后加载最大的正方形图像。
附注2:如果您需要多个纹理集,请尝试将每个内部的图像分组在一起,以最小化您需要切换纹理的次数(这可能会影响性能)。例如,在我的Android游戏中,我将所有静态游戏板元素放入一个图集中,并将各种动画效果的帧放入第二个图集中。这样,我可以绑定图集#1并在游戏板上绘制所有内容,然后我可以绑定图集#2并在其上绘制所有特殊效果。每帧两个纹理选择非常高效。
附注3:如果您需要重复/镜像纹理,则需要将它们放入自己的纹理中,并且需要对其进行缩放(而不是添加黑色像素来填充边缘)。

是的,我考虑过类似的事情。唯一的问题是仍然存在一些小量的浪费内存,在一个不断推动24MB边界的程序中,我需要尽可能多的内存。 - Kleptine

3
不,它必须是2的倍数。但是,您可以通过在图像顶部和/或底部添加黑色条来绕过此问题,然后使用纹理坐标数组来限制纹理将从图像映射到哪里。例如,假设您有一个13 x 16像素的纹理。您可以在右侧添加3个黑色像素,然后执行以下操作:
static const GLfloat texCoords[] = {
        0.0, 0.0,
        0.0, 13.0/16.0,
        1.0, 0.0,
        1.0, 13.0/16.0
    };

现在,您有一个2base图像文件,但非2base纹理。只需确保使用线性缩放即可 :)

问题在于它浪费了纹理内存;而我的应用程序对此非常紧缺。 - Kleptine

2
这有点晚了,但非2的幂纹理通过扩展在OpenGL ES 1/2中得到支持。主要的一个是GL_OES_texture_npot。还有针对iOS设备的GL_IMG_texture_npot和GL_APPLE_texture_2D_limited_npot。通过调用glGetString(GL_EXTENSIONS)并搜索所需的扩展名来检查这些扩展。我还建议将纹理大小保持为4的倍数,因为某些硬件会拉伸纹理。

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