Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/opengl/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
基于像素区域的OpenGL纹理映射_Opengl_2d_Texture Mapping_Opentk - Fatal编程技术网

基于像素区域的OpenGL纹理映射

基于像素区域的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; 现在

假设游戏中有一个简单的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;

现在,在处理一个简单的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版本,您还可以直接在着色器中查询纹理大小,这样就可以完全不用制服进行查询。