OpenGL glGenVertexArray() 异常
OpenGL glGenVertexArray() Exception
我现在正在使用 SDL、glew 和 glm 使用 C++ 学习 OpenGL。我已经到了 "VAO and 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();
}
我已经阅读了关于这个问题的其他帖子,他们的解决方案似乎是 "set glewExperimental = GL_TRUE." 如您所见,我这样做了,但仍然出现异常。当我将旧的图形管道与 OpenGL 一起使用时,它起作用了。然而现在,它没有。我使用的是 OpenGL 3.0+,有什么问题吗?
您是否以正确的顺序调用 类 程序?就像它真的在生成数组之前创建上下文一样吗?我有同样的问题,这就是原因。
如果你有一段时间没有更新你的图形驱动程序,你也可以尝试更新^^
崩溃数据表明 glGenVertexArrays()
功能不可用,这很可能是您的 GLEW/SDL 设置有问题。
但是,您的代码中还有一个微妙但非常关键的问题。我不认为它应该导致崩溃,但它肯定会阻止它工作。有害行在这里:
_mesh = Mesh(_vertices, 3);
在这里,您将一个(新构造的)Mesh
实例分配给一个变量。此行发生的情况如下:
- 创建了一个新的
Mesh
对象。
- 构造函数被调用。在构造函数中创建 VAO 和其他 OpenGL 对象。
- 新对象被分配给
_mesh
变量。由于您的 Mesh
class 没有定义赋值运算符,因此使用默认的成员赋值。
- 由于新创建的
Mesh
实例只存在于语句中,所以被销毁了。
- 对象的析构函数被调用。在析构函数中,您删除了 VAO。
所以在这条语句的最后,你的 VAO 已经被删除了。您仍然将 VAO id 存储在 _mesh
变量的成员中,但此 id 现在无效。
在 C++ 中包装 OpenGL 对象 classes 如果您没有牢牢掌握 C++,并且不确切理解如何实现正确的复制和赋值语义,通常会造成麻烦。
我在此处对类似问题的回答中详细说明了解决此类问题的一些选项:。最直接的方法是不允许复制这些类型的对象,并在整个代码中使用(智能)指针引用它们。
我现在正在使用 SDL、glew 和 glm 使用 C++ 学习 OpenGL。我已经到了 "VAO and 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();
}
我已经阅读了关于这个问题的其他帖子,他们的解决方案似乎是 "set glewExperimental = GL_TRUE." 如您所见,我这样做了,但仍然出现异常。当我将旧的图形管道与 OpenGL 一起使用时,它起作用了。然而现在,它没有。我使用的是 OpenGL 3.0+,有什么问题吗?
您是否以正确的顺序调用 类 程序?就像它真的在生成数组之前创建上下文一样吗?我有同样的问题,这就是原因。 如果你有一段时间没有更新你的图形驱动程序,你也可以尝试更新^^
崩溃数据表明 glGenVertexArrays()
功能不可用,这很可能是您的 GLEW/SDL 设置有问题。
但是,您的代码中还有一个微妙但非常关键的问题。我不认为它应该导致崩溃,但它肯定会阻止它工作。有害行在这里:
_mesh = Mesh(_vertices, 3);
在这里,您将一个(新构造的)Mesh
实例分配给一个变量。此行发生的情况如下:
- 创建了一个新的
Mesh
对象。 - 构造函数被调用。在构造函数中创建 VAO 和其他 OpenGL 对象。
- 新对象被分配给
_mesh
变量。由于您的Mesh
class 没有定义赋值运算符,因此使用默认的成员赋值。 - 由于新创建的
Mesh
实例只存在于语句中,所以被销毁了。 - 对象的析构函数被调用。在析构函数中,您删除了 VAO。
所以在这条语句的最后,你的 VAO 已经被删除了。您仍然将 VAO id 存储在 _mesh
变量的成员中,但此 id 现在无效。
在 C++ 中包装 OpenGL 对象 classes 如果您没有牢牢掌握 C++,并且不确切理解如何实现正确的复制和赋值语义,通常会造成麻烦。
我在此处对类似问题的回答中详细说明了解决此类问题的一些选项: