【问题标题】:Non power-of-two textures giving a "This application has requested the Runtime..." error非二次幂纹理给出“此应用程序已请求运行时...”错误
【发布时间】:2014-08-17 15:44:35
【问题描述】:

我正在使用 OpenGL 创建一个简单的 3D 游戏,但我真的不明白为什么会出现这个错误。我正在尝试加载一个数字集(一组文件,名为“1.tga”、“2.tga”等)以用作乐谱显示,但由于某种原因,如果有任何一个图像'尺寸不是 2 的幂,然后我得到错误:

“此应用程序以异常方式请求运行时终止它。请联系应用程序的支持团队以获取更多信息。”

更奇怪的是,它不将 128、64、32 等视为 2 的幂。我不明白的是,在程序中我已经加载了不是 2 次方的纹理(天空盒,即 3072 x 2304),而且效果很好。但是,出于某种原因,这不是。

我不确定提供我的代码是否会有所帮助,但这里是:

void CNumberSet::Load(char *NumberSetDirectory, bool BottomLeftAlign) {
    std::string NSD;
    m_BottomLeftAlign = BottomLeftAlign;
    for (int i = 0; i < 11; i++) {
        // Load texture for each digit
        NSD = NumberSetDirectory;
        if (NSD.at(NSD.length() - 1) == '\\' || NSD.at(NSD.length() - 1) == '/') NSD += (ToString(i) + ".tga");
        else NSD += ("/" + ToString(i) + ".tga");
        m_Textures[i].LoadDataFromFile((char *) NSD.c_str(), CTexture::TARGA);
        m_Textures[i].SetTextureParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        m_Textures[i].SetTextureParameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        // Load and create mesh for each digit, and associate with texture
        float Width = m_Textures[i].GetWidth();
        float Height = m_Textures[i].GetHeight();

        if (BottomLeftAlign) {
            float Vertices[] = {
                0.0f, Height, 0.0f,             0.0f, 1.0f,
                0.0f, 0.0f, 0.0f,               0.0f, 0.0f,
                Width, Height, 0.0f,            1.0f, 1.0f,
                Width, 0.0f, 0.0f,              1.0f, 0.0f
            };
            m_Meshes[i].LoadData(Vertices, sizeof(Vertices), GL_STATIC_DRAW);
        } else {
            float Vertices[] = {
                -Width, Height, 0.0f,           0.0f, 1.0f,
                -Width, 0.0f, 0.0f,             0.0f, 0.0f,
                0.0f, Height, 0.0f,             1.0f, 1.0f,
                0.0f, 0.0f, 0.0f,               1.0f, 0.0f
            };
            m_Meshes[i].LoadData(Vertices, sizeof(Vertices), GL_STATIC_DRAW);
        }

        m_Meshes[i].SetTexture(&m_Textures[i]);
        m_Meshes[i].SetVertexAttribute(m_ShaderProgram, "Vertex", 3, GL_FLOAT, 5 * sizeof(float), (void *)(0 * sizeof(float)));
        m_Meshes[i].SetVertexAttribute(m_ShaderProgram, "TexCoord", 2, GL_FLOAT, 5 * sizeof(float), (void *)(3 * sizeof(float)));
    }
}

LoadDataFromFile函数负责加载每张图片,其来源在这里:

