假设您有一个简单的游戏Tileset,如下所示:
现在,在处理一个简单的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,Width 32,Height 32
答案 0 :(得分:5)
最直接的方法是使用你所谓的“这些奇怪的分数”。他们并不是那么奇怪。他们只是......分数。
假设您的整个纹理图集是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);
并像平常一样设置纹理坐标的顶点属性,除了你现在可以使用像素坐标而不是“奇怪的分数”。