首页 > 解决方案 > 从剪辑计算纹理坐标

问题描述

我正在使用以下片段着色器来显示纹理:

std::string const fragment_shader_source = 
    "#version 330 core\n"
    ""
    "in vec4 fColor;\n"
    "in vec2 fTexPos;\n"
    "\n"
    "out vec4 finalColor;\n"
    "\n"
    "uniform sampler2D textureUniform;\n"
    "\n"
    "void main() {\n"
    "    \n"
    "    vec4 textureColor = texture(textureUniform, fTexPos);\n"
    "    finalColor = fColor * textureColor;\n"
    "}";

在此处输入图像描述

但是,我希望能够只显示图像的剪辑而不是整个图像。所以,我添加了一个对 textureSize 的调用来获取纹理的宽度和高度,这样我就可以自己标准化坐标。但是,它提出了看起来只是重复的东西

std::string const fragment_shader_source = 
    "#version 330 core\n"
    ""
    "in vec4 fColor;\n"
    "in vec2 fTexPos;\n"
    "\n"
    "out vec4 finalColor;\n"
    "\n"
    "uniform sampler2D textureUniform;\n"
    "\n"
    "void main() {\n"
    "    \n"
    "    ivec2 samplerSize = textureSize(textureUniform, 0);\n"
    "    vec2 texturePos = vec2(fTexPos.x / float(samplerSize.x), fTexPos.y / float(samplerSize.y));\n"
    "    vec4 textureColor = texture(textureUniform, texturePos);\n"
    "    finalColor = fColor * textureColor;\n"
    "}";

这就是我上传数据的方式:

  glBufferData(GL_ARRAY_BUFFER, sizeof(acorn::graphics::Vertex) * sprite_batch_.size() * 6, nullptr, GL_DYNAMIC_DRAW);

  std::vector<Vertex> vertex_data;
  for(auto const& sprite : sprite_batch_) {
    GLfloat fw = (sprite.origin_x + sprite.u);
    GLfloat bw = sprite.origin_x;

    GLfloat fh = (sprite.origin_y + sprite.v);
    GLfloat bh = sprite.origin_y;

    //                      body                  color          texture
    //                      x     y      r    g      b    a     s   t
    vertex_data.push_back({0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, fw, fh});
    vertex_data.push_back({-0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, bw, fh});
    vertex_data.push_back({0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, fw, bh});
    vertex_data.push_back({-0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, bw, bh});
    vertex_data.push_back({-0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, bw, fh});
    vertex_data.push_back({0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, fw, bh});

  }

  glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vertex) * vertex_data.size(), static_cast<void*>(vertex_data.data()));


  glDrawArrays(GL_TRIANGLES, 0, 6);

在此处输入图像描述

标签: c++openglglsl

解决方案


您所做的是获取纹理坐标并重新映射它们以仅覆盖图像中的第一个像素。如果要剪切输入图像,则需要向着色器指定要显示的区域的边界。您可以传入左下角和右上角坐标并针对这些坐标进行测试。像这样的东西(未经测试):

#version 330 core
in vec4 fColor;
in vec2 fTexPos;

out vec4 finalColor

uniform sampler2D textureUniform;
uniform float2 lowerLeft;
uniform float2 upperRight;

void main()
{
    if ((lowerLeft.x <= fTexPos.x) && (fTexPos.x <= upperRight.x) &&
        (lowerLeft.y <= fTexPos.y) && (fTexPos.y <= upperRight.y))
    {
        textureColor = texture(textureUniform, fTexPos);
    }
    else
    {
        textureColor = vec4(0.0);
    }
    finalColor = textureColor * fColor;
}

推荐阅读