编辑* 我按照 much_a_chos 的建议重新排列了初始化列表,以便 Window 对象在 Game 对象之前初始化,确保首先初始化 glew。但是,这不起作用:
//Rearranged initialization list
class TempCore
{
public:
TempCore(Game* g) :
win(new Window(800, 800, "EngineTry", false)), gamew(g) {}
~TempCore() { if(gamew) delete gamew; }
...
};
下面是我在 Mesh 构造函数中更改的代码,当上面的代码不起作用时:
Mesh::Mesh( Vertex* vertices, unsigned int numVerts )
{
m_drawCount = numVerts;
glewExperimental = GL_TRUE;
if(glewInit() != GLEW_OK){
exit(-150); //application stops and exits here with the code -150
}
glGenVertexArrays(1, &m_vertexArrayObject);
glBindVertexArray(m_vertexArrayObject);
...
}
当我编译和运行时发生的事情令人惊讶。 程序在我从 Window 构造函数复制的 if(glewInit() != GLEW_OK)
处退出。出于某种原因,glew 在 Window 构造函数(之前调用)中正确初始化Game 构造函数),但在 Mesh 构造函数中第二次调用时无法初始化。我认为在一个程序中多次调用 glewInit()
是不好的做法,但我认为如果我真的这样做了,它应该不会失败。有人知道会发生什么吗?我是否在多次调用 glewInit()
时犯了错误?
*编辑结束
我一直在关注 3D Game Engine Development tutorial我在我的代码中遇到了一个奇怪的错误,我将在下面进行演示。我试图纯粹出于教育原因制作自己的游戏引擎。我使用 Code-blocks 13.12 作为我的 IDE,使用 mingw-w64 v4.0 作为我的编译器。我还使用 SDL2、glew、Assimp 和 boost 作为我的第三方库。
对于大量的代码摘录,我提前表示歉意,但我输入了我认为理解错误上下文所必需的内容。
我的游戏引擎有一个 Core
类,它包含主循环并相应地更新和渲染,调用 Game
类 update()
和 render()
方法。 Game 类旨在作为游戏中所有 Assets 的持有者,并将成为使用该引擎制作的任何游戏的基类,因此,它包含网格、纹理和相机引用。 Game 类 update()
、render()
和 input()
方法都是虚拟的,因为 Game
类意味着派生。
我的问题是:当我在 Core
类中初始化 Game 成员变量时,我在 Mesh
对象的构造函数中得到一个 SIGSEGV(即段错误)glGenVertexArrays
调用。
但是,当我将 Game
对象移出 Core
类并直接进入 main 方法时(因此我将它从类成员更改为main 方法),以及来自 Core
类的必要部分,然后它完美运行并呈现我的基本三角形示例。这是一个我从未遇到过的错误,我将非常感谢我能得到的任何帮助。
下面是我完美运行并呈现三角形的变形代码的摘录:
int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
Window win(800, 800, "EngineTry", false); //Creates an SDL implemented window with a GL_context
Game* gamew = new Game;
const double frameTime = 1.0 / 500; //500 = maximum fps
double lastTime = FTime::getTime(); //gets current time in milliseconds
double unprocessedTime = 0.0;
int frames = 0;
double frameCounter = 0;
while(win.isRunning()){
bool _render = false;
double startTime = FTime::getTime();
double passedTime = startTime - lastTime;
lastTime = startTime;
unprocessedTime += passedTime / (double)FTime::SECOND;
frameCounter += passedTime;
while(unprocessedTime > frameTime){
if(!win.isRunning())
exit(0);
_render = true;
unprocessedTime -= frameTime;
FTime::delta = frameTime;
gamew->input();
Input::update();
gamew->update();
if(frameCounter >= FTime::SECOND)
{
std::cout << "FPS: " << frames << std::endl;
frames = 0;
frameCounter = 0;
}
}
if(_render){
RenderUtil::clearScreen(); //simple wrapper to the glClear function
gamew->render();
win.Update();
frames++;
}else{
Sleep(1);
}
}
delete gamew;
return 0;
}
这是我修改后的 Core
类的摘录,它不起作用(在 Mesh
构造函数中抛出 sigsegv)
class TempCore
{
public:
TempCore(Game* g) :
gamew(g), win(800, 800, "EngineTry", false) {}
~TempCore() { if(gamew) delete gamew; }
void start();
private:
Window win;
Game* gamew;
};
int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
TempCore m_core(new Game());
m_core.start();
return 0;
}
void TempCore::start()
{
const double frameTime = 1.0 / 500;
double lastTime = FTime::getTime();
double unprocessedTime = 0.0;
int frames = 0;
double frameCounter = 0;
while(win.isRunning()){
bool _render = false;
double startTime = FTime::getTime();
double passedTime = startTime - lastTime;
lastTime = startTime;
unprocessedTime += passedTime / (double)FTime::SECOND;
frameCounter += passedTime;
while(unprocessedTime > frameTime){
if(!win.isRunning())
exit(0);
_render = true;
unprocessedTime -= frameTime;
FTime::delta = frameTime;
gamew->input();
Input::update();
gamew->update();
if(frameCounter >= FTime::SECOND){
//double totalTime = ((1000.0 * frameCounter)/((double)frames));
//double totalMeasuredTime = 0.0;
std::cout << "Frames: " << frames << std::endl;
//m_frames_per_second = frames;
frames = 0;
frameCounter = 0;
}
}
if(_render){
RenderUtil::clearScreen();
gamew->render();
win.Update();
frames++;
}else{
Sleep(1);
}
}
}
上述TestCore
实现中出现sigsegv的Mesh构造函数:
Mesh::Mesh( Vertex* vertices, unsigned int numVerts )
{
m_drawCount = numVerts;
glGenVertexArrays(1, &m_vertexArrayObject); //sigsegv occurs here
glBindVertexArray(m_vertexArrayObject);
std::vector<glm::vec3> positions;
std::vector<glm::vec2> texCoords;
positions.reserve(numVerts);
texCoords.reserve(numVerts);
for(unsigned i = 0; i < numVerts; i++){
positions.push_back(vertices[i].pos);
texCoords.push_back(vertices[i].texCoord);
}
glGenBuffers(NUM_BUFFERS, m_vertexArrayBuffers);
glBindBuffer(GL_ARRAY_BUFFER, m_vertexArrayBuffers[POSITION_VB]);
glBufferData(GL_ARRAY_BUFFER, numVerts*sizeof(positions[0]), &positions[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, m_vertexArrayBuffers[TEXCOORD_VB]);
glBufferData(GL_ARRAY_BUFFER, numVerts*sizeof(texCoords[0]), &texCoords[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
glBindVertexArray(0);
}
初始化Mesh
对象的Game
构造函数:
Vertex vertices[] = { Vertex(-0.5f, -0.5f, 0, 0, 0),
Vertex(0, 0.5f, 0, 0.5f, 1.0f),
Vertex(0.5f, -0.5f, 0, 1.0f, 0)};
//Vertex is basically a struct with a glm::vec3 for position and a glm::vec2 for texture coordinate
Game::Game() :
m_mesh(vertices, sizeof(vertices)/sizeof(vertices[0])),
m_shader("res\\shaders\\basic_shader"),
m_texture("res\\textures\\mist_tree.jpg")
{
}
初始化glew
的Window
类构造函数:
Window::Window(int width, int height, const std::string& title, bool full_screen) :
m_fullscreen(full_screen)
{
SDL_Init(SDL_INIT_EVERYTHING);
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);
//SDL_Window* in private of class declaration
m_window = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
//SDL_GLContext in private of class declaration
m_glContext = SDL_GL_CreateContext(m_window);
std::cout << "GL Version: " << glGetString(GL_VERSION) << std::endl;
glewExperimental = GL_TRUE;
if(glewInit() != GLEW_OK || !glVersionAbove(3.0)){
std::cerr << "Glew failed to initialize...\n";
exit(-150);
}
}
最佳答案
这里不太可能,因为给定的信息量非常大。我搜索了类似的问题,例如 this one和 this one ,但他们中的每一个都已经用你在 Window 类构造函数中所做的技巧来回答,必须在你的游戏构造函数之前调用。正如我在您的 TempCore 构造函数中看到的那样,您构建游戏对象(并调用 glGenVertexArrays)在构建 Window 对象之前
...
TempCore(Game* g) :
gamew(g), win(800, 800, "EngineTry", false) {}
...
因此,在使用 SDL_GL_CreateContext(m_window)
调用创建 OpenGL 上下文之前和 glewExperimental = GL_TRUE; 之前glewInit();
。然后你说按这个顺序放到main里就解决了问题...
...
Window win(800, 800, "EngineTry", false); //Creates an SDL implemented window with a GL_context
Game* gamew = new Game;
...
也许像这样在构造函数中重新排序初始化列表可以解决您的问题?
class TempCore
{
public:
TempCore(Game* g) :
win(800, 800, "EngineTry", false), gamew(g) {}
~TempCore() { if(gamew) delete gamew; }
...
};
更新
我错了,如评论中所述,初始化列表顺序无关紧要。重要的是定义顺序,这里是正确的...
关于c++ - 类构造函数中的 OpenGL sigsegv 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36184231/