使用GLSL组合切片的纹理坐标

时间:2014-07-07 09:50:02

标签: algorithm opengl glsl shader vertex-shader

前言

考虑以下示例图片:

Tilesheet Example


请注意以下事项:

  • 每个图块索引从左到右,从上到下递增
  • 只有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;
}

1 个答案:

答案 0 :(得分:2)

反转纹理坐标似乎是黑暗中的一个镜头。你只需要缩小它:

float endX = (startX + tileWidth) / imgWidth;
float endY = (startY + tileHeight) / imgHeight;
startX = startX / imgWidth;
startY = startY / imgHeight;