我使用 STB 图像加载图像时出错

问题描述 投票:0回答:1

我的问题是,在使用库 STB 图像加载任何类型的图像时,我收到下一个错误:BAD PNG SIG,即使它甚至不是 PNG,在我尝试创建 OBJECT 类之前,所有代码都有效我正在学习 OpenGL,现在我得到的结果是下一个:

首先,我没有发现任何明显的错误,除了我应该看到两个纹理而不仅仅是板条箱的事实之外,

如果我运行程序但使用不同的纹理,发生的另一件事是我得到一个 debugBreak:

纹理生成/加载不同部分的代码如下:

纹理创建/添加:

TEXTURE tex1("res/textures/container.jpg", FILTER_LINEAR, GL_RGB, GL_TEXTURE_2D);

TEXTURE tex2("res/textures/dog.jpg", FILTER_NEAREST, GL_RGBA, GL_TEXTURE_2D);

box1.AddTextures(tex1);

box1.AddTextures(tex2);

这是纹理类:

class TEXTURE{

private:

    unsigned int m_TextureID;
    std::string m_filepath;
    int m_width, m_height, m_BPP;
    unsigned int m_TextureType;

public:

    TEXTURE(std::string filepath, FILTERING_OPTIONS opt, unsigned int RGB_CHANNEL, unsigned int TEXTURE_TYPE, bool FLIP_IMAGE = 0, bool MIPMAP = 1);
    ~TEXTURE();


    void Bind(unsigned int slot = 0);

    void Unbind();


    inline int GetWidth() const { return m_width; }
    inline int GetHeight() const { return m_height; }

};

它的构造函数是下一个:

TEXTURE::TEXTURE(std::string filepath, FILTERING_OPTIONS opt, unsigned int RGB_CHANNEL, unsigned int TEXTURE_TYPE, bool FLIP_IMAGE, bool MIPMAP) : m_filepath(filepath), m_TextureType(TEXTURE_TYPE){

    //stbi_set_flip_vertically_on_load(FLIP_IMAGE);
    stbi_set_flip_vertically_on_load(1);
    glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT));
    glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT));

    float borderColor[] = { 1.0f, 1.0f, 0.0f, 1.0f };
    glCall(glTexParameterfv(TEXTURE_TYPE, GL_TEXTURE_BORDER_COLOR, borderColor));


    if (MIPMAP) {

        switch (opt)
        {
        
        case FILTER_NEAREST:
            glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR));
            glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
            break;
        
        case FILTER_LINEAR:
            glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR));
            glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
            break;
        
        case BOTH:
            glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR));
            glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
            break;
        
        default:

            std::cerr << "[Error]: Wrong option parameter" << std::endl;

            return;
            break;
        }

    }
    else {

        switch (opt)
        {

        case FILTER_NEAREST:
            glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
            glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
            break;

        case FILTER_LINEAR:
            glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
            glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
            break;

        case BOTH:
            glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
            glCall(glTexParameteri(TEXTURE_TYPE, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
            break;

        default:

            std::cerr << "[Error]: Wrong option parameter" << std::endl;

            return;
            break;
        }

    }

    
    unsigned char* data = stbi_load(filepath.c_str(), &m_width, &m_height, &m_BPP, 0);

    glCall(glGenTextures(1, &m_TextureID));

    glCall(glBindTexture(m_TextureType, m_TextureID));

    std::cerr << stbi_failure_reason() << std::endl;

    if (data)
    {
        glCall(glTexImage2D(TEXTURE_TYPE, 0, GL_RGB, m_width, m_height, 0, RGB_CHANNEL, GL_UNSIGNED_BYTE, data));
        glCall(if (MIPMAP) glGenerateMipmap(TEXTURE_TYPE));
    }
    else
    {
        std::cout << "Failed to load texture" << std::endl;
    };
    stbi_image_free(data);



}

并且加载是由 OBJECT 类进行的:

这会将纹理添加到向量中:

void OBJECT::AddTextures(TEXTURE texture){
    textures.push_back(texture);

}

这会加载对象(和纹理):

void OBJECT::Show(bool INDEXED, callbackFunction preRenderFunction){

    vb.Bind();
    va.Bind();
    shader.Bind();
    shader.Use();

    for (unsigned int i = 0; i < textures.size(); i++) {

        textures[i].Bind(i);

    }

    preRenderFunction(this);

    if (INDEXED) {
        ib.Bind();
        glCall(glDrawElements(GL_TRIANGLES, ib.GetLength() , GL_UNSIGNED_INT, 0));
        
    }else glDrawArrays(GL_TRIANGLES, 0, vb.GetLength());

}

我认为相关的所有代码也是,这里是我的项目的文件树(顺便说一句,我正在使用 Visual Studio):

C:.
├───res
│   ├───shaders
│   └───textures
├───src
│   ├───include
│   └───vendor
│       ├───glm
│       │   ├───detail
│       │   ├───ext
│       │   ├───gtc
│       │   ├───gtx
│       │   └───simd
│       ├───imgui
│       └───stb_image
└───x64
    ├───Debug
    │   └───OpenGL-PLSDFMTT.tlog
    └───Release
        └───OpenGL-PLSDFMTT.tlog

我尝试使用VS的调试器来观察发生了什么,在它没有崩溃的情况下,指向图像数据的数据指针为空(数据为空),当它有数据时,它崩溃了,我尝试查看我的逻辑,但这一切似乎都没问题,这就是我所尝试的(所有这一切都在 4 小时内完成)。

c++ opengl opengl-3 stb-image
1个回答
0
投票

在将

stbi_image
头文件包含到 one C 或 C++ 源文件中以创建实现之前,请执行

#define STB_IMAGE_IMPLEMENTATION

或者添加

#define STBI_FAILURE_USERMSG //generate user friendly error messages

之后

#include "stb_image.h"

一旦包含了

stbi_image
实现,要加载图像,请执行

unsigned char *pixels = stbi_load(filename, &width, &height, &channels, 0);

但在做其他事情之前,应该进行强制错误检查

if (!pixels) {
    std::cout
    << "unable to load image: "
    << stbi_failure_reason() 
    << "\n";
    //throw;
}

从现在开始,我们可以放心地假设图像已加载,并且

pixels
width
height
channels
字段中的值可以安全使用。

额外检查,例如如果尺寸是 2 的幂(对于对齐很重要)、通道数等等,肯定不会造成伤害。

© www.soinside.com 2019 - 2024. All rights reserved.