bool CTexture::LoadDataFromFile(char *Filename, short Type) {
    std::ifstream File(Filename, std::ios::in | std::ios::binary);
    switch (Type) {
    case BMP24: {
        char Header[54];
        char *Data;
        int Width, Height;

        if (File.is_open()) {
            File.read(Header, 54);
            if (Header[0] != 'B' || Header[1] != 'M') {
                    MessageBox(NULL, "Not a valid BMP24 file!", "Error", MB_OK | MB_ICONERROR);
                return false;
            }
            Width = *(int*) & Header[18];
            Height = *(int*) & Header[22];
            Data = new char [Width * Height * 3];
            File.read(Data, Width * Height * 3);
            File.close();
        } else {
            MessageBox(NULL, "Cannot open BMP24 file!", "Error", MB_OK | MB_ICONERROR);
            return false;
        }

        glBindTexture(GL_TEXTURE_2D, m_ID);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, Width, Height, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, Data);

        m_Width = Width;
        m_Height = Height;

        delete Data;
        return true;
        break; }
    case TARGA: {
        char Header[12];
        char ImageInfo[6];
        char *Data;
        int Width, Height, BitDepth;

        char UncompressedTGA[12] = { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        char CompressedTGA[12] = { 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

        if (File.is_open()) {
            File.read(Header, 12);
            File.read(ImageInfo, 6);
            Width = ImageInfo[1] * 256 + ImageInfo[0];
            Height = ImageInfo[3] * 256 + ImageInfo[2];
            BitDepth = ImageInfo[4];
            int TGASize = Width * Height * BitDepth / 8;
            Data = new char[TGASize];

            m_Width = Width;
            m_Height = Height;

            if (BitDepth != 24 && BitDepth != 32) {
                MessageBox(NULL, "Only bit depths of 24 and 32 are supported!", "Error", MB_OK | MB_ICONERROR);
                return false;
            }

            if (memcmp(Header, UncompressedTGA, 12) == 0) {
                // Uncompressed
                File.read(Data, TGASize);
            } else if (memcmp(Header, CompressedTGA, 12) == 0) {
                // Compressed
                unsigned char ChunkHeader = 0;
                unsigned char *ColourBuffer = new unsigned char[BitDepth / 8];
                unsigned int PixelCount = Width * Height;
                unsigned int CurrentPixel = 0;
                unsigned int CurrentByte = 0;

                while (CurrentPixel < PixelCount) {
                    File.read((char *) &ChunkHeader, 1);
                    if (ChunkHeader < 128) {    // RAW chunk
                        ChunkHeader++;
                        for (int i = 0; i < ChunkHeader; i++) {
                            File.read((char *)ColourBuffer, BitDepth / 8);
                            Data[CurrentByte + 0] = ColourBuffer[0];                        // Write 'B' byte
                            Data[CurrentByte + 1] = ColourBuffer[1];                        // Write 'G' byte
                            Data[CurrentByte + 2] = ColourBuffer[2];                        // Write 'R' byte
                            if (BitDepth == 32) Data[CurrentByte + 3] = ColourBuffer[3];    // Write 'A' byte (if needed)
                            CurrentByte += BitDepth / 8;
                            CurrentPixel++;
                        }
                    } else {                    // Run-length encoded chunk
                        ChunkHeader -= 127;
                        File.read((char *) ColourBuffer, BitDepth / 8);
                        for (int i = 0; i < ChunkHeader; i++) {
                            Data[CurrentByte + 0] = ColourBuffer[0];                        // Write 'B' byte
                            Data[CurrentByte + 1] = ColourBuffer[1];                        // Write 'G' byte
                            Data[CurrentByte + 2] = ColourBuffer[2];                        // Write 'R' byte
                            if (BitDepth == 32) Data[CurrentByte + 3] = ColourBuffer[3];    // Write 'A' byte (if needed)
                            CurrentByte += BitDepth / 8;
                            CurrentPixel++;
                        }
                    }
                }

                delete ColourBuffer;
            } else {
                MessageBox(NULL, "Not a valid TARGA file!", "Error", MB_OK | MB_ICONERROR);
                return false;
            }
            File.close();
        } else {
            MessageBox(NULL, "Cannot open TARGA file!", "Error", MB_OK | MB_ICONERROR);
            return false;
        }

        glBindTexture(GL_TEXTURE_2D, m_ID);
        glTexImage2D(GL_TEXTURE_2D, 0, BitDepth == 24 ? GL_RGB : GL_RGBA, Width, Height, 0, BitDepth == 24 ? GL_BGR_EXT : GL_BGRA_EXT, GL_UNSIGNED_BYTE, Data);

        delete Data;
        return true;
        break; }
    default:
        MessageBox(NULL, "Image format not recognised!", "Error", MB_OK | MB_ICONERROR);
        return false;
        break;
    }
}

【问题讨论】:

  • 您收到的消息意味着您的应用程序做了一些非常糟糕的事情,例如除以 0 或访问 null 对象。你能通过 Debugger 运行它,看看是哪一行出现了这个错误吗?
  • 从我几天前的尝试来看,是 glTexImage2D 行导致了问题。

标签: c++ opengl graphics 3d textures


【解决方案1】:

在这里遇到的限制很可能不是大小必须是 2 的幂,而是它需要是默认设置的 4 的倍数。

注意:此答案类似于Missing Pixel When Loading Texture?,但我决定不将问题指定为重复问题,因为问题场景和产生的症状不同。

GL_UNPACK_ALIGNMENT 像素存储值控制传递给glTexImage2D() 的纹理数据的行对齐。默认值为 4。这意味着当glTexImage2D() 读取您的输入数据时,行大小(以字节为单位)将向上舍入为 4 的下一个倍数。

由于您以 GL_BGR_EXT 格式指定纹理,因此每个像素有 3 个字节。因此,如果纹理的宽度也是 4 的倍数,则行大小(以字节为单位)仅为 4 的倍数。

要在不填充您传递给glTexImage2D() 的纹理数据的情况下完成这项工作,必须将行对齐值更改为 1:

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

【讨论】:

  • 我试过了,但不幸的是没有用。我应该把这条线放在一个特定的地方吗?我写之前需要绑定纹理吗?
  • 不,这是一个“全局”(即每个上下文)设置。它将适用于所有纹理。在glTexImage2D() 调用之前的任何地方都可以。
猜你喜欢
  • 1970-01-01
  • 2016-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多