且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何在不拉伸的情况下在OpenGL(ES)中将非2幂的纹理显示为精灵?

更新时间:2023-11-30 18:29:58

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

To get a pixel-perfect coordinate system, you could set up your matrices as follows:

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映射,并将原点放在左下角.

This ensures a 1:1 mapping of OpenGL coordinates to pixels, and puts your origin in the bottom left corner.

关于纹理,如果您不想依赖非2的幂次扩展,则必须 将其填充为2的幂.即使OpenGL ES规范没有说它也必须是正方形的(据我所知),但我已经看到Android在512 x 128的纹理尺寸上发生了奇怪的事情,因此***坚持使用 square 具有2的幂次幂.

As to your texture, if you don't want to rely on the non-power-of-two extension, you must pad it to be a power of two. Even though the OpenGL ES spec doesn't say it has to be square as well (as far as I know), I've seen strange things happen on Android with texture sizes like 512 x 128, so it might be best to stick to square power-of-two textures.

要注意的是,无论纹理的像素大小如何,OpenGL中的纹理坐标始终在0到1之间.因此,如果您的精灵为48像素宽,并且将其填充为64 x 64的纹理,则它将跨越0到0.75的x坐标:

The thing to note is that texture coordinates in OpenGL are always between 0 and 1, no matter what the pixel size of your texture is. So if your sprite is 48 pixels wide, and you padded it to a texture of 64 x 64, then it will span the x coordinates from 0 to 0.75:

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

因此,您必须为四边形的角设置这些纹理坐标.因为我们有一个完美的像素投影,所以四边形也必须恰好是48像素宽.

So you have to set up these texture coordinates for the corners of your quad. Because we have a pixel-perfect projection, the quad must also be exactly 48 pixels wide.

最后,要在x, y位置绘制精灵(从左下角开始以像素为单位),请执行以下操作:

In conclusion, to draw your sprite at position x, y (in pixels from the bottom left), do something like this:

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();

我知道OpenGL ES没有glVertex2i等,因此您必须将这些坐标放入缓冲区中.而且它不允许四边形,因此您必须将其分成三角形.但这是基本思想.

I know OpenGL ES doesn't have glVertex2i and so on, so you'll have to put these coordinates into a buffer. And it doesn't allow quads, so you'll have to split it up into triangles. But this is the basic idea.