假设您有一个简单的游戏图块集,如下所示:
现在,在处理简单的 GUI 框架(例如 .NET)时,加载该图像、选择其中的一部分,然后逐块绘制它会相当容易。然而,当使用 OpenGL 时,这个过程似乎有点……呃,独特。我可以轻松地将图像加载到 OpenGL 中并将其绑定到某些几何体,但是,当涉及“选择”某些图块(无需取消绑定所述纹理)时,它似乎需要与传统的 x、y、宽度不同的数学运算,高度接近。
如果我想为当前图块选择 64,128(像素空间中的坐标)的图块,我会使用反映理想情况的纹理坐标,而不是我在其他网站上看到的人们建议的这些奇怪的分数。
OpenGL在绑定纹理时似乎根本不使用像素空间,或者也许我在这里误解了一些基本概念;我不确定。
这是在某个任意位置渲染 32 x 32 图块的简单方法(在本例中将保持为 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。
最直接的方法是使用你所谓的“这些奇怪的分数”。他们其实并没有那么奇怪。它们只是...分数。
假设您的整个纹理图集为 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);
并像平常一样设置纹理坐标的顶点属性,除了现在可以使用它们的像素坐标而不是“奇怪的分数”。