基于像素区域的OpenGL纹理映射
假设游戏中有一个简单的Tileset,如下所示:基于像素区域的OpenGL纹理映射,opengl,2d,texture-mapping,opentk,Opengl,2d,Texture Mapping,Opentk,假设游戏中有一个简单的Tileset,如下所示: 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; 现在
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;
现在,在处理一个简单的GUI框架(如.NET)时,加载该图像,选择其中的一部分,然后逐块绘制它将非常容易。然而,当使用OpenGL时,这个过程似乎更…呃,独一无二。我可以轻松地将该图像加载到OpenGL中,并将其绑定到某些几何体上,然而,当涉及到“选择”某些瓷砖(不解除所述纹理的绑定)时,它似乎需要一种与传统的x、y、宽度和高度方法不同的数学
如果我想选择64128(像素空间中的坐标)的瓷砖作为当前瓷砖,我会使用反映理想的纹理坐标,而不是我在其他网站上看到人们建议的这些奇怪的分数
似乎OpenGL在绑定纹理时根本不使用像素空间,或者我在这里误解了一些基本概念;我不确定
下面是一种在任意位置渲染32 x 32平铺的简单方法(在本例中保持为0,0):
在任何人抱怨立即模式之前:我完全知道它已被弃用;我不打算把它用于任何成品
与其用整个纹理映射绘制的四边形(上面的代码就是这么做的),不如告诉它只映射图像的一个区域,比如:x64,y128,宽度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;
然后,可以使用纹理图集中的像素位置指定纹理坐标
对于可编程管道,上述内容已过时。但是,通过将统一的值传递给着色器,然后与纹理坐标相乘,可以轻松应用相同类型的缩放
在顶点着色器中,它可能如下所示:
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
,并将其用于纹理采样操作
在客户机代码中,您可以设置制服:
GLint texCoordScaleLoc = glGetUniformLocation(program, "TexCoordScale");
glUniform2f(texCoordScaleLoc, 1.0f / 1024.0f, 1.0f / 1024.0f);
然后像平常一样为纹理坐标设置顶点属性,只是现在可以使用像素坐标,而不是“奇怪的分数”。如果我使用缩放变换(这就像做梦一样)会有任何明显的性能损失吗?我怀疑会有可测量的差异。@Krythic:你应该知道纹理矩阵-作为矩阵堆栈的其余部分和固定函数管道的整体-与立即模式一样不受欢迎。然而,将其移植到可编程着色器是很简单的-你甚至不需要一个完整的4x4矩阵的开销,一个简单的2D向量乘法就足够了。@derhass如果你有时间,你认为你可以写一个这样的例子吗?我很感兴趣。@Krythic:嗯,在什么背景下?您对可编程管道和GLSL着色器编程的熟悉程度如何?加上这个比例因子,就可以加上uniformvec2texscale
和稍后的纹理采样时,只需将texcoords乘以该向量即可应用纹理。在客户端,您只需将制服设置为(1.0/宽,1.0/高)
。对于相当现代的GLSL版本,您还可以直接在着色器中查询纹理大小,这样就可以完全不用制服进行查询。