【问题标题】:OpenGL glGenVertexArray() ExceptionOpenGL glGenVertexArray() 异常
【发布时间】:2015-07-15 16:51:56
【问题描述】:

我现在正在使用 SDL、glew 和 glm 使用 c++ 学习 OpenGL。我已经到了“VAO 和 VBO”阶段。但是,我收到一个错误。当我运行我的程序时,我得到一个异常:LearningOpenGL.exe 中 0x74DECB49 处的未处理异常:0xC0000005:访问冲突执行位置 0x00000000。有一个箭头指向线 glGenVertexArrays 我初始化了 SDL,创建了一个 OpenGL 上下文,并且正在使用 OpenGL 3.0+。

这里是 Display.cpp(初始化一切)

    #include "Display.h"

    Display::Display(int width, int height, std::string title)
    {
        _displayWidth = width;
        _displayHeight = height;
        _displayTitle = title;
        _window = nullptr;
    }

    Display::Display()
    {

    }

    Display::~Display()
    {

    }

    void Display::createDisplay()
    {
        // Initialize SDL
        SDL_Init(SDL_INIT_EVERYTHING);
        // Setting attributes to our window
        SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
        SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
        SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
        SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
        SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32);
        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

        // Create Window
        _window = SDL_CreateWindow((_displayTitle.c_str()), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _displayWidth, _displayHeight, SDL_WINDOW_OPENGL);
        // Error Check Window
        if (_window == nullptr)
        {
            std::cerr << "Window could not be created!" << std::endl;
        }
        else
        {
            std::cout << "Window Created Successfully With SDL!" << std::endl;
        }
        // Create OpenGL Context
        _glContext = SDL_GL_CreateContext(_window);

        // Initialize GLEW
        glewExperimental = GL_TRUE;
        GLenum status = glewInit();

        if (glewExperimental)
        {
            std::cout << "Glew Experimental: On" << std::endl;
        }
        else
        {
            std::cout << "Glew Experimental: Off" << std::endl;
        }
        // Error Check GLEW
        if (status != GLEW_OK)
        {
            std::cerr << "GLEW could not be initialized!" << std::endl;
        }
        else
        {
            std::cout << "GLEW Was Initilized Successfully!" << std::endl;
        }

        // Log OpenGL Version Number
        std::cout << "Using OpenGL Version: " << glGetString(GL_VERSION) << std::endl;

        _closed = false;
    }

    void Display::destroyDisplay()
    {
        SDL_GL_DeleteContext(_glContext);
        SDL_DestroyWindow(_window);
        SDL_Quit();
    }

    void Display::update()
    {
        SDL_GL_SwapWindow(_window);

        // Check for Input
        while (SDL_PollEvent(&_sdlEvent))
        {
            if (_sdlEvent.type == SDL_QUIT)
            {
                _closed = true;
            }
        }

    }

    bool Display::isClosed()
    {
        return _closed;
    }

这里是Mesh.cpp

#include "Mesh.h"

Mesh::Mesh(Vertex* vertices, unsigned int numVertices)
{
    _renderCount = numVertices;

    // Create VAO
    glGenVertexArrays(1, &_vaoID);
    glBindVertexArray(_vaoID);

    // Create VBO
    glGenBuffers(1, _vboID);
    glBindBuffer(GL_ARRAY_BUFFER, _vboID[POSITION_VB]);

    // Put data into the VBO
    glBufferData(GL_ARRAY_BUFFER, (numVertices * sizeof(vertices[0])), vertices, GL_STATIC_DRAW);

    // Enable the first attibute of the VAO
    glEnableVertexAttribArray(0);

    // Put the data in the VAO
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

    // Unbind the VAO and VBO and disable attribute 0
    glDisableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}

Mesh::Mesh()
{

}

Mesh::~Mesh()
{
    cleanUp();
}

