【问题标题】:Texture isn't loading properly OpenGL纹理未正确加载 OpenGL
【发布时间】:2021-08-31 23:37:15
【问题描述】:

我正在使用 MS Visual Studio 2019,并且只是在 C++ 中学习 opengl。我从https://learnopengl.com 开始学习,它展示了许多加载纹理的方法。我只是使用 stb 图像来加载纹理,这是加载纹理的函数:

 
static unsigned int loadTexture(char const* path)
{
    unsigned int textureID;
    glGenTextures(1, &textureID);

    int width, height, nrComponents;
    unsigned char* data = stbi_load(path, &width, &height, &nrComponents, 0);
    if (data)
    {
        GLenum format;
        if (nrComponents == 1)
            format = GL_RED;
        else if (nrComponents == 3)
            format = GL_RGB;
        else if (nrComponents == 4)
            format = GL_RGBA;

        glBindTexture(GL_TEXTURE_2D, textureID);
        glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        stbi_image_free(data);
    }
    else
    {
        std::cout << "Texture failed to load at path: " << path << std::endl;
        stbi_image_free(data);
    }

    return textureID;
}

我尝试将它加载到一个矩形中,但不知何故,它似​​乎无法在其上正确打印。我被困了几个小时,仍然找不到我犯了什么错误。 这是初始化 VAO 和 VBO 的代码:

    inline void InitTextureBuffer(const char* img_filepath)
    {
        texture_shader.Bind();
        tex_img_id = loadTexture(img_filepath);
        glGenVertexArrays(1, &tex_VAO);
        glGenBuffers(1, &tex_VBO);
        glBindVertexArray(tex_VAO);
        glBindBuffer(GL_ARRAY_BUFFER, tex_VBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindVertexArray(0);
        texture_shader.Unbind();
    }

和绘制矩形的函数:

    inline void Draw_Rectangle_IMG(_Point _min, _Point _max)
    {
        glActiveTexture(GL_TEXTURE0);
        glBindVertexArray(tex_VAO);
        texture_shader.Bind();
        float vertices[] =
        {
             _min.x, _min.y,   0.0f, 0.0f ,
             _max.x, _min.y,   0.0f, 1.0f ,
             _max.x, _max.y,   1.0f, 1.0f ,

             _min.x, _min.y,   0.0f, 0.0f ,
             _max.x, _max.y,   1.0f, 1.0f ,
             _min.x, _max.y,   1.0f, 0.0f ,
        };
        glBindTexture(GL_TEXTURE_2D, tex_img_id);

        glBindBuffer(GL_ARRAY_BUFFER, tex_VBO);
        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glDrawArrays(GL_TRIANGLES, 0, 6);

        glBindVertexArray(0);
        glBindTexture(GL_TEXTURE_2D, 0);
        texture_shader.Unbind();
    }

我用过的着色器:

const std::string texture_shader_vs =
{
    "#version 330 core\n"
    "layout(location = 0) in vec2 aPos;\n"
    "layout(location = 1) in vec2 aTexCoord;\n"
    "\n"
    "out vec2 TexCoord;\n"
    "\n"
    "void main()\n"
    "{\n"
    "   gl_Position = vec4(aPos,0.0f, 1.0f);\n"
    "   TexCoord = aTexCoord;\n"
    "}\n"
};
const std::string texture_shader_fs =
{
    "#version 330 core\n"
    "out vec4 FragColor;\n"
    "\n"
    "in vec2 TexCoord;\n"
    "\n"
    "// texture sampler\n"
    "uniform sampler2D texture1;\n"
    "\n"
    "void main()\n"
    "{\n"
    "   FragColor = texture(texture1, TexCoord);\n"
    "}\n"
};

以及我调用的函数:

    _Point p1, p2;
    p1 = _Point(-0.5f, -0.25f);
    p2 = _Point(0.5f, 0.25f);

    ogl.InitTextureBuffer("resources/textures/1.png");
    while (!glfwWindowShouldClose(ogl.GetWindow()))
    {
        glClear(GL_COLOR_BUFFER_BIT);

        ogl.Draw_Rectangle_IMG(p1, p2);

        glfwSwapBuffers(ogl.GetWindow());
        glfwPollEvents();
    }

我尝试打印的纹理是:

但我得到的结果是

我似乎找不到错误。任何帮助将不胜感激。谢谢!

【问题讨论】:

  • @AlexF 我尝试更改顶点,导致glGenerateMipmap(GL_TEXTURE_2D);中出现访问冲突错误
  • 我会假设图像行的对齐方式与纹理图像的对齐方式不匹配。我知道某些图像文件格式(例如BMP)需要行对齐到 4 的倍数。仅供参考:Texture upload and pixel reads

标签: c++ opengl textures


【解决方案1】:

纹理坐标与顶点的关联是错误的。改为:

float vertices[] =
{
    _min.x, _min.y,   0.0f, 1.0f,
    _max.x, _min.y,   1.0f, 1.0f,
    _max.x, _max.y,   1.0f, 0.0f,

    _min.x, _min.y,   0.0f, 1.0f,
    _max.x, _max.y,   1.0f, 0.0f,
    _min.x, _max.y,   0.0f, 0.0f,
};

默认情况下,OpenGL 假定图像每行的开头对齐到 4 个字节。
这是因为 GL_UNPACK_ALIGNMENT 参数默认为 4。当将具有 3 个颜色通道的 RGB 图像加载到纹理对象并且 3*width 不能被 4 整除时,这可能会导致未对齐。

在使用glTexImage2D 指定纹理图像之前,通过将GL_UNPACK_ALIGNMENT 设置为1 来更改对齐方式:

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);

当您删除glGenerateMipmap(GL_TEXTURE_2D); 时,您还必须更改缩小功能(GL_TEXTURE_MIN_FILTER)。由于过滤器为GL_LINEAR_MIPMAP_LINEAR,因此如果您不将最小化函数更改为GL_NEARESTGL_LINEAR,则纹理将为“Mipmap Incomplete”。

【讨论】:

  • @ShreeyashShrestha 完全按照我在答案中所做的操作。使用纹理坐标(我现在已经更改)和glPixelStorei(GL_UNPACK_ALIGNMENT, 1);。 (但没有其他改变)。我已经测试了代码,它现在对我来说很好。
猜你喜欢
  • 1970-01-01
  • 2015-12-22
  • 1970-01-01
  • 1970-01-01
  • 2013-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多