纹理加载不正确 OpenGL

3

我正在使用MS Visual Studio 2019学习C++中的OpenGL技术。我是从https://learnopengl.com开始学习的,它展示了很多加载纹理的方法。我只用了stb image来加载纹理,以下是加载纹理的函数:

 
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();
    }

我尝试打印的质感是:

this

但我得到的结果是:

this

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

@AlexF 我尝试改变顶点,结果在 glGenerateMipmap(GL_TEXTURE_2D); 出现了访问冲突错误。 - Shreeyash Shrestha
我会认为图像行的对齐方式与纹理图像的对齐方式不匹配。我知道某些图像文件格式(例如BMP)需要将行对齐到4的倍数。请注意:纹理上传和像素读取 - Scheff's Cat
1个回答

4

纹理坐标与顶点的关联不正确。请更改为:

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 * 宽度不可被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不完整"。


@ShreeyashShrestha 在答案中完全按照我所做的去做。使用纹理坐标(我现在已经更改了)和 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);。(但不要更改其他任何内容)。我已经测试过代码,现在对我来说可以正常工作了。 - Rabbid76

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接