glGenVertexArrays 在主循环中不创建唯一的 VAO,但在其他情况下工作
glGenVertexArrays Not creating unique VAO when in Main loop but works otherwise
我目前正在为我一直在编写的游戏引擎开发一个小型编辑器。我已经使用 Qt 5.6 设置了一个文件菜单,其中有一个选项可以添加一个模型,该模型可以创建一个新模型并将其添加到渲染引擎管理器中。在 Mac OSX 10.11(使用 OpenGL 3 或 4)上,这工作正常。在 Ubuntu 16.04 上,它只能稍微起作用。我可以在主循环之外初始化任意数量的模型。但是在主循环内,我只能初始化与在主循环外初始化的模型一样多的模型。当我在 IDE 中启动 gdb 时,问题似乎与 VAO 相关。在 OSX 上,无论我在哪里创建网格,都会为每个模型初始化一个新的 VAO。在 Ubuntu 上,在主循环之外为每个网格生成新的 VAO。在主循环内,绘制的网格与先前在主循环外创建的网格具有相同的 VAO。一旦我创建的模型多于在主循环外创建的模型并且生成了新的 VAO,模型就不会绘制。
总而言之,在 Ubuntu 中,主循环外的所有模型都有自己的 VAO。在主循环中,VAO GLuint 句柄再次从 2 开始重新计数。一旦 handle/tag 计数过去,但是许多模型在主循环之外被初始化,模型停止绘制。它工作得很好 Mac OSX。我怀疑这是一个 OpenGL/Qt 问题,所以尽管引擎有很多额外的代码,但我认为这个问题很公平。 Link: https://github.com/BennetLeff/engine
由于有很多文件,我将只包含我认为必要的文件,但我也会 link 到 github 项目。很抱歉出现大量代码转储,但请告诉我是否还有其他我可以提供的内容。
Mesh.cpp
#include "Mesh.h"
#include "Transform.h"
#include <stdio.h>
Mesh::Mesh(std::vector<glm::vec3> vertices, std::vector<glm::vec3> normals, std::vector<glm::vec2> textures, std::vector<GLuint> indices)
{
drawCount_ = indices.size();
glGenVertexArrays(1, &vertexArrayObject_);
glBindVertexArray(vertexArrayObject_);
glGenBuffers(NUMBUFFERS, vertexBufferObject_);
// Position Attrib
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject_[POSITION_VB]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Texture Attrib
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject_[TEXCOORD_VB]);
glBufferData(GL_ARRAY_BUFFER, sizeof(textures[0]) * textures.size(), textures.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
// Normals Attrib
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject_[NORMAL_VB]);
glBufferData(GL_ARRAY_BUFFER, sizeof(normals[0]) * normals.size(), normals.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertexBufferObject_[INDEX_VB]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices.size(), indices.data(), GL_STATIC_DRAW);
glBindVertexArray(0);
fprintf(stderr, "vao val %d\n", vertexArrayObject_);
}
Mesh::~Mesh()
{
glDeleteVertexArrays(1, &vertexArrayObject_);
}
void Mesh::draw()
{
glBindVertexArray(vertexArrayObject_);
glDrawElements(GL_TRIANGLES, drawCount_, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
if (glGetError())
printf("GL error %d", glGetError());
}
Main.cpp
#include <stdio.h>
#ifdef __APPLE__
#include <OpenGL/gl3.h>
#else
#include <GL/glew.h>
#endif
#include "Camera.h"
#include "Model.h"
#include "Editor.h"
#include "RenderEngine.h"
#include <QApplication>
bool quit = false;
int main(int argc, char* argv[])
{
auto WIDTH = 1024;
auto HEIGHT = 800;
/*
* Sets up a QApplication
* with the proper formatting. This allows
* GL versions to be set and so forth. Then
* the QApplication is polled in the main loop
* for events.
*/
QApplication app(argc, argv);
QSurfaceFormat format;
format.setSamples(16);
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
format.setVersion(4, 3);
format.setProfile(QSurfaceFormat::CoreProfile);
QSurfaceFormat::setDefaultFormat(format);
// Sets up Rendering Engine and Editor.
auto cam = new Camera(glm::vec3(0, 6, -20), 70.0f, (float) WIDTH / (float) HEIGHT, 0.01f, 1000.0f);
RenderEngine* engine = new RenderEngine(cam);
Editor editor(engine, WIDTH, HEIGHT);
editor.showEditor();
/*
* Must call Editor.show() before any other
* OpenGL calls. This is mostly because of Qt.
*/
// auto house = Model("./res/farm house/OBJ/Farmhouse OBJ.obj", "./res/farm house/Textures/Farmhouse Texture.jpg");
// house.transform->getPosition()->z = 40;
// auto model = Model("./res/Alfred/Alfred.obj", "./res/Alfred/alfred_dif.png");
// auto model2 = Model("./res/Alfred/Alfred.obj", "./res/Alfred/alfred_dif.png");
float counter = 0.0f;
while (editor.isVisible())
{
app.processEvents();
// model.transform->getRotation()->y = float(editor.getSliderValue()) / 10;
// model.transform->getPosition()->z = editor.getManValue();
counter += 0.1f;
/*
* Just updating window for now because
* it may be faster. Need to benchmark this
* and determine what is necessary.
*/
editor.getWindow()->update();
}
return 0;
}
GUIWindow.cpp(继承自QOpenGLWidget、QOpenGLFunctions)
#include <GL/glew.h>
#include "GUIWindow.h"
GUIWindow::GUIWindow(QWidget* parent, RenderEngine* engine) :
QOpenGLWidget(parent), engine(engine) { }
void GUIWindow::initializeGL()
{
// Set up the rendering context, load shaders and other resources, etc.:
initializeOpenGLFunctions();
// If not on OSX we need to include
// OpenGL as an extension
#ifndef __APPLE__
glewExperimental = GL_TRUE;
GLenum err = glewInit();
if (GLEW_OK != err) {
/* Problem: glewInit failed, something is seriously wrong. */
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
}
#endif
// Depth test not enabled by default.
glEnable(GL_DEPTH_TEST);
}
void GUIWindow::resizeGL(int w, int h) { }
void GUIWindow::paintGL()
{
// Draw the scene
clear(0.1, 0.4, 0.6, 1.0);
// Draw all Models
engine->draw();
}
void GUIWindow::clear(float r, float g, float b, float a)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glClearColor(r, g, b, a);
}
GUIWindow::~GUIWindow() { }
Model.cpp(不包括仅从 AssImp 获取数据的模型加载)
void Model::draw(Camera* cam)
{
shader.draw();
shader.update(transform, cam);
tex.bind(0);
modelMesh->draw();
}
void Model::bindTexture(Texture tex)
{
this->tex = tex;
}
RenderingEngine.cpp
#include "RenderEngine.h"
RenderEngine::RenderEngine(Camera* cam)
: cam(cam)
{
this->init();
}
void RenderEngine::init()
{
// If not on OSX we need to include
// OpenGL as an extension
#ifndef __APPLE__
glewExperimental = GL_TRUE;
GLenum err = glewInit();
if (GLEW_OK != err) {
/* Problem: glewInit failed, something is seriously wrong. */
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
}
glEnable(GL_DEPTH_TEST);
#endif
}
void RenderEngine::addModel(Model model)
{
printf("added model \n");
this->models.push_back(model);
for (int i = 0; i < this->models.size(); i++)
printf("Model Pos: (%g, %g, %g) \n", models[i].transform->getPosition()->x,
models[i].transform->getPosition()->y,
models[i].transform->getPosition()->z);
printf("there are %d models now \n", this->models.size());
}
void RenderEngine::draw()
{
for (int i = 0; i < this->models.size(); i++)
models[i].draw(this->cam);
}
Editor.cpp(减去大多数刚刚设置 window 的 Qt 调用)
#include "Editor.h"
Editor::Editor(RenderEngine* renderEngine, int width, int height)
{
frame = 0;
this->width = width;
this->height = height;
this->engine = renderEngine;
this->window = new GUIWindow(0, renderEngine);
}
void Editor::initialize()
{
// Set up the rendering context, load shaders and other resources, etc.:
// initializeOpenGLFunctions();
glViewport(0, 0, width, height);
setupWidgets();
}
float Editor::getRandNum()
{
srand(time(0));
float num = rand() % 10 + 1;
fprintf(stderr, "%d \n", num);
return num;
}
void Editor::addModelToScene()
{
srand (time(NULL));
auto trans = new Transform();
trans->getPosition()->x = rand() % 10 + 1;
trans->getPosition()->y = rand() % 10 + 1;
trans->getPosition()->z = rand() % 10 + 1;
engine->addModel(Model("./res/Alfred/Alfred.obj", "./res/Alfred/alfred_dif.png", trans));
fprintf(stderr, "Add a Model \n");
}
void Editor::showEditor()
{
// Sets up the rest of the widgets locations.
setupWidgets();
// Sets up the QMainWindow.
this->show();
}
void Editor::addModel(Model model)
{
engine->addModel(model);
}
我不知道为什么我被否决了,但我终于弄清楚了这个问题。在 Editor::addModelToScene()
中,我需要在调用 addModel()
之前调用 window.makeCurrent()
。我完全不知道为什么这会在 OSX 上起作用。还要感谢 让我有了尝试这个的想法。
我目前正在为我一直在编写的游戏引擎开发一个小型编辑器。我已经使用 Qt 5.6 设置了一个文件菜单,其中有一个选项可以添加一个模型,该模型可以创建一个新模型并将其添加到渲染引擎管理器中。在 Mac OSX 10.11(使用 OpenGL 3 或 4)上,这工作正常。在 Ubuntu 16.04 上,它只能稍微起作用。我可以在主循环之外初始化任意数量的模型。但是在主循环内,我只能初始化与在主循环外初始化的模型一样多的模型。当我在 IDE 中启动 gdb 时,问题似乎与 VAO 相关。在 OSX 上,无论我在哪里创建网格,都会为每个模型初始化一个新的 VAO。在 Ubuntu 上,在主循环之外为每个网格生成新的 VAO。在主循环内,绘制的网格与先前在主循环外创建的网格具有相同的 VAO。一旦我创建的模型多于在主循环外创建的模型并且生成了新的 VAO,模型就不会绘制。
总而言之,在 Ubuntu 中,主循环外的所有模型都有自己的 VAO。在主循环中,VAO GLuint 句柄再次从 2 开始重新计数。一旦 handle/tag 计数过去,但是许多模型在主循环之外被初始化,模型停止绘制。它工作得很好 Mac OSX。我怀疑这是一个 OpenGL/Qt 问题,所以尽管引擎有很多额外的代码,但我认为这个问题很公平。 Link: https://github.com/BennetLeff/engine
由于有很多文件,我将只包含我认为必要的文件,但我也会 link 到 github 项目。很抱歉出现大量代码转储,但请告诉我是否还有其他我可以提供的内容。
Mesh.cpp
#include "Mesh.h"
#include "Transform.h"
#include <stdio.h>
Mesh::Mesh(std::vector<glm::vec3> vertices, std::vector<glm::vec3> normals, std::vector<glm::vec2> textures, std::vector<GLuint> indices)
{
drawCount_ = indices.size();
glGenVertexArrays(1, &vertexArrayObject_);
glBindVertexArray(vertexArrayObject_);
glGenBuffers(NUMBUFFERS, vertexBufferObject_);
// Position Attrib
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject_[POSITION_VB]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Texture Attrib
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject_[TEXCOORD_VB]);
glBufferData(GL_ARRAY_BUFFER, sizeof(textures[0]) * textures.size(), textures.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
// Normals Attrib
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject_[NORMAL_VB]);
glBufferData(GL_ARRAY_BUFFER, sizeof(normals[0]) * normals.size(), normals.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertexBufferObject_[INDEX_VB]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices.size(), indices.data(), GL_STATIC_DRAW);
glBindVertexArray(0);
fprintf(stderr, "vao val %d\n", vertexArrayObject_);
}
Mesh::~Mesh()
{
glDeleteVertexArrays(1, &vertexArrayObject_);
}
void Mesh::draw()
{
glBindVertexArray(vertexArrayObject_);
glDrawElements(GL_TRIANGLES, drawCount_, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
if (glGetError())
printf("GL error %d", glGetError());
}
Main.cpp
#include <stdio.h>
#ifdef __APPLE__
#include <OpenGL/gl3.h>
#else
#include <GL/glew.h>
#endif
#include "Camera.h"
#include "Model.h"
#include "Editor.h"
#include "RenderEngine.h"
#include <QApplication>
bool quit = false;
int main(int argc, char* argv[])
{
auto WIDTH = 1024;
auto HEIGHT = 800;
/*
* Sets up a QApplication
* with the proper formatting. This allows
* GL versions to be set and so forth. Then
* the QApplication is polled in the main loop
* for events.
*/
QApplication app(argc, argv);
QSurfaceFormat format;
format.setSamples(16);
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
format.setVersion(4, 3);
format.setProfile(QSurfaceFormat::CoreProfile);
QSurfaceFormat::setDefaultFormat(format);
// Sets up Rendering Engine and Editor.
auto cam = new Camera(glm::vec3(0, 6, -20), 70.0f, (float) WIDTH / (float) HEIGHT, 0.01f, 1000.0f);
RenderEngine* engine = new RenderEngine(cam);
Editor editor(engine, WIDTH, HEIGHT);
editor.showEditor();
/*
* Must call Editor.show() before any other
* OpenGL calls. This is mostly because of Qt.
*/
// auto house = Model("./res/farm house/OBJ/Farmhouse OBJ.obj", "./res/farm house/Textures/Farmhouse Texture.jpg");
// house.transform->getPosition()->z = 40;
// auto model = Model("./res/Alfred/Alfred.obj", "./res/Alfred/alfred_dif.png");
// auto model2 = Model("./res/Alfred/Alfred.obj", "./res/Alfred/alfred_dif.png");
float counter = 0.0f;
while (editor.isVisible())
{
app.processEvents();
// model.transform->getRotation()->y = float(editor.getSliderValue()) / 10;
// model.transform->getPosition()->z = editor.getManValue();
counter += 0.1f;
/*
* Just updating window for now because
* it may be faster. Need to benchmark this
* and determine what is necessary.
*/
editor.getWindow()->update();
}
return 0;
}
GUIWindow.cpp(继承自QOpenGLWidget、QOpenGLFunctions)
#include <GL/glew.h>
#include "GUIWindow.h"
GUIWindow::GUIWindow(QWidget* parent, RenderEngine* engine) :
QOpenGLWidget(parent), engine(engine) { }
void GUIWindow::initializeGL()
{
// Set up the rendering context, load shaders and other resources, etc.:
initializeOpenGLFunctions();
// If not on OSX we need to include
// OpenGL as an extension
#ifndef __APPLE__
glewExperimental = GL_TRUE;
GLenum err = glewInit();
if (GLEW_OK != err) {
/* Problem: glewInit failed, something is seriously wrong. */
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
}
#endif
// Depth test not enabled by default.
glEnable(GL_DEPTH_TEST);
}
void GUIWindow::resizeGL(int w, int h) { }
void GUIWindow::paintGL()
{
// Draw the scene
clear(0.1, 0.4, 0.6, 1.0);
// Draw all Models
engine->draw();
}
void GUIWindow::clear(float r, float g, float b, float a)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glClearColor(r, g, b, a);
}
GUIWindow::~GUIWindow() { }
Model.cpp(不包括仅从 AssImp 获取数据的模型加载)
void Model::draw(Camera* cam)
{
shader.draw();
shader.update(transform, cam);
tex.bind(0);
modelMesh->draw();
}
void Model::bindTexture(Texture tex)
{
this->tex = tex;
}
RenderingEngine.cpp
#include "RenderEngine.h"
RenderEngine::RenderEngine(Camera* cam)
: cam(cam)
{
this->init();
}
void RenderEngine::init()
{
// If not on OSX we need to include
// OpenGL as an extension
#ifndef __APPLE__
glewExperimental = GL_TRUE;
GLenum err = glewInit();
if (GLEW_OK != err) {
/* Problem: glewInit failed, something is seriously wrong. */
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
}
glEnable(GL_DEPTH_TEST);
#endif
}
void RenderEngine::addModel(Model model)
{
printf("added model \n");
this->models.push_back(model);
for (int i = 0; i < this->models.size(); i++)
printf("Model Pos: (%g, %g, %g) \n", models[i].transform->getPosition()->x,
models[i].transform->getPosition()->y,
models[i].transform->getPosition()->z);
printf("there are %d models now \n", this->models.size());
}
void RenderEngine::draw()
{
for (int i = 0; i < this->models.size(); i++)
models[i].draw(this->cam);
}
Editor.cpp(减去大多数刚刚设置 window 的 Qt 调用)
#include "Editor.h"
Editor::Editor(RenderEngine* renderEngine, int width, int height)
{
frame = 0;
this->width = width;
this->height = height;
this->engine = renderEngine;
this->window = new GUIWindow(0, renderEngine);
}
void Editor::initialize()
{
// Set up the rendering context, load shaders and other resources, etc.:
// initializeOpenGLFunctions();
glViewport(0, 0, width, height);
setupWidgets();
}
float Editor::getRandNum()
{
srand(time(0));
float num = rand() % 10 + 1;
fprintf(stderr, "%d \n", num);
return num;
}
void Editor::addModelToScene()
{
srand (time(NULL));
auto trans = new Transform();
trans->getPosition()->x = rand() % 10 + 1;
trans->getPosition()->y = rand() % 10 + 1;
trans->getPosition()->z = rand() % 10 + 1;
engine->addModel(Model("./res/Alfred/Alfred.obj", "./res/Alfred/alfred_dif.png", trans));
fprintf(stderr, "Add a Model \n");
}
void Editor::showEditor()
{
// Sets up the rest of the widgets locations.
setupWidgets();
// Sets up the QMainWindow.
this->show();
}
void Editor::addModel(Model model)
{
engine->addModel(model);
}
我不知道为什么我被否决了,但我终于弄清楚了这个问题。在 Editor::addModelToScene()
中,我需要在调用 addModel()
之前调用 window.makeCurrent()
。我完全不知道为什么这会在 OSX 上起作用。还要感谢