glGenVertexArrays Не создает уникальный VAO в основном цикле, но работает иначе

В настоящее время я работаю над небольшим редактором для игрового движка, который я писал. Я создал меню файлов с Qt 5.6, в котором есть возможность добавить модель, которая создает новую модель и добавляет ее в диспетчер механизма рендеринга. В Mac OSX 10.11 (с OpenGL 3 или 4) это работает нормально. В Ubuntu 16.04 это работает незначительно. Я могу инициализировать столько моделей, сколько захочу, вне основного цикла. Однако внутри основного цикла я могу инициализировать только столько моделей, сколько я инициализировал вне основного цикла. Когда я запускаю gdb внутри своей IDE, проблема, похоже, связана с VAO. В OSX новый VAO инициализируется для каждой модели независимо от того, где я создаю сетку. В Ubuntu вне основного цикла для каждой сетки генерируются новые VAO. Внутри основного цикла меши, которые отрисовываются, имеют тот же VAO, что и ранее созданный меш вне основного цикла. Как только я создаю больше моделей, чем было создано вне основного цикла, и создается новый VAO, модель не рисуется.

Подводя итог, в Ubuntu все модели вне основного цикла получают свой собственный VAO. Внутри основного цикла дескриптор VAO GLuint снова начинает считать с 2. Как только число дескрипторов/тегов превышает количество моделей, инициализированных вне основного цикла, модели перестают рисоваться. Он отлично работает на Mac OSX. Я подозреваю, что это проблема OpenGL/Qt, поэтому, несмотря на то, что для движка много дополнительного кода, я думаю, что вопрос будет справедливым. Ссылка: https://github.com/BennetLeff/engine

Поскольку файлов довольно много, я включу только то, что считаю необходимым, но также приведу ссылку на проект github. Извините за большой дамп кода, но скажите, могу ли я что-нибудь еще предоставить.

Сетка.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 (за исключением большинства вызовов 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);
}

person Bennet Leff    schedule 25.05.2016    source источник


Ответы (1)


Я не знаю, почему меня проголосовали против, но я, наконец, разобрался с проблемой. В Editor::addModelToScene() мне нужно было позвонить window.makeCurrent() прямо перед тем, как позвонить addModel(). Я понятия не имею, почему это будет работать на OSX независимо. Также спасибо этому ответу за то, что он дал мне идею попробовать это.

person Bennet Leff    schedule 26.05.2016