void Mesh::render()
{
    glBindVertexArray(_vaoID);
    glEnableVertexAttribArray(0);

    glDrawArrays(GL_TRIANGLES, 0, _renderCount);

    glDisableVertexAttribArray(0);
    glBindVertexArray(0);
}

void Mesh::cleanUp()
{
    glDeleteBuffers(1, _vboID);
    glDeleteVertexArrays(1, &_vaoID);
}

这里是 Game.cpp

#include "Game.h"

Game::Game()
{
    _display = Display(_displayWidth, _displayHeight, _displayTitle);

    // TODO: Fix Hardcoded 3 below

    _vertices[0] = Vertex(glm::vec3(-1.0f, -1.0f, 0.0f));
    _vertices[1] = Vertex(glm::vec3(1.0f, -1.0f, 0.0f));
    _vertices[2] = Vertex(glm::vec3(0.0f, 1.0f, 0.0f));

    _mesh = Mesh(_vertices, 3);

}

Game::~Game()
{

}

void Game::init()
{
    _display.createDisplay();
}

void Game::gameLoop()
{
    while (!_display.isClosed())
    {
        glClearColor(0.0f, 0.15f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        _mesh.render();

        _display.update();
    }
    _display.destroyDisplay();
}

void Game::start()
{
    init();
    gameLoop();
}

我已阅读有关此问题的其他帖子,他们的解决方案似乎是“设置 glewExperimental = GL_TRUE”。如您所见,我这样做了,但仍然是例外。当我使用带有 OpenGL 的旧图形管道时,它可以工作。然而现在,它没有。我使用的是OpenGL 3.0+,请问有什么问题?

【问题讨论】:

  • 好吧,从目前发布的代码来看,我完全不清楚您使用的是 OpenGL >= 3.0。你当然不会在任何地方要求它。因此,请确保您确实得到了它。另一种选择是在创建上下文(并初始化 glew)之前调用您的网格构造函数。
  • 我确实在 display.cpp 中调用了 getString(Gl_VERSION)。它输出: 3.1.0 Build 8.15.10.2618 ;我还将更新我上面的问题以显示我的游戏类。

标签: c++ opengl sdl glew


【解决方案1】:

崩溃数据表明 glGenVertexArrays() 函数不可用,这很可能是您的 GLEW/SDL 设置存在问题。

但是,您的代码中还有一个微妙但非常关键的问题。我不认为它应该导致崩溃,但它肯定会阻止它工作。有害行在这里:

_mesh = Mesh(_vertices, 3);

在这里,您将一个(新建的)Mesh 实例分配给一个变量。这一行发生的情况如下:

  1. 创建了一个新的Mesh 对象。
  2. 构造函数被调用。在构造函数中创建 VAO 和其他 OpenGL 对象。
  3. 新对象分配给_mesh 变量。由于您的 Mesh 类没有定义赋值运算符,因此使用默认的按成员赋值。
  4. 由于新创建的Mesh实例只存在于语句中,因此被销毁。
  5. 对象的析构函数被调用。在析构函数中,删除 VAO。

因此,在此声明的最后,您的 VAO 已被删除。您仍然将 VAO id 存储在 _mesh 变量的成员中,但该 id 现在无效。

如果您没有牢牢掌握 C++ 并没有准确理解如何实现正确的复制和赋值语义,那么在 C++ 类中包装 OpenGL 对象通常会带来麻烦。

我在此处对类似问题的回答中详细阐述了一些解决此类问题的选项:Mesh class called with default constructor not working OpenGL C++。最直接的方法是不允许复制这些类型的对象,并在整个代码中使用(智能)指针引用它们。

【讨论】:

    【解决方案2】:

    你调用类过程的顺序是否正确?就像它真的在生成数组之前创建上下文一样吗?我有同样的问题,这就是原因。 如果您有一段时间没有更新显卡驱动程序,也可以尝试更新 ^^

    【讨论】:

      猜你喜欢
      • 2020-01-28
      • 1970-01-01
      • 2014-11-08
      • 2015-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多