按像素区域的 OpenGL 纹理映射

OpenGL Texture Mapping by Pixel Region

假设您有一个简单的游戏 Tileset,如下所示:

现在,在处理 .NET 等简单的 GUI 框架时,加载该图像 select 部分,然后绘制它 tile-by-tile 会相当容易。然而,当使用 OpenGL 时,这个过程似乎有点......呃,独特。我可以轻松地将图像加载到 OpenGL 中并将其绑定到某些几何体,但是,当涉及到 "selecting" 某些图块(没有解除绑定所述纹理)时,它似乎需要与传统 x、y 不同的数学,宽度,高度方法。

如果我想 select 当前图块的 64,128(pixel-space 中的坐标)的图块,我会使用反映理想情况的纹理坐标,而不是我见过的这些奇怪的分数人们在其他网站上提出建议。

似乎 OpenGL 在绑定纹理时根本不使用 pixel-space,或者我在这里误解了一些基本概念;我不确定。

这是在某个任意位置渲染 32 x 32 tile 的简单方法(在本例中将保持在 0,0):

            int spriteX = 0;
            int spriteY = 0;
            int spriteWidth = 32;
            int spriteHeight = 32;
            GL.BindTexture( TextureTarget.Texture2D , texture );
            GL.Begin( PrimitiveType.Quads );
            {
                GL.TexCoord2( 0 , 1 );
                GL.Vertex2( spriteX , spriteY );
                GL.TexCoord2( 1 , 1 );
                GL.Vertex2( spriteX + spriteWidth , spriteY );
                GL.TexCoord2( 1 , 0 );
                GL.Vertex2( spriteX + spriteWidth , spriteY + spriteHeight );
                GL.TexCoord2( 0 , 0 );
                GL.Vertex2( spriteX , spriteY + spriteHeight );
            }
            GL.End();

在有人抱怨立即模式之前:我完全知道它已被弃用;我不打算将它用于任何类型的成品。

与其将绘制的四边形映射到整个纹理(上面的代码正在做的),不如告诉它只映射图像的一个区域,比如:X 64,Y 128,宽度 32,身高32.

最直接的方法是使用您所说的"these weird fractions"。他们并没有那么奇怪。它们只是...分数。

假设您的整个纹理图集是 1024x1024,并且您想要具有指定尺寸(X 64、Y 128、宽度 32、高度 32)的纹理,则纹理坐标为:

left: X / 1024 = 64.0f / 1024.0f
right: (X + Width) / 1024 = 96.f / 1024.0f
top = Y / 1024 = 128.0f / 1024.0f
bottom = (Y + Height) / 1024 = 160.0f / 1024.f

另一种方法是为纹理坐标指定变换,在本例中为缩放变换。使用固定管道,它看起来像这样:

glMatrixMode(GL_TEXTURE);
glScalef(1.0f / 1024.0f, 1.0f / 1024.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);

然后您可以使用纹理图集中的像素位置指定纹理坐标。

使用可编程流水线,以上内容已过时。但是您可以通过将统一值传递给着色器轻松应用相同类型的缩放,然后将其与纹理坐标相乘。

在顶点着色器中,它可能看起来像这样:

uniform vec2 TexCoordScale;
in vec2 TexCoord;
out vec2 FragTexCoord;
...
    FragTexCoord = TexCoordScale * TexCoord;

然后在片段着色器中,您有匹配的 FragTexCoord in 变量,并将其用于您的纹理采样操作。

在客户端代码中,您设置统一:

GLint texCoordScaleLoc = glGetUniformLocation(program, "TexCoordScale");
glUniform2f(texCoordScaleLoc, 1.0f / 1024.0f, 1.0f / 1024.0f);

并像往常一样设置纹理坐标的顶点属性,除了您现在可以为它们使用像素坐标而不是 "weird fractions"。