Opengl es 如何在OpenGL(ES)中以sprite的形式显示非二次幂纹理而不进行拉伸?

Opengl es 如何在OpenGL(ES)中以sprite的形式显示非二次幂纹理而不进行拉伸?,opengl-es,sprite,Opengl Es,Sprite,我想画一个任意大小的精灵作为png,比如说一些完全疯狂的东西,比如56宽x30高。在任一维度上都不是2的幂。另外,我可能想画另一个不同的精灵,72宽x 33高。指出这一点是因为这里不接受“技巧”,所以我需要处理一般情况 所以我有这个png(带透明度),我想把它画成一个精灵,绝对没有拉伸,插值,等等。我希望它在屏幕上以1:1的比例映射像素。假设这些精灵是像素艺术(它们可能是,也可能不是,但它们是为精确的分辨率绘制的) 我理解精灵绘制-2个三角形作为一个四边形,通过纹理坐标映射将我的纹理渲染成那个样

我想画一个任意大小的精灵作为png,比如说一些完全疯狂的东西,比如56宽x30高。在任一维度上都不是2的幂。另外,我可能想画另一个不同的精灵,72宽x 33高。指出这一点是因为这里不接受“技巧”,所以我需要处理一般情况

所以我有这个png(带透明度),我想把它画成一个精灵,绝对没有拉伸,插值,等等。我希望它在屏幕上以1:1的比例映射像素。假设这些精灵是像素艺术(它们可能是,也可能不是,但它们是为精确的分辨率绘制的)

我理解精灵绘制-2个三角形作为一个四边形,通过纹理坐标映射将我的纹理渲染成那个样-但是我只理解2的幂。我也不知道如何调整我的“四边形”的大小和设置我的GL矩阵,以便我可以使精灵的像素大小与精灵的像素大小完全相同

我使用的是OpenGL ES,因此使用新的扩展来使用非2次幂纹理是不可接受的


我一次只画3-10个精灵,所以我愿意接受关于效率的建议,但我最感兴趣的是“精确”的外观结果。

要获得像素完美的坐标系,您可以按如下方式设置矩阵:

glViewport(0, window_width, 0, window_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, window_width, 0, window_height, 0, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
这确保了OpenGL坐标与像素的1:1映射,并将原点放在左下角

至于你的纹理,如果你不想依赖于非二次幂的延伸,你必须将其填充为二次幂。尽管OpenGL ES规范没有说它也必须是正方形(据我所知),但我看到Android上出现了一些奇怪的事情,纹理大小为512 x 128,所以最好还是坚持使用两种纹理的平方幂

需要注意的是,无论纹理的像素大小如何,OpenGL中的纹理坐标始终在0和1之间。因此,如果精灵的宽度为48像素,并将其填充为64 x 64的纹理,则其x坐标范围为0到0.75:

1 +--------+
  |        |
  |        |
  +-----+  |
  |\_O_/|  |
  |  O  |  |
  | / \ |  |
0 +-----+--+
  0   0.75 1   <- texture coordinates
  0     48 64  <- pixels

我知道OpenGL ES没有
glVertex2i
等等,所以您必须将这些坐标放入缓冲区。它不允许四边形,所以你必须把它分成三角形。但这是基本的想法。

看起来不错-我应该如何处理纹理插值提示?这样它就不会试图“变聪明”并扭曲我的纹理?或者他们只是因为texcoord将与纹理上的参考点完美匹配(或者足够接近,插值算法将产生我的像素的完美值)而不来玩,理论上是的。实际上,在GL_MIN_过滤器和GL_MAX_过滤器中都使用GL_NEAREST,这是为了确保——它甚至可能更快一些。对于viewport,我不是真的想要0,宽度-1,0,高度-1吗?对于ortho,我正在手工计算我的矩阵(因为ES2不包括glOrtho),到目前为止,我在该计算中使用640/2和960/2(宽度和高度VAL)——我应该有-1吗。。。。我有你的技术非常接近工作,但我遇到了别名和一些是错误的。。。。(可能是这个,可能是我的图像加载和处理,仍然不确定,所以请在我调试时感谢您的输入!)不,我非常确定它应该从0变为
宽度
高度
glViewport
需要视口的宽度和高度,而不是右侧和顶部。从640/2和960/2,我想你想要你的原点在屏幕的中心?不这样做可能更容易,但可以将转换放在modelview矩阵中。如果你无法理解,请打开一个新问题,并在此处添加一条注释,指向它:)我肯定迷路了:)我给出了一些关于我用于投影的矩阵的轻微错误信息。请看这里-谢谢!-->
float texcoord_x = (float)sprite_width / texture_width;
float texcoord_y = (float)sprite_height / texture_height;

glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture_id);

glBegin(GL_QUADS);
// bottom left
glTexCoord2f(0, 0);
glVertex2i(x, y);
// bottom right
glTexCoord2f(texcoord_x, 0);
glVertex2i(x + sprite_width, y);
// top right
glTexCoord2f(texcoord_x, texcoord_y);
glVertex2i(x + sprite_width, y + sprite_height);
// top left
glTexCoord2f(0, texcoord_y);
glVertex2i(x, y + sprite_height);
glEnd();