提问人:Nico Cano 提问时间:9/13/2023 最后编辑:Nico Cano 更新时间:9/14/2023 访问量:93
我使用 STB 映像加载映像时出错
I have an error loading an image with STB image
问:
我的问题是,在使用库 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);
}
这是纹理绑定函数:
void TEXTURE::Bind(unsigned int slot){
glCall(glActiveTexture(GL_TEXTURE0 + slot));
glCall(glBindTexture(m_TextureType, m_TextureID));
}
加载是由 OBJECT 类进行的:
这会将纹理添加到矢量中:
void OBJECT::AddTextures(TEXTURE texture){
textures.push_back(texture);
}
这将加载 OBJECT(和纹理):
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());
}
这是着色器绑定和使用函数
void SHADER::Bind(){
glCall(glUseProgram(m_ShaderProgramID));
}
void SHADER::Use(){
glCall(glUseProgram(m_ShaderProgramID));
}
这是顶点着色器:
#version 330 core
layout (location = 0) in vec3 aPos; // the position variable has attribute position 0
layout (location = 1) in vec2 aTexCoord;
out vec3 vertexColor; // specify a color output to the fragment shader
out vec2 TexCoord;
uniform mat4 transform;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform mat4 MVP;
void main()
{
gl_Position = projection * view * model * transform * vec4(aPos, 1.0); // see how we directly give a vec3 to vec4's constructor
//gl_Position = MVP* vec4(aPos, 1.0);
//gl_Position = projection * view * model * vec4(aPos, 1.0);
TexCoord = aTexCoord;
}
这是片段着色器:
#version 330 core
out vec4 FragColor;
in vec3 vertexColor; // the input variable from the vertex shader (same name and same type)
in vec2 TexCoord;
uniform sampler2D texture1;
uniform sampler2D texture2;
uniform float blend;
void main()
{
//FragColor = texture(texture2, vec2(TexCoord.x, TexCoord.y * -1 ));
FragColor = mix(texture(texture1, TexCoord), texture(texture2, vec2(TexCoord.x, TexCoord.y * -1 )) / 10, blend);
}
我认为它的所有代码都是相关的,这里是我项目的文件树(顺便说一句,我正在使用 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 或 C++ 源文件中以创建实现之前,请执行stbi_image
#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 的幂(对于像素解包对齐很重要)、通道数(像素格式)等。
要在上传像素数据之前设置像素解包对齐方式,请执行
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //default is 4
此外
TEXTURE tex2("res/textures/dog.jpg", FILTER_NEAREST, GL_RGBA, GL_TEXTURE_2D);
如果图像文件没有 Alpha 通道(编码图像就是这种情况),则调用 将失败,因为您传递的格式参数无效(与像素数据不匹配)。因此,请检查您的图像有多少个通道,并根据该通道使用正确的格式参数。jpeg
glTexImage2D
#1 -> GL_RED
#2 -> GL_RG
#3 -> GL_RGB
#4 -> GL_RGBA
可以强制添加其他通道,因为您必须将最后一个参数设置为所需的通道数,这意味着要获取存储在图像文件中的通道数。stbi
stbi_load
0
与其加载整个图像,不如做
stbi_info(filename, &width, &height, &channels);
它仅加载图像文件的标题(大多数图像格式确实包含包含所有相关信息的标题)。
一旦数据成功加载并上传到 GPU,就该将纹理绑定到特定的纹理图像单元了。
还必须通过设置相应的统一变量来通知着色器,例如
//bind tex to unit 0
glActiveTexture(GL_TEXTURE0);
glBindTexture(target, tex);
//set the value of the uniform located at sampler_loc to the
//unit where the texture is bound to, here 0
glProgramUniform1i(prog, sampler_loc, 0);
评论
#define STBI_FAILURE_USERMSG
stbi_load
nullptr
stbi_failure_reason()
STBI_FAILURE_USERMSG
glActiveTexture(GLenum)
glBindTexture(GLuint)
glBindTextureUnit(GLuint, GLuint)
glProgramUniform
评论
stbi_failure_reason()
TEXTURE::Bind()
shader.Bind()
sampler