Algorithm 组成一个平铺';使用GLSL创建纹理坐标 前言
考虑以下示例图像:Algorithm 组成一个平铺';使用GLSL创建纹理坐标 前言,algorithm,opengl,glsl,shader,vertex-shader,Algorithm,Opengl,Glsl,Shader,Vertex Shader,考虑以下示例图像: 注意以下几点: 每个平铺索引从左到右、从上到下递增 只有28个有效磁贴(在可能的32个磁贴中) 在本例中,我们知道每个磁贴的像素为32x32 我们还知道整体图像尺寸为256x128像素 问题: 仅给出上述信息和有效的平铺索引,我们如何使用顶点着色器来构造用于所需平铺的适当纹理坐标,然后将其传递给片段着色器进行采样?幸运的是,我们可以利用gl_VertexID来识别我们需要的图像的哪个“角点”。。。但是,由于我们使用的是标准化的文本(而不仅仅是像素),因此我们需要某种
注意以下几点:
- 每个平铺索引从左到右、从上到下递增
- 只有28个有效磁贴(在可能的32个磁贴中)
- 在本例中,我们知道每个磁贴的像素为32x32
- 我们还知道整体图像尺寸为256x128像素
问题: 仅给出上述信息和有效的平铺索引,我们如何使用顶点着色器来构造用于所需平铺的适当纹理坐标,然后将其传递给片段着色器进行采样?幸运的是,我们可以利用
gl_VertexID
来识别我们需要的图像的哪个“角点”。。。但是,由于我们使用的是标准化的文本(而不仅仅是像素),因此我们需要某种方法将其缩小到0到1之间,这会使算法更加复杂
到目前为止,我得到的是,虽然它似乎只显示图像中的纯色#version 330 core
layout(location=0) in vec3 in_pos;
out vec2 out_texCoord;
void main()
{
// These will eventually be uniforms/attributes, and are
// only used here for more immediate debugging purposes
int tileNum = 1; // Desired tile index
int tileCount = 28; // Maximum # of tiles
float tileWidth = 32; // Width of each tile in pixels
float tileHeight = 32; // Height of each tile in pixels
float imgWidth = 256; // Overall width of image in pixels
float imgHeight = 128; // Overall height of image in pixels
// Attempt to calculate the correct texture coordinates
// for the desired tile, given only the above info...
int tileIndex = tileNum % tileCount;
int columnCount = int(imgWidth / tileWidth);
int rowCount = int(imgHeight / tileHeight);
int tileX = tileIndex % columnCount;
int tileY = int(float(tileIndex) / float(columnCount));
float startX = float(tileX) * tileWidth;
float startY = float(tileY) * tileHeight;
float endX = 1.0f / (startX + tileWidth);
float endY = 1.0f / (startY + tileHeight);
startX = 1.0f / startX;
startY = 1.0f / startY;
// Check which corner of the image we are working with
int vid = gl_VertexID % 4;
switch(vid) {
case 0:
out_texCoord = vec2(startX, endY);
break;
case 1:
out_texCoord = vec2(endX, endY);
break;
case 2:
out_texCoord = vec2(startX, startY);
break;
case 3:
out_texCoord = vec2(endX, startY);
break;
}
gl_Position = vec4(in_pos, 1);
}
免责声明 在任何人谈论缺少信息/代码之前,请注意,使用以下代码确实可以正确显示整个图像,正如预期的那样…
有效地说,这意味着实际纹理坐标计算有问题,
而不是我的应用程序的OpenGL实现有问题:
int vid = gl_VertexID % 4;
switch(vid) {
case 0:
out_texCoord = vec2(0, 1);
break;
case 1:
out_texCoord = vec2(1, 1);
break;
case 2:
out_texCoord = vec2(0, 0);
break;
case 3:
out_texCoord = vec2(1, 0);
break;
}
反转纹理坐标似乎是在黑暗中拍摄的。您只需将其缩小:
float endX = (startX + tileWidth) / imgWidth;
float endY = (startY + tileHeight) / imgHeight;
startX = startX / imgWidth;
startY = startY / imgHeight;
嗯。。嗯,它确实显示了一块瓷砖。只是不是正确的。它从第一块瓷砖开始,正如预期的。。。但是,就好像每个增量的平铺索引跳过任意数量的平铺一样。因此,也许我们在这里遗漏了一些其他内容……您是否通过更改
tileNum
来增加?你是一次画一个四边形吗?我不确定int(.)
操作符的行为是否与您期望的一样。使用纯cast操作符(int)()
可能值得一试。不过我不确定。您能否将tileIndex
、tileX
和tileY
作为颜色输出,并检查这些值是否合理?在我上次发表评论之前,我已经检查了tileIndex
在tileIndex>5
时,通过将所有片段设置为红色,在着色器中是否正确递增(以及直接将其设置为顶点着色器本身内的所需值)。在这两种情况下,tileIndex
都是正确的。我还没有在内部检查tileX
或tileY
,但我已经将其绘制出来,并使用计算器确保我使用了正确的公式。此外,GLSL不允许C样式转换(编译/链接着色器后会出现错误),所以我知道这也不是问题所在。现在你可以明白为什么我这么长时间以来一直坚持这一点了……解决方案似乎很简单,我确信它实际上非常简单,但实际的答案不知怎么地让我难以捉摸。真是个难题!嗯……偏移量总是4的倍数。你有机会调试着色器吗?我通常不要使用OGL,而是DX,因此我无法帮助您。您可以尝试将%tileCount
放在一边吗?我感觉问题是由一个模引起的。