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
放在一边吗?我感觉问题是由一个模引起